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.

187 lines
6.8 KiB

"""
WebSocket API端点
"""
import asyncio
import json
from datetime import datetime
from typing import Dict, Any, Optional
from fastapi import APIRouter, WebSocket, WebSocketDisconnect, HTTPException, status
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field
from app.core.websocket.manager import WebSocketManager
from app.core.websocket.client import WebSocketClient
from app.schemas.websocket import SuccessResponse as WebSocketResponse
from app.utils.structured_log import get_structured_logger
from app.utils.api_decorators import handle_api_errors
logger = get_structured_logger(__name__)
router = APIRouter()
# 创建全局websocket_manager实例
websocket_manager = WebSocketManager()
# 定义缺失的请求和响应模型
class SuccessResponse(BaseModel):
"""成功响应模型"""
success: bool = Field(True, description="操作是否成功")
message: str = Field(..., description="响应消息")
data: Optional[Dict[str, Any]] = Field(None, description="响应数据")
timestamp: str = Field(..., description="时间戳")
class CreateWebSocketClientRequest(BaseModel):
"""创建WebSocket客户端请求模型"""
name: str = Field(..., description="客户端名称")
url: str = Field(..., description="WebSocket URL")
heartbeat_interval: Optional[int] = Field(30, description="心跳间隔(秒)")
def now_iso() -> str:
return datetime.now().isoformat()
# 创建并连接客户端
@router.post("/websocket/clients", summary="创建并连接WebSocket客户端", response_model=SuccessResponse)
@handle_api_errors
async def create_and_connect_client(request: CreateWebSocketClientRequest):
"""创建客户端并立即连接"""
try:
# 创建客户端(自动创建3个Channel和适配器)
client = await websocket_manager.create_client(request.name, request.url, request.heartbeat_interval)
# 连接客户端
success = await websocket_manager.connect_client(request.name)
if not success:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"WebSocket客户端 {request.name} 连接失败"
)
logger.info(f"WebSocket客户端 {request.name} 创建并连接成功")
return SuccessResponse(
success=True,
message=f"WebSocket客户端 {request.name} 创建并连接成功",
data={
"name": request.name,
"url": request.url,
"status": "connected",
"heartbeat_interval": request.heartbeat_interval,
"channels": ["heartbeat", "send", "receive"]
},
timestamp=now_iso()
)
except Exception as e:
logger.error(f"创建WebSocket客户端失败: {request.name} - {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"创建WebSocket客户端失败: {str(e)}"
)
# 断开客户端
@router.post("/websocket/clients/{name}/disconnect", summary="断开WebSocket客户端", response_model=SuccessResponse)
@handle_api_errors
async def disconnect_client(name: str):
"""断开已存在客户端"""
try:
success = await websocket_manager.disconnect_client(name)
if not success:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"WebSocket客户端 {name} 不存在或已断开"
)
logger.info(f"WebSocket客户端 {name} 断开成功")
return SuccessResponse(
success=True,
message=f"WebSocket客户端 {name} 断开成功",
timestamp=now_iso()
)
except Exception as e:
logger.error(f"断开WebSocket客户端失败: {name} - {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"断开WebSocket客户端失败: {str(e)}"
)
# 发送消息
@router.post("/websocket/clients/{name}/send", summary="发送消息到WebSocket客户端", response_model=SuccessResponse)
@handle_api_errors
async def send_message(name: str, message_type: str = "data", data: dict = None, priority: int = 0):
"""发送消息到指定客户端"""
try:
if data is None:
data = {}
success = await websocket_manager.send_message(name, message_type, data, priority)
if not success:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"发送消息到WebSocket客户端 {name} 失败"
)
logger.info(f"消息发送成功: {name} -> {message_type}")
return SuccessResponse(
success=True,
message=f"消息发送成功",
data={"client": name, "type": message_type, "priority": priority},
timestamp=now_iso()
)
except Exception as e:
logger.error(f"发送消息失败: {name} -> {message_type} - {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"发送消息失败: {str(e)}"
)
# 发送心跳
@router.post("/websocket/clients/{name}/heartbeat", summary="发送心跳消息", response_model=SuccessResponse)
@handle_api_errors
async def send_heartbeat(name: str):
"""发送心跳消息到指定客户端"""
try:
success = await websocket_manager.send_heartbeat(name)
if not success:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"发送心跳到WebSocket客户端 {name} 失败"
)
logger.info(f"心跳发送成功: {name}")
return SuccessResponse(
success=True,
message=f"心跳发送成功",
data={"client": name},
timestamp=now_iso()
)
except Exception as e:
logger.error(f"发送心跳失败: {name} - {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"发送心跳失败: {str(e)}"
)
# 获取统计信息
@router.get("/websocket/stats", summary="获取WebSocket统计信息")
@handle_api_errors
async def get_stats():
"""获取WebSocket管理器统计信息"""
try:
stats = websocket_manager.get_stats()
return SuccessResponse(
message="获取统计信息成功",
data=stats,
timestamp=now_iso()
)
except Exception as e:
logger.error(f"获取统计信息失败: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"获取统计信息失败: {str(e)}"
)