Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OCT-1825: Initial passthrough FastAPI server #379

Closed
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
0f28150
wip - failing app context
adam-gf Aug 5, 2024
e2310d1
Throwing more wip
adam-gf Aug 13, 2024
591ef92
Adds more migrated code. Allocation and rewards look ok
adam-gf Aug 27, 2024
17a1402
Merge branch 'develop' into adam/oct-1825-initial-passthrough-fastapi…
adam-gf Aug 27, 2024
56a5f6e
Small fixes after local testing
adam-gf Aug 27, 2024
501c1eb
Additional fixes to alighn with what was before
adam-gf Aug 27, 2024
3cbf515
Updates based on pr comments and extracting dependencies
adam-gf Sep 3, 2024
b44f1aa
wip - investigating why fastapi is so slow
adam-gf Oct 1, 2024
ffdc06e
adds metric files
adam-gf Oct 1, 2024
dc7cef7
Updates
adam-gf Oct 4, 2024
7e30a33
Merge branch 'develop' into adam/oct-1825-initial-passthrough-fastapi…
adam-gf Oct 4, 2024
d768ba3
Adds fixes and other stuff
adam-gf Oct 6, 2024
19374e2
Bump argo app to 0.2.65
mslomnicki Oct 7, 2024
7ca1dae
Updates host
adam-gf Oct 7, 2024
859ea28
Merge branch 'adam/oct-1825-initial-passthrough-fastapi-server' of gi…
adam-gf Oct 7, 2024
1f80fe6
[CI/CD] Update master.env contracts
housekeeper-bot Oct 7, 2024
7394dc3
Updates with fixes
adam-gf Oct 7, 2024
f649b91
Merge branch 'adam/oct-1825-initial-passthrough-fastapi-server' of gi…
adam-gf Oct 7, 2024
9ee0a76
Merge branch 'develop' into adam/oct-1825-initial-passthrough-fastapi…
adam-gf Oct 10, 2024
e9310d4
Merge branch 'develop' into adam/oct-1825-initial-passthrough-fastapi…
adam-gf Oct 10, 2024
deeef47
Updates MAINNET handling and UQ
adam-gf Oct 10, 2024
d634fd5
[CI/CD] Update uat.env contracts
housekeeper-bot Oct 10, 2024
2bae451
Merge branch 'develop' into adam/oct-1825-initial-passthrough-fastapi…
aziolek Oct 10, 2024
34bb061
Merge branch 'develop' into adam/oct-1825-initial-passthrough-fastapi…
aziolek Oct 10, 2024
a1ddb51
Merge branch 'develop' into adam/oct-1825-initial-passthrough-fastapi…
adam-gf Oct 15, 2024
8fa3e8c
Updates the address list validation
adam-gf Oct 15, 2024
360be62
[CI/CD] Update uat.env contracts
housekeeper-bot Oct 15, 2024
4a23185
Bugfix missing argument
adam-gf Oct 15, 2024
887123f
Merge branch 'adam/oct-1825-initial-passthrough-fastapi-server' of gi…
adam-gf Oct 15, 2024
c0b5994
update
adam-gf Oct 15, 2024
60811c9
adds address to timeout for testing
adam-gf Oct 15, 2024
b011b05
up
adam-gf Oct 15, 2024
f3fc9b0
adds address to timeout list for testing
adam-gf Oct 15, 2024
3eb9286
[CI/CD] Update uat.env contracts
housekeeper-bot Oct 15, 2024
724b765
update timeout list for dev envs
adam-gf Oct 16, 2024
42d7379
Merge branch 'develop' into adam/oct-1825-initial-passthrough-fastapi…
aziolek Oct 16, 2024
0065e04
Adds redis for socketio manager
adam-gf Oct 16, 2024
64dbe8c
Merge branch 'adam/oct-1825-initial-passthrough-fastapi-server' of gi…
adam-gf Oct 16, 2024
233a90a
Merge branch 'develop' into adam/oct-1825-initial-passthrough-fastapi…
adam-gf Oct 16, 2024
9dc8ba0
updated formatting
adam-gf Oct 16, 2024
1579830
Trying to fix tests
adam-gf Oct 16, 2024
093a86b
remove ununsed imports
adam-gf Oct 16, 2024
b1f5421
Merge branch 'develop' into adam/oct-1825-initial-passthrough-fastapi…
adam-gf Oct 17, 2024
1e48be2
Update and PR comments address
adam-gf Oct 18, 2024
1521dda
Merge branch 'develop' into adam/oct-1825-initial-passthrough-fastapi…
adam-gf Oct 18, 2024
36e4a96
liter formatting fix
adam-gf Oct 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def register_extensions(app):
cors.init_app(app)
db.init_app(app)
migrate.init_app(app, db)
socketio.init_app(app)
# socketio.init_app(app)
kgarbacinski marked this conversation as resolved.
Show resolved Hide resolved
cache.init_app(app)
init_scheduler(app)
init_logger(app)
Expand Down
5 changes: 5 additions & 0 deletions backend/app/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ def config(app_level):
"apscheduler.executors.default": {
"level": "WARNING",
},
"uvicorn": { # Adding for the uvicorn logger (FastAPI)
"level": app_level,
"handlers": ["stdout", "stderr"],
"propagate": 0,
},
},
}

