import asyncio import socket from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles from app.config import get_settings from app.plugins import PLUGINS, ROUTERS as PLUGIN_ROUTERS from app.render import BASE, render from app.routers import disks, overview, plugins, processes, services from app.routers import journal as journal_router from app.sampling import sampler_loop from app.state import HistoryStore @asynccontextmanager async def lifespan(app: FastAPI): settings = get_settings() app.state.settings = settings app.state.store = HistoryStore(maxlen=settings.history_maxlen) for p in PLUGINS: try: await p.open() except Exception: # noqa pass task = asyncio.create_task(sampler_loop(app.state.store, settings.sample_interval)) yield _ = task.cancel() try: await task except asyncio.CancelledError: pass for p in PLUGINS: try: await p.close() except Exception: # noqa pass def create_app() -> FastAPI: app = FastAPI(title="Dashboard", lifespan=lifespan) app.mount("/static", StaticFiles(directory=BASE / "static"), name="static") for r in (overview.router, disks.router, processes.router, journal_router.router, services.router, plugins.router): app.include_router(r) for r in PLUGIN_ROUTERS: app.include_router(r) @app.get("/", include_in_schema=False) async def index(): return HTMLResponse(render("index.html", hostname=socket.gethostname())) return app app = create_app()