from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from starlette.middleware.base import BaseHTTPMiddleware from app.core.config import settings from app.core.websocket.broadcaster import broadcaster from app.db.session import init_db, async_session_factory from app.api.main import api_router from app.api.v1 import websocket from app.services.scheduler import start_scheduler, stop_scheduler class WebSocketCORSMiddleware(BaseHTTPMiddleware): async def dispatch(self, request, call_next): if request.url.path.startswith("/ws") and request.method == "GET": response = await call_next(request) response.headers["Access-Control-Allow-Origin"] = "*" response.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" response.headers["Access-Control-Allow-Headers"] = "*" return response return await call_next(request) @asynccontextmanager async def lifespan(app: FastAPI): await init_db() start_scheduler() broadcaster.start() yield broadcaster.stop() stop_scheduler() app = FastAPI( title=settings.PROJECT_NAME, version=settings.VERSION, description="智能星球计划 - 态势感知系统\n\n## 功能模块\n\n- **用户认证**: JWT-based authentication\n- **数据源管理**: 多源数据采集器管理\n- **任务调度**: 定时任务调度与监控\n- **实时更新**: WebSocket实时数据推送\n- **告警系统**: 多级告警管理\n\n## 数据层级\n\n- **L1**: 核心数据 (TOP500, Epoch AI GPU)\n- **L2**: 扩展数据 (HuggingFace, PeeringDB, 海缆)\n- **L3**: 分析数据\n- **L4**: 决策支持", lifespan=lifespan, docs_url=None, redoc_url="/docs", openapi_url="/openapi.json", ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.add_middleware(WebSocketCORSMiddleware) app.include_router(api_router, prefix="/api/v1") app.include_router(websocket.router) @app.get("/health") async def health_check(): """健康检查端点""" return { "status": "healthy", "version": settings.VERSION, } @app.get("/") async def root(): """API根目录""" return { "name": settings.PROJECT_NAME, "version": settings.VERSION, "docs": "/docs", "redoc": "/redoc", } @app.get("/api/v1/scheduler/jobs") async def get_scheduler_jobs(): """获取调度任务列表""" from app.services.scheduler import get_scheduler_jobs return {"jobs": get_scheduler_jobs()}