Expand Down
2 changes: 1 addition & 1 deletion backend/app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class DevConfig(Config):

ENV = "dev"
DEBUG = True
LOG_LVL = os.getenv("OCTANT_LOG_LEVEL", "DEBUG")
LOG_LVL = os.getenv("OCTANT_LOG_LEVEL", "INFO")
kgarbacinski marked this conversation as resolved.
Show resolved Hide resolved
DB_NAME = "dev.db"
CHAIN_ID = int(os.getenv("CHAIN_ID", 1337))
# Put the db file in project root
Expand Down
199 changes: 190 additions & 9 deletions backend/poetry.lock

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ pandas = "^2.2.0"
gmpy2 = "^2.1.5"
sentry-sdk = {extras = ["flask"], version = "^2.5.1"}
redis = "^5.0.7"
fastapi = "^0.112.0"
mypy = "^1.11.2"
isort = "^5.13.2"
pydantic-settings = "^2.4.0"
uvicorn = "^0.30.6"

[tool.poetry.group.dev.dependencies]
pytest = "^7.3.1"
Expand All @@ -43,6 +48,10 @@ pyright = "^1.1.366"
pylookup = "^0.2.2"
importmagic = "^0.1.7"
epc = "^0.0.5"
isort = "^5.13.2"
mypy = "^1.11.2"
ruff = "^0.6.2"
aiosqlite = "^0.20.0"

[tool.poetry.group.prod]
optional = true
Expand Down
85 changes: 85 additions & 0 deletions backend/socket_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import asyncio
import socketio

# Create a Socket.IO client
sio = socketio.AsyncClient(logger=True, engineio_logger=True)


# Define event handlers
@sio.event
async def connect():
print(">>>Connected to the server")


@sio.event
async def connect_error(data):
print(">>>The connection failed with error:", data)


@sio.event
async def disconnect():
print(">>>I'm disconnected!")


# A handler for any event with a wildcard (not all implementations of Socket.IO support this feature directly)
@sio.on("*")
async def catch_all(event, data):
print(f">>>Received an event of type '{event}' with data:", data)


@sio.event
async def epoch(data):
print(f">>>Epoch received: {data}")


@sio.event
async def project_rewards(data):
print(f"Message received: {data}")


@sio.event
async def threshold(data):
print(f"Custom event received: {data}")


# Connect to the server
async def main():
print("Connecting to the server...")
await sio.connect("http://localhost:8000/", wait_timeout=10)
print("Connected. Waiting for events...")
# This line will keep the client running and listening for events

# Emit events

# Emit a custom event
data = {
"userAddress": "0xb429d71F676f6e804010D8B699EefbF1ed050420",
"payload": {
"allocations": [
{
"proposalAddress": "0x1c01595f9534E33d411035AE99a4317faeC4f6Fe",
"amount": 100,
},
{
"proposalAddress": "0x6e8873085530406995170Da467010565968C7C62",
"amount": 200,
},
],
"nonce": 0,
"signature": "0x03c0e67cdc612bf1c0a690346805c5f461fbc0a8fe3041b4849c9ddbc939553a53997dfb6578200192e071618d9f054ae68513f134206149acf70ff04cea02931c",
},
"isManuallyEdited": False,
}
await sio.emit("allocate", data)

