import logging from contextlib import asynccontextmanager from fastapi import FastAPI, WebSocket, WebSocketDisconnect from fastapi.middleware.cors import CORSMiddleware from app.config import settings from app.api.routes.api import api_router from app.ws.manager import ws_manager logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s") logger = logging.getLogger("WTFX-Backend") @asynccontextmanager async def lifespan(app: FastAPI): logger.info(f"Starting {settings.PROJECT_NAME} v{settings.VERSION} [{settings.ENVIRONMENT}]") yield logger.info("Shutting down WTFX Backend service...") app = FastAPI( title=settings.PROJECT_NAME, version=settings.VERSION, lifespan=lifespan, docs_url="/docs" if settings.DEBUG or settings.ENVIRONMENT != "production" else None, ) # CORS 配置 app.add_middleware( CORSMiddleware, allow_origins=settings.CORS_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # 注册 API 路由 app.include_router(api_router, prefix="/api") # WebSocket 实时订阅端点 @app.websocket("/ws/market/{market_address}") async def websocket_market_endpoint(websocket: WebSocket, market_address: str): channel = f"market:{market_address.lower()}" await ws_manager.connect(websocket, channel) try: while True: data = await websocket.receive_text() # 客户端心跳 ping/pong if data == "ping": await websocket.send_text("pong") except WebSocketDisconnect: ws_manager.disconnect(websocket, channel) @app.get("/health") async def health_check(): return {"status": "ok", "version": settings.VERSION, "env": settings.ENVIRONMENT}