You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
3.4 KiB
110 lines
3.4 KiB
"""
|
|
实时数据路由
|
|
"""
|
|
from fastapi import APIRouter, Depends, Query, WebSocket, WebSocketDisconnect
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.db.session import get_db
|
|
from app.schemas.base import ResponseModel
|
|
from app.services.realtime_service import RealtimeService
|
|
from app.core.security import get_current_user
|
|
from app.models.user import User
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/snapshot", response_model=ResponseModel)
|
|
async def get_realtime_snapshot(
|
|
codes: str = Query(..., description="代码列表,多个用逗号分隔"),
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(get_current_user)
|
|
):
|
|
"""获取最新快照数据"""
|
|
service = RealtimeService(db)
|
|
code_list = [c.strip() for c in codes.split(",")]
|
|
data = service.get_latest_snapshot(code_list)
|
|
return ResponseModel(data=data)
|
|
|
|
|
|
@router.post("/subscribe", response_model=ResponseModel)
|
|
async def subscribe_realtime(
|
|
codes: str = Query(..., description="代码列表,多个用逗号分隔"),
|
|
types: str = Query("snapshot", description="订阅类型: snapshot, kline"),
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(get_current_user)
|
|
):
|
|
"""开始实时数据订阅"""
|
|
code_list = [c.strip() for c in codes.split(",")]
|
|
return ResponseModel(data={
|
|
"message": "订阅成功",
|
|
"codes": code_list,
|
|
"types": types.split(",")
|
|
})
|
|
|
|
|
|
@router.delete("/subscribe", response_model=ResponseModel)
|
|
async def unsubscribe_realtime(
|
|
codes: str = Query(None, description="代码列表,多个用逗号分隔,为空则取消所有"),
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(get_current_user)
|
|
):
|
|
"""停止实时数据订阅"""
|
|
code_list = [c.strip() for c in codes.split(",")] if codes else None
|
|
return ResponseModel(data={
|
|
"message": "取消订阅成功",
|
|
"codes": code_list
|
|
})
|
|
|
|
|
|
@router.get("/subscribe/status", response_model=ResponseModel)
|
|
async def get_subscribe_status(
|
|
current_user: User = Depends(get_current_user)
|
|
):
|
|
"""获取订阅状态"""
|
|
return ResponseModel(data={
|
|
"subscribed_codes": [],
|
|
"subscribed_types": []
|
|
})
|
|
|
|
|
|
@router.websocket("/stream")
|
|
async def realtime_websocket(websocket: WebSocket):
|
|
"""WebSocket实时数据流"""
|
|
# 获取查询参数
|
|
query_params = websocket.query_params
|
|
codes_str = query_params.get("codes", "")
|
|
types_str = query_params.get("types", "snapshot")
|
|
|
|
codes = [c.strip() for c in codes_str.split(",") if c.strip()]
|
|
|
|
if not codes:
|
|
await websocket.close(code=4000, reason="Missing codes parameter")
|
|
return
|
|
|
|
# 创建数据库会话
|
|
from app.db.session import SessionLocal
|
|
db = SessionLocal()
|
|
|
|
try:
|
|
service = RealtimeService(db)
|
|
await service.subscribe_websocket(websocket, codes)
|
|
|
|
# 保持连接
|
|
while True:
|
|
try:
|
|
# 接收客户端消息(心跳检测)
|
|
data = await websocket.receive_text()
|
|
# 回复心跳
|
|
await websocket.send_json({"type": "heartbeat", "timestamp": datetime.utcnow().isoformat()})
|
|
except WebSocketDisconnect:
|
|
break
|
|
except Exception as e:
|
|
break
|
|
|
|
finally:
|
|
await service.unsubscribe_websocket(websocket, codes)
|
|
db.close()
|
|
|
|
|
|
from datetime import datetime
|