"""FastAPI application entrypoint and runtime wiring.""" import asyncio import logging import os from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware import src.api.network_api as network_api import src.api.sniffer_api as sniffer_api import src.shared_objects as shared_objects from src.api import nft_manager from src.api import analysis_api from src.api import packet_api from src.api import packet_scripting_api from src.config import settings from src.utilities.database import DatabasePool from src.utilities.packet_broadcaster import PacketBroadcaster logging.basicConfig(level=getattr(logging, settings.log_level.upper(), logging.DEBUG)) shared_objects.db = DatabasePool( settings.db_dsn, min_size=settings.db_pool_min_size, max_size=settings.db_pool_max_size, ) app = FastAPI( root_path="/api", title="MITM Webserver Backend", description="Backend API for MITM Webserver", version="1.0.0", docs_url="/docs", redoc_url="/redoc", openapi_url="/openapi.json", ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.on_event("startup") async def on_startup() -> None: """Initialize shared runtime objects on the FastAPI event loop.""" loop = asyncio.get_running_loop() shared_objects.web_loop = loop try: await shared_objects.db.init_pool() except Exception: logging.exception("Failed to initialize DB pool") raise try: shared_objects.broadcaster = PacketBroadcaster(loop, queue_maxsize=settings.broadcaster_queue_maxsize) shared_objects.db.broadcaster = shared_objects.broadcaster except Exception: logging.exception("Failed to create/attach broadcaster") try: shared_objects.network_broadcaster = PacketBroadcaster(loop, queue_maxsize=settings.broadcaster_queue_maxsize) except Exception: logging.exception("Failed to create network broadcaster") try: from src import network_sniffer as sniffer try: sniffer.drain_buffer_to_shared_db() except Exception: logging.exception("Failed to drain sniffer buffer") except ImportError: logging.debug("Sniffer module not importable at startup; skipping buffer drain") @app.on_event("shutdown") async def shutdown_event() -> None: """Stop network resources and release shared runtime objects.""" try: from src.network_sniffer import stop_capture_session stop_capture_session() except Exception: logging.exception("Failed to stop capture sessions during shutdown") try: network_api.shutdown_network_api() except Exception: logging.exception("Error shutting down network API") try: from src.utilities.bridge_telemetry import bridge_telemetry_manager bridge_telemetry_manager.stop() except Exception: logging.exception("Failed to stop bridge telemetry collector") try: from src.utilities.tshark_manager import tshark_manager tshark_manager.stop() except Exception: logging.exception("Failed to stop tshark workers") try: from src.utilities.packet_tracker import packet_tracker packet_tracker.stop() except Exception: logging.exception("Failed to stop packet tracker") try: if shared_objects.broadcaster is not None: await shared_objects.broadcaster.close() except Exception: logging.exception("Failed to close packet broadcaster during shutdown") try: if shared_objects.network_broadcaster is not None: await shared_objects.network_broadcaster.close() except Exception: logging.exception("Failed to close network broadcaster during shutdown") try: web_db = getattr(shared_objects, "db", None) if web_db is not None: await web_db.close_pool() except Exception: logging.exception("Failed to close DB pool during shutdown") shared_objects.db = None shared_objects.broadcaster = None shared_objects.network_broadcaster = None shared_objects.web_loop = None @app.get("/hello") def hello() -> dict[str, str]: """Simple health-check endpoint.""" return {"message": "Hello from FastAPI 🎉"} @app.get("/versions") def versions() -> dict[str, str]: """Return runtime Python version.""" message = os.popen("python --version").read().strip() return {"message": message} app.include_router(network_api.router, prefix="/network", tags=["network"]) app.include_router(sniffer_api.router, prefix="/sniffer", tags=["sniffer"]) app.include_router(packet_api.router, prefix="/packets", tags=["packets"]) app.include_router(analysis_api.router, prefix="/analysis", tags=["analysis"]) app.include_router(nft_manager.router, tags=["firewall"]) app.include_router(packet_scripting_api.router, prefix="/scripts", tags=["scripts"]) packet_scripting_api.register_lifecycle(app)