Files
plm-lottery/app/main.py
T

91 lines
3.1 KiB
Python
Raw Normal View History

import asyncio
2026-07-21 10:46:47 +02:00
import logging
from contextlib import asynccontextmanager
2026-07-21 10:46:47 +02:00
from fastapi import FastAPI, Request
from fastapi.responses import FileResponse, JSONResponse
2026-07-21 10:27:05 +02:00
from fastapi.staticfiles import StaticFiles
2026-07-21 10:46:47 +02:00
from app.logging_config import setup_logging
setup_logging()
import app.bets.confirmation # noqa: F401 (registers the "bet" confirmation handler)
import app.rounds.confirmation # noqa: F401 (registers the "payout" confirmation handler)
import app.withdrawals.confirmation # noqa: F401 (registers the "withdrawal" confirmation handler)
from app.api.routes.admin import router as admin_router
from app.api.routes.bets import router as bets_router
2026-07-21 10:51:56 +02:00
from app.api.routes.qr import router as qr_router
2026-07-21 10:57:31 +02:00
from app.api.routes.rounds import router as rounds_router
from app.api.routes.users import router as users_router
from app.api.routes.withdrawals import router as withdrawals_router
from app.auth.routes import router as auth_router
from app.config import settings
from app.db.base import AsyncSessionLocal
from app.electrum.client import ElectrumClient
from app.electrum.listener import ElectrumListener
from app.rounds.scheduler import RoundScheduler
from app.tx.broadcast import RbfBumper
from app.tx.confirmation import ConfirmationPoller
from app.tx.locks import UserLocks
2026-07-21 10:46:47 +02:00
logger = logging.getLogger(__name__)
def _make_electrum_client() -> ElectrumClient:
return ElectrumClient(settings.electrum_host, settings.electrum_port, settings.electrum_use_ssl)
@asynccontextmanager
async def lifespan(app: FastAPI):
listener = ElectrumListener(_make_electrum_client, AsyncSessionLocal)
app.state.electrum_listener = listener
app.state.user_locks = UserLocks()
scheduler = RoundScheduler(AsyncSessionLocal, listener)
poller = ConfirmationPoller(AsyncSessionLocal, lambda: listener.client)
bumper = RbfBumper(AsyncSessionLocal, lambda: listener.client)
tasks = [
asyncio.create_task(listener.run()),
asyncio.create_task(scheduler.run()),
asyncio.create_task(poller.run()),
asyncio.create_task(bumper.run()),
]
try:
yield
finally:
for task in tasks:
task.cancel()
if listener.client is not None:
await listener.client.close()
app = FastAPI(title="PLM Lottery", lifespan=lifespan)
app.include_router(auth_router)
app.include_router(users_router)
app.include_router(bets_router)
app.include_router(withdrawals_router)
app.include_router(admin_router)
2026-07-21 10:51:56 +02:00
app.include_router(qr_router)
2026-07-21 10:57:31 +02:00
app.include_router(rounds_router)
2026-07-21 10:46:47 +02:00
@app.exception_handler(Exception)
async def log_unhandled_exception(request: Request, exc: Exception) -> JSONResponse:
logger.exception("Unhandled error on %s %s", request.method, request.url.path)
return JSONResponse(status_code=500, content={"detail": "internal server error"})
@app.get("/health")
async def health() -> dict[str, str]:
return {"status": "ok"}
2026-07-21 10:27:05 +02:00
@app.get("/admin", include_in_schema=False)
async def admin_panel() -> FileResponse:
return FileResponse("app/static/admin.html")
2026-07-21 10:27:05 +02:00
app.mount("/", StaticFiles(directory="app/static", html=True), name="static")