import os import sys from contextlib import asynccontextmanager from fastapi import FastAPI from app.api.auth.router import router as auth_router from app.api.editor.router import router as editor_router from app.api.proxy.router import router as proxy_router from app.core.config import settings from app.core.mongodb import close_mongodb, init_mongodb from app.core.security import hash_password from app.integrations.docker import get_all_services_in_dir from app.integrations.docker.discovery import service_scan_root from app.repositories.auth import ensure_auth_indexes, ensure_single_account from app.repositories.health import ensure_health_indexes from app.repositories.proxy import ensure_proxy_indexes from app.repositories.templates import ensure_template_indexes from app.services.mitmproxy.health_monitor import health_monitor from app.services.mitmproxy.recovery import reconcile_runtime @asynccontextmanager async def lifespan(_: FastAPI): await init_mongodb() await ensure_auth_indexes() await ensure_single_account( username=settings.AUTH_USERNAME, password_hash=hash_password(settings.AUTH_PASSWORD), ) await ensure_proxy_indexes() await ensure_template_indexes() await ensure_health_indexes() recovered = await reconcile_runtime() if recovered: recovered_count = len(recovered) error_count = sum( 1 for _proxy_port, values in recovered if values.get("status") == "error" ) print( f"[thePlug] Reconciled {recovered_count} persisted proxy runtimes" f" ({error_count} with errors).", file=sys.stderr, ) scan_root = service_scan_root() services = get_all_services_in_dir(scan_root) or [] if not services: warning = ( "\n" + "!" * 60 + "\n" " WARNING: No services found in scan root!\n" f" Scanned: {scan_root}\n" + "!" * 60 + "\n" ) print(warning, file=sys.stderr) try: await health_monitor.start() yield finally: await health_monitor.stop() await close_mongodb() DEBUG = os.getenv("DEBUG", "false").lower() == "true" app = FastAPI( title="thePlugAPI", lifespan=lifespan, docs_url="/docs" if DEBUG else None, redoc_url="/redoc" if DEBUG else None, openapi_url="/openapi.json" if DEBUG else None, ) app.include_router(auth_router) app.include_router(editor_router) app.include_router(proxy_router) @app.get("/") async def root(): return {"Hello": "World!"}