netx/netx_api/main.py
oliver a2f91f6ee2 Split port traffic service and replace deprecated UTC/lifespan APIs.
Keep the public facade stable while moving device CRUD and sample/compare
logic into focused modules, and use naive UTC via timeutil plus FastAPI lifespan.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-02 17:06:46 +08:00

106 lines
3.4 KiB
Python

"""FastAPI application entry — routers + thin lifecycle hooks."""
from __future__ import annotations
import logging
import time
from contextlib import asynccontextmanager
from typing import AsyncIterator
import uvicorn
from fastapi import FastAPI
from .auth_middleware import AuthAuditMiddleware
from .auth_router import router as auth_router
from .alarms_router import router as alarms_router
from .cli_router import router as cli_router
from .collection_router import router as collection_router
from .config import settings
from .config_sync_router import router as config_sync_router
from .integrations_router import router as integrations_router
from .lldp_collect_router import router as lldp_collect_router
from .managed_ne_router import router as managed_ne_router
from .ops_router import router as ops_router
from .parser_config import load_parser_config
from .port_traffic_router import router as port_traffic_router
from .sql_router import router as sql_router
from .sql_router import sql_query, sql_ume_query # noqa: F401 — tests import from main
from .topology_router import router as topology_router
from .ume_router import router as ume_router
from .ume_router import ( # noqa: F401 — tests import from main
_extract_ume_raw_group_field,
_serialize_ume_alarm_raw_row,
ume_alarms_fields,
)
from .ume_support import ( # noqa: F401 — tests import from main
_classify_protocol_bucket,
_protocol_bucket_label,
)
import netx_api.ume_support as ume_support
from .oclaw_alarm_forwarder import shutdown_oclaw_alarm_forwarder
from .ume_alarm_ws import shutdown_ws_consumer
from .webcrt_router import router as webcrt_router
_schedule_log = logging.getLogger("netx.ume.schedule")
_BOOT_MONO = time.monotonic()
@asynccontextmanager
async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
from .app_startup import run_api_startup
run_api_startup()
try:
yield
finally:
shutdown_oclaw_alarm_forwarder()
if ume_support._UME_WS_STOP_EVENT is not None:
ume_support._UME_WS_STOP_EVENT.set()
shutdown_ws_consumer()
app = FastAPI(
title="netx ops tool",
version="0.1.0",
docs_url="/docs" if bool(settings.docs_enabled) else None,
redoc_url="/redoc" if bool(settings.docs_enabled) else None,
openapi_url="/openapi.json" if bool(settings.docs_enabled) else None,
lifespan=lifespan,
)
app.add_middleware(AuthAuditMiddleware)
app.include_router(auth_router)
app.include_router(managed_ne_router)
app.include_router(cli_router)
app.include_router(collection_router)
app.include_router(config_sync_router)
app.include_router(port_traffic_router)
app.include_router(webcrt_router)
app.include_router(topology_router)
app.include_router(lldp_collect_router)
app.include_router(ops_router)
app.include_router(sql_router)
app.include_router(integrations_router)
app.include_router(ume_router)
app.include_router(alarms_router)
parser_cfg = load_parser_config()
@app.get("/health", status_code=200)
def health() -> dict[str, str]:
return {"status": "ok"}
@app.get("/")
def root() -> dict:
return {
"ok": True,
"mode": "api_only",
"message": "netx UI is served by Vite frontend only",
"frontend_url": settings.frontend_url,
"api_health": "/health",
"api_status": "/v1/integrations/status",
}
if __name__ == "__main__":
uvicorn.run("netx_api.main:app", host=settings.host, port=settings.port, reload=False)