import logging from contextlib import asynccontextmanager from fastapi import FastAPI, HTTPException from fastapi.responses import FileResponse from app.blobs import BLOB_ID_RE, blob_path from app.bootstrap import bootstrap from app.config import get_settings from app.db import SessionLocal from app.routers import auth, games, i18n, metadata, roles, users, versions logging.basicConfig(level=logging.INFO) @asynccontextmanager async def lifespan(_: FastAPI): if get_settings().secret_key == "change-me": logging.getLogger(__name__).warning("SECRET_KEY is the default value — set it in .env") async with SessionLocal() as db: await bootstrap(db) yield app = FastAPI(title="pgames-manager", lifespan=lifespan, docs_url="/api/docs", openapi_url="/api/openapi.json") for r in (auth, users, roles, games, versions, i18n, metadata): app.include_router(r.router) @app.get("/api/health") async def health() -> dict[str, str]: return {"status": "ok"} @app.get("/blobs/{blob_id}") async def blob(blob_id: str) -> FileResponse: """Fallback for running without nginx; in compose nginx serves /blobs itself.""" if not BLOB_ID_RE.match(blob_id) or not (path := blob_path(blob_id)).is_file(): raise HTTPException(404) return FileResponse(path, headers={"Cache-Control": "public, max-age=31536000, immutable"})