import asyncio from contextlib import asynccontextmanager from typing import Any, AsyncGenerator, Optional from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from decnet.env import DECNET_CORS_ORIGINS, DECNET_DEVELOPER from decnet.web.dependencies import repo from decnet.web.ingester import log_ingestion_worker from decnet.web.router import api_router ingestion_task: Optional[asyncio.Task[Any]] = None @asynccontextmanager async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: global ingestion_task # Retry initialization a few times if DB is locked (common in tests) for _ in range(5): try: await repo.initialize() break except Exception: await asyncio.sleep(0.5) # Start background ingestion task if ingestion_task is None or ingestion_task.done(): ingestion_task = asyncio.create_task(log_ingestion_worker(repo)) yield # Shutdown ingestion task if ingestion_task: ingestion_task.cancel() app: FastAPI = FastAPI( title="DECNET Web Dashboard API", version="1.0.0", lifespan=lifespan, docs_url="/docs" if DECNET_DEVELOPER else None, redoc_url="/redoc" if DECNET_DEVELOPER else None, openapi_url="/openapi.json" if DECNET_DEVELOPER else None ) app.add_middleware( CORSMiddleware, allow_origins=DECNET_CORS_ORIGINS, allow_credentials=False, allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], allow_headers=["Authorization", "Content-Type"], ) # Include the modular API router app.include_router(api_router, prefix="/api/v1")