Skip to content

Commit

Permalink
Start backend for events
Browse files Browse the repository at this point in the history
  • Loading branch information
tupui committed Aug 19, 2024
1 parent cde16bf commit 3c0222c
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 6 deletions.
8 changes: 7 additions & 1 deletion tansu/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,16 @@ test = [
"pytest",
"pytest-asyncio",
"locust",
"respx",
]

backend = [
"fastapi",
"uvicorn[standard]",
]

dev = [
"tansu[test]",
"tansu[test,backend]",
"pre-commit",
"hatch",
"ruff",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,9 @@ class Event(BaseModel):
value: SCValNative_

model_config = dict(arbitrary_types_allowed=True)


class EventRequest(BaseModel):
project_key: str
action: str
limit: int = 1000
69 changes: 69 additions & 0 deletions tansu/src/tansu/events/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""FastAPI app.
Connect all routers to the app and add error handling.
"""

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from fastapi.middleware import Middleware
from starlette.middleware.cors import CORSMiddleware

from tansu.events.log import logger
from tansu.events.routers import system, events

ORIGINS = [
"https://testnet.tansu.dev",
"https://app.tansu.dev",
]


async def unhandled_exception_handler(request: Request, exc: Exception) -> JSONResponse:
"""Log all unhandled exceptions."""
message = f"Internal API error: {exc}"
logger.error(message)
return JSONResponse(
status_code=500,
content={"message": "Internal API error. The error was reported to our team."},
)


def create_app(debug: bool = False):
app = FastAPI(
title="Tansu - events backend",
debug=debug,
description="",
version="1.0.0",
middleware=[
Middleware(
CORSMiddleware,
**{
"allow_origins": ORIGINS,
"allow_credentials": True,
"allow_methods": ["GET", "POST", "DELETE", "OPTIONS"],
"allow_headers": ["*"],
},
),
],
)

app.add_exception_handler(Exception, unhandled_exception_handler)

app.include_router(system.router, tags=["system"])
app.include_router(events.router, tags=["events"])

logger.info("Tansu RPC is running...")

return app


if __name__ == "__main__":
import uvicorn

uvicorn.run(
"tansu.event.main:app",
host="127.0.0.1",
reload=True,
port=8080,
access_log=True,
log_level="debug",
)
8 changes: 4 additions & 4 deletions tansu/src/tansu/events/consume.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import sqlalchemy

from tansu.events import models
from tansu.events import api_models
from tansu.events.database import db_models
from tansu.events.log import logger


@sqlalchemy.event.listens_for(db_models.Event, "after_insert")
def event_handler(mapper, connection, target: db_models.Event):
event = models.Event(
event = api_models.Event(
project_key=target.project_key, action=target.action, value=target.value
)

logger.info(
f"Event listener: {event.project_key} :: {event.action} :: {event.value}"
logger.debug(
f"Event listener: {event.project_key} :: {event.action} :: {event.value} :: {event.ledger}"
)
2 changes: 1 addition & 1 deletion tansu/src/tansu/events/log.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import logging

logger = logging.getLogger("soroban-versioning-events-events")
logger = logging.getLogger("tansu-events")
8 changes: 8 additions & 0 deletions tansu/src/tansu/events/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Main entry point for the FastAPI server."""

import os
from tansu.events.app import create_app

env = os.getenv("ENV", "production")
debug = True if env == "testing" else False
app = create_app(debug=debug)
Empty file.
27 changes: 27 additions & 0 deletions tansu/src/tansu/events/routers/events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from fastapi import APIRouter

from tansu.events.database import SessionFactory, db_models
from tansu.events import api_models

router = APIRouter()


@router.post("/events")
async def events(request: api_models.EventRequest) -> list[api_models.Event | None]:
async with SessionFactory() as session:
events_ = (
session.query(db_models.Event)
.where(db_models.Event.project_key == request.project_key)
.where(db_models.Event.action == request.action)
.limit(request.limit)
.all()
)

result = [
api_models.Event(
project_key=event_.project_key, action=event_.action, value=event_.value
)
for event_ in events_
]

return result
11 changes: 11 additions & 0 deletions tansu/src/tansu/events/routers/system.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from fastapi import APIRouter
from fastapi.responses import PlainTextResponse

router = APIRouter()


@router.get("/favicon.ico")
@router.get("/health")
@router.get("/")
async def health_check() -> PlainTextResponse:
return PlainTextResponse("OK")

0 comments on commit 3c0222c

Please sign in to comment.