""" FastAPI application entry point. """ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.config import settings from app.core.http_metrics import HTTPMetricsMiddleware # Create FastAPI app app = FastAPI( title=settings.PROJECT_NAME, version="0.1.0", description="MyBeacon Backend API - Modular BLE/WiFi monitoring platform", docs_url="/docs", redoc_url="/redoc", ) # Configure CORS app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins_list, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Add HTTP metrics middleware app.add_middleware(HTTPMetricsMiddleware) @app.get("/") async def root(): """Root endpoint - API info.""" return { "name": settings.PROJECT_NAME, "version": "0.1.0", "status": "running", } @app.get("/health") async def health_check(): """Health check endpoint.""" return {"status": "healthy"} # Include routers from app.api.v1 import router as api_v1_router app.include_router(api_v1_router, prefix=settings.API_V1_PREFIX) # Background task for tunnel watchdog with DB updates async def tunnel_watchdog_with_db(): """ Tunnel watchdog: cleanup orphaned ttyd and stale sessions Runs independently of in-memory state and survives restarts """ import asyncio from app.services.tunnel_service import tunnel_service from app.core.database import async_session_maker from app.models.device import Device from sqlalchemy import select from sqlalchemy.orm import attributes while True: await asyncio.sleep(60) # Every minute # Run watchdog and get list of tunnels to disable tunnels_to_disable = await tunnel_service.watchdog_cleanup() if tunnels_to_disable: print(f"[watchdog] Disabling {len(tunnels_to_disable)} tunnels in device config") async with async_session_maker() as db: for device_mac, tunnel_type in tunnels_to_disable: # Find device by MAC address result = await db.execute( select(Device).where(Device.mac_address == device_mac) ) device = result.scalar_one_or_none() if device and device.config: tunnel_key = f"{tunnel_type}_tunnel" if tunnel_key in device.config: # Disable tunnel device.config[tunnel_key]["enabled"] = False attributes.flag_modified(device, "config") print(f"[watchdog] Disabled {tunnel_type} tunnel for {device_mac}") await db.commit() # Startup event @app.on_event("startup") async def startup_event(): """Initialize services on startup""" # Start tunnel watchdog background task import asyncio asyncio.create_task(tunnel_watchdog_with_db()) print("[startup] Tunnel watchdog started (checks every 60s)") # Start host monitoring background task from app.services.host_monitor import host_monitor asyncio.create_task(host_monitor.run_monitoring_loop()) print("[startup] Host monitoring task started") # Shutdown event @app.on_event("shutdown") async def shutdown_event(): """Cleanup on shutdown""" from app.services.host_monitor import host_monitor await host_monitor.stop() print("[shutdown] Host monitoring stopped")