Files
Magent/backend/app/main.py

85 lines
2.9 KiB
Python

import asyncio
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from .config import settings
from .db import init_db
from .routers.requests import (
router as requests_router,
startup_warmup_requests_cache,
run_requests_delta_loop,
run_daily_requests_full_sync,
run_daily_db_cleanup,
)
from .routers.auth import router as auth_router
from .routers.admin import router as admin_router, events_router as admin_events_router
from .routers.images import router as images_router
from .routers.branding import router as branding_router
from .routers.status import router as status_router
from .routers.feedback import router as feedback_router
from .routers.site import router as site_router
from .routers.events import router as events_router
from .services.jellyfin_sync import run_daily_jellyfin_sync
from .logging_config import configure_logging
from .runtime import get_runtime_settings
app = FastAPI(
title=settings.app_name,
docs_url="/docs" if settings.api_docs_enabled else None,
redoc_url=None,
openapi_url="/openapi.json" if settings.api_docs_enabled else None,
)
app.add_middleware(
CORSMiddleware,
allow_origins=[settings.cors_allow_origin],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.middleware("http")
async def add_security_headers(request: Request, call_next):
response = await call_next(request)
response.headers.setdefault("X-Content-Type-Options", "nosniff")
response.headers.setdefault("X-Frame-Options", "DENY")
response.headers.setdefault("Referrer-Policy", "no-referrer")
response.headers.setdefault("Permissions-Policy", "geolocation=(), microphone=(), camera=()")
# Keep API responses non-executable and non-embeddable by default.
if request.url.path not in {"/docs", "/redoc"} and not request.url.path.startswith("/openapi"):
response.headers.setdefault(
"Content-Security-Policy",
"default-src 'none'; frame-ancestors 'none'; base-uri 'none'",
)
return response
@app.get("/health")
async def health() -> dict:
return {"status": "ok"}
@app.on_event("startup")
async def startup() -> None:
init_db()
runtime = get_runtime_settings()
configure_logging(runtime.log_level, runtime.log_file)
asyncio.create_task(run_daily_jellyfin_sync())
asyncio.create_task(startup_warmup_requests_cache())
asyncio.create_task(run_requests_delta_loop())
asyncio.create_task(run_daily_requests_full_sync())
asyncio.create_task(run_daily_db_cleanup())
app.include_router(requests_router)
app.include_router(auth_router)
app.include_router(admin_router)
app.include_router(admin_events_router)
app.include_router(images_router)
app.include_router(branding_router)
app.include_router(status_router)
app.include_router(feedback_router)
app.include_router(site_router)
app.include_router(events_router)