from fastapi import FastAPI, Depends from fastapi.staticfiles import StaticFiles from routers import docker_router, gitea, files, terminal, system, auth import auth as auth_module import asyncio import httpx from config import TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID app = FastAPI(title="NAS Dashboard") async def monitor_containers(): import docker from config import DOCKER_HOST client = docker.DockerClient(base_url=DOCKER_HOST) # Store initial states previous_states = {} while True: try: for c in client.containers.list(all=True): current_status = c.status if c.id in previous_states: prev_status = previous_states[c.id] # Alert if it transitioned from running to exited or unhealthy if prev_status == "running" and current_status in ("exited", "dead"): msg = f"⚠️ *Container Alert* ⚠️\nContainer `{c.name}` just stopped unexpectedly (Status: {current_status})." # Use httpx directly as system.send_notification expects a FastAPI request object usually if TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID: proxy_url = os.environ.get("TELEGRAM_PROXY") async with httpx.AsyncClient(proxy=proxy_url) as hc: await hc.post( f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage", data={"chat_id": TELEGRAM_CHAT_ID, "text": msg, "parse_mode": "Markdown"}, ) previous_states[c.id] = current_status except Exception as e: print(f"Error in container monitor: {e}") await asyncio.sleep(60) @app.on_event("startup") async def startup_event(): asyncio.create_task(monitor_containers()) @app.get("/api/health") async def health(): return {"status": "ok"} # Public auth endpoints app.include_router(auth.router, prefix="/api/auth", tags=["auth"]) # Protected endpoints app.include_router(docker_router.router, prefix="/api/docker", dependencies=[Depends(auth_module.get_current_user)]) app.include_router(gitea.router, prefix="/api/gitea", dependencies=[Depends(auth_module.get_current_user)]) app.include_router(files.router, prefix="/api/files", dependencies=[Depends(auth_module.get_current_user)]) app.include_router(system.router, prefix="/api/system", dependencies=[Depends(auth_module.get_current_user)]) # WebSocket endpoint (auth handled inside handler via Query param) app.add_api_websocket_route("/ws/terminal", terminal.ws_endpoint) app.mount("/", StaticFiles(directory="/app/static", html=True), name="static")