from fastapi import FastAPI from contextlib import asynccontextmanager, AsyncExitStack from fastapi.middleware.gzip import GZipMiddleware from fastapi.middleware.cors import CORSMiddleware import logging from datetime import datetime from app.api.problem_details import install_problem_details_handlers from app.api.health import router as health_router from app.api.v1.rest_router import api_router from app.infra.db.dynamic_manager import project_connection_manager from app.infra.db.postgresql.workbench_event_hub import workbench_event_hubs from app.infra.db.metadb.database import close_metadata_engine from app.infra.db.timescaledb.sync_pool import close_all_timescale_pools from app.native.wndb.core.connection import close_all_project_pools from app.core.config import settings from samples.peripheral.api import create_app as create_peripheral_app # 导入审计中间件 from app.infra.audit.middleware import AuditMiddleware logger = logging.getLogger() logger.setLevel(logging.INFO) @asynccontextmanager async def lifespan(app: FastAPI): app.state.startup_complete = False logger.info("**********************************************************") logger.info(str(datetime.now())) logger.info("TJWater CloudService is starting...") logger.info("**********************************************************") try: async with AsyncExitStack() as stack: if mcp_runtime is not None: await stack.enter_async_context(mcp_runtime.lifespan()) app.state.startup_complete = True try: yield finally: app.state.startup_complete = False finally: await workbench_event_hubs.close_all() await project_connection_manager.close_all() close_all_timescale_pools() close_all_project_pools() await close_metadata_engine() logger.info("Database connections closed") # Disabled deployments do not import the MCP SDK or acquire business credentials. from app.mcp.config import McpSettings mcp_settings = McpSettings() mcp_runtime = None if mcp_settings.enabled: from app.mcp.application import McpQueryApplication mcp_runtime = McpQueryApplication(mcp_settings) # 根据环境配置决定是否启用文档 is_production = settings.ENVIRONMENT.lower() == "production" app = FastAPI( lifespan=lifespan, title=settings.PROJECT_NAME, description="TJWater Server - 供水管网智能管理系统", version="1.0.0", docs_url=None if is_production else "/docs", redoc_url=None if is_production else "/redoc", openapi_url=None if is_production else "/openapi.json", redirect_slashes=False, ) # Include Routers app.state.startup_complete = False app.include_router(health_router) app.include_router(api_router, prefix="/api/v1") install_problem_details_handlers(app) from app.api.v1.endpoints.mcp_queries import router as mcp_context_router app.state.mcp_runtime = mcp_runtime app.include_router(mcp_context_router, prefix="/api/v1") app.mount("/peripheral", create_peripheral_app(), name="peripheral") # Legacy routers without version prefix # app.include_router(api_router) # 配置中间件 app.add_middleware(GZipMiddleware, minimum_size=1000) # 添加审计中间件(可选,记录关键操作) app.add_middleware(AuditMiddleware) if mcp_runtime is not None: from app.mcp.dispatch import McpDispatchMiddleware app.add_middleware(McpDispatchMiddleware, runtime=mcp_runtime) # 配置 CORS 中间件 # 确保这是你最后一个添加的 app.add_middleware app.add_middleware( CORSMiddleware, allow_origins=settings.cors_allowed_origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )