import os import sys from contextlib import asynccontextmanager from api.auth.router import router as auth_router from api.editor.router import router as editor_router from api.proxy.router import router as proxy_router from core.config import settings from core.mongodb import close_mongodb, init_mongodb from core.redis import close_redis, init_redis from core.security import hash_password from fastapi import FastAPI from integrations.docker import get_all_services_in_dir from integrations.docker.discovery import service_scan_root from repositories.auth import ensure_auth_indexes, ensure_single_account from repositories.examples import ensure_example_indexes from repositories.proxy import ensure_proxy_indexes from services.mitmproxy.recovery import reconcile_runtime @asynccontextmanager async def lifespan(_: FastAPI): await init_mongodb() await init_redis() 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_example_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() app.state.services = get_all_services_in_dir(scan_root) or [] if not app.state.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: yield finally: await close_redis() 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!"}