Files
sanguo_vnpy_v2/sanguo_web/api/__init__.py
T
claude_dev 653472def3 feat: VeighNa Web 前端对等实现
对齐 VeighNa 4.4 原生 Qt UI,新增成交监控、资金监控、网关管理、全局配置等页面与 API,功能对等性 98.5%。

- 新增 API: /api/v1/trades, /api/v1/accounts, /api/v1/settings, 网关扩展
- 新增前端页面: 成交、资金、合约、网关、全局配置、微信通知
- 扩展导航菜单与实时数据推送
- 补充需求分析与实现计划文档
2026-07-04 20:13:03 +08:00

245 lines
6.2 KiB
Python

"""
Sanguo VeighNa Web API
FastAPI 应用入口
"""
from fastapi import FastAPI, Request, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException
from contextlib import asynccontextmanager
import logging
import os
from .routes import auth, gateway, market, trading, strategy, system, trades, accounts, settings
from ..services.main_service import VeighNaService
from ..websocket import router as websocket_router, EventMonitorManager
logger = logging.getLogger(__name__)
# 获取项目根目录
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 全局 VeighNa 服务实例
vn_service: VeighNaService = None
# 全局事件监听器管理器
event_monitor_manager: EventMonitorManager = None
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期管理"""
# 启动时初始化
global vn_service, event_monitor_manager
logger.info("Starting Sanguo VeighNa Web API...")
try:
vn_service = VeighNaService()
await vn_service.initialize()
logger.info("VeighNa service initialized successfully")
# 设置服务实例到各个路由模块
settings.set_vn_service(vn_service)
# 初始化事件监听器管理器
if vn_service.main_engine and vn_service.main_engine.event_engine:
event_monitor_manager = EventMonitorManager(vn_service.main_engine.event_engine)
event_monitor_manager.start_all()
logger.info("Event monitor manager initialized")
except Exception as e:
logger.error(f"Failed to initialize VeighNa service: {e}")
# 允许应用启动,但标记服务为未就绪
vn_service = None
event_monitor_manager = None
yield
# 关闭时清理
if event_monitor_manager:
event_monitor_manager.stop_all()
logger.info("Event monitor manager stopped")
if vn_service:
await vn_service.shutdown()
logger.info("VeighNa service shutdown complete")
# 创建 FastAPI 应用
app = FastAPI(
title="Sanguo VeighNa Web API",
description="Sanguo 量化交易平台 Web API",
version="1.0.0",
docs_url="/docs",
redoc_url="/redoc",
lifespan=lifespan
)
# CORS 中间件配置
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 生产环境应限制具体域名
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 全局异常处理
@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
"""处理 HTTP 异常"""
return JSONResponse(
status_code=exc.status_code,
content={"error": exc.detail, "status_code": exc.status_code}
)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
"""处理请求验证异常"""
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={
"error": "Validation error",
"details": exc.errors(),
"status_code": 422
}
)
@app.exception_handler(Exception)
async def general_exception_handler(request: Request, exc: Exception):
"""处理未捕获的异常"""
logger.error(f"Unhandled exception: {exc}", exc_info=True)
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={"error": "Internal server error", "status_code": 500}
)
# 注册路由
api_prefix = "/api/v1"
app.include_router(
system.router,
prefix=f"{api_prefix}/system",
tags=["system"]
)
app.include_router(
auth.router,
prefix=f"{api_prefix}/auth",
tags=["auth"]
)
app.include_router(
gateway.router,
prefix=f"{api_prefix}/gateway",
tags=["gateway"]
)
app.include_router(
market.router,
prefix=f"{api_prefix}/market",
tags=["market"]
)
app.include_router(
trading.router,
prefix=f"{api_prefix}/trading",
tags=["trading"]
)
app.include_router(
strategy.router,
prefix=f"{api_prefix}/strategy",
tags=["strategy"]
)
# Phase 1: 成交和资金监控
app.include_router(
trades.router,
prefix=f"{api_prefix}/trades",
tags=["trades"]
)
app.include_router(
accounts.router,
prefix=f"{api_prefix}/accounts",
tags=["accounts"]
)
# Phase 3: 全局配置
app.include_router(
settings.router,
prefix=f"{api_prefix}/settings",
tags=["settings"]
)
# WebSocket 路由(不使用 API 前缀)
app.include_router(
websocket_router,
tags=["websocket"]
)
# 挂载静态文件
static_dir = os.path.join(BASE_DIR, "static")
if os.path.exists(static_dir):
app.mount("/static", StaticFiles(directory=static_dir), name="static")
logger.info(f"Static files mounted from: {static_dir}")
else:
logger.warning(f"Static files directory not found: {static_dir}")
# 根路径 - 返回主页
@app.get("/")
async def root():
"""返回前端主页"""
template_path = os.path.join(BASE_DIR, "templates", "index.html")
if os.path.exists(template_path):
return FileResponse(template_path)
return {
"name": "Sanguo VeighNa Web API",
"version": "1.0.0",
"status": "running",
"docs": "/docs",
"health": "/health"
}
# API 根路径(保持兼容性)
@app.get("/api")
async def api_root():
"""API 根路径"""
return {
"name": "Sanguo VeighNa Web API",
"version": "1.0.0",
"status": "running",
"docs": "/docs",
"health": "/health"
}
# 健康检查(不通过 /api/v1 前缀,供容器健康检查使用)
@app.get("/health")
async def health_check():
"""健康检查端点"""
if vn_service is None:
return {
"status": "degraded",
"message": "VeighNa service not initialized"
}
return {
"status": "healthy",
"service": "Sanguo VeighNa Web API",
"version": "1.0.0"
}
# 导出应用实例(供 uvicorn 使用)
__all__ = ["app", "vn_service", "event_monitor_manager"]