await sio.wait()


# Emit events
async def emit_event(event_name, data):
await sio.emit(event_name, data)


# Run the client
if __name__ == "__main__":
asyncio.run(main())
53 changes: 35 additions & 18 deletions backend/startup.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
# !!! IMPORTANT: DO NOT REARRANGE IMPORTS IN THIS FILE !!!
# The eventlet monkey patch needs to be applied before importing the Flask application for the following reasons:
# 1. Enabling Asynchronous I/O: The monkey patch is required to activate eventlet’s asynchronous and non-blocking I/O capabilities.
# Without this patch, the app's I/O requests might be blocked, which is not desirable for our API's performance.
# 2. Import Order Significance: The monkey patch must be applied before importing the Flask application to ensure that the app utilizes
# the asynchronous versions of standard library modules that have been patched by eventlet. If not done in this order, we might experience issues similar to
# what is reported in the following eventlet issue: https://github.com/eventlet/eventlet/issues/371
# This comment provides additional insight and helped resolve our specific problem: https://github.com/eventlet/eventlet/issues/371#issuecomment-779967181
# 3. Issue with dnspython: If dnspython is present in the environment, eventlet monkeypatches socket.getaddrinfo(),
# which breaks dns functionality. By setting the EVENTLET_NO_GREENDNS environment variable before importing eventlet,
# we prevent this monkeypatching

import os
from fastapi import Request
from fastapi.middleware.wsgi import WSGIMiddleware


os.environ["EVENTLET_NO_GREENDNS"] = "yes"
import eventlet # noqa
from starlette.middleware.base import BaseHTTPMiddleware

eventlet.monkey_patch()

if os.getenv("SENTRY_DSN"):
import sentry_sdk
Expand Down Expand Up @@ -54,13 +43,41 @@ def sentry_before_send(event, hint):
from app import create_app # noqa
from app.extensions import db # noqa

app = create_app()
# Create Flask app
flask_app = create_app()


@app.teardown_request
@flask_app.teardown_request
def teardown_session(*args, **kwargs):
db.session.remove()


from v2.main import fastapi_app

# Mount Flask app under a sub-path
fastapi_app.mount("/flask", WSGIMiddleware(flask_app))

# Middleware to check if the path exists in FastAPI
class PathCheckMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
path = request.url.path
# Check if the path exists in FastAPI routes
for route in fastapi_app.routes:
if path == route.path:
# If path exists, proceed with the request
return await call_next(request)
# If path does not exist, modify the request to forward to the Flask app
if path.startswith("/flask"):
return await call_next(request)
request.scope["path"] = "/flask" + path # Adjust the path as needed
response = await call_next(request)
return response


fastapi_app.add_middleware(PathCheckMiddleware)


if __name__ == "__main__":
eventlet.wsgi.server(eventlet.listen(("0.0.0.0", 5000)), app, log=app.logger)
import uvicorn

uvicorn.run(fastapi_app, host="0.0.0.0", port=5000)
Empty file added backend/v2/__init__.py
Empty file.
Empty file.
38 changes: 38 additions & 0 deletions backend/v2/allocations/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from decimal import Decimal

from pydantic import BaseModel, ConfigDict


class AllocationWithUserUQScore(BaseModel):
model_config = ConfigDict(frozen=True)

project_address: str
amount: int
user_address: str
user_uq_score: Decimal


class AllocationRequest(BaseModel):
model_config = ConfigDict(frozen=True)

project_address: str
amount: int


class UserAllocationRequest(BaseModel):
model_config = ConfigDict(frozen=True)

user_address: str
allocations: list[AllocationRequest]
nonce: int
signature: str

is_manually_edited: bool


class ProjectDonation(BaseModel):
model_config = ConfigDict(frozen=True)

amount: int
donor_address: str # user address
project_address: str
Loading
Loading