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.

192 lines
8.3 KiB

"""
WebSocket发送控制器
专门负责统一的消息发送逻辑
遵循单一职责原则
"""
import asyncio
from typing import Dict, Any, Optional
from datetime import datetime
from app.core.websocket.channel import ChannelMessage, WebSocketChannel
from app.core.websocket.client import WebSocketClient
from app.utils.structured_log import get_structured_logger, LogLevel
logger = get_structured_logger(__name__, LogLevel.INFO)
class WebSocketSendController:
"""WebSocket发送控制器
单一职责:只负责统一的消息发送逻辑
- 统一发送循环
- 消息发送到WebSocket
- 优先级控制
- 发送任务管理
"""
def __init__(self, client: WebSocketClient, heartbeat_channel: WebSocketChannel, send_channel: WebSocketChannel):
self.client = client
self.client_name = client.name
self.heartbeat_channel = heartbeat_channel
self.send_channel = send_channel
self._send_task: Optional[asyncio.Task] = None
self._running = False
self._created_at = datetime.now()
logger.info(f"WebSocket发送控制器初始化: {self.client_name}")
async def start(self) -> bool:
"""启动发送控制器"""
if self._running:
logger.warning(f"WebSocket发送控制器 {self.client_name} 已在运行")
return True
try:
self._running = True
self._send_task = asyncio.create_task(self._unified_send_loop())
logger.info(f"WebSocket发送控制器启动成功: {self.client_name}")
return True
except Exception as e:
self._running = False
logger.error(f"WebSocket发送控制器启动失败: {self.client_name} - {e}")
return False
async def stop(self) -> bool:
"""停止发送控制器"""
if not self._running:
logger.warning(f"WebSocket发送控制器 {self.client_name} 未在运行")
return True
try:
self._running = False
if self._send_task and not self._send_task.done():
self._send_task.cancel()
try:
await self._send_task
except asyncio.CancelledError:
pass
logger.info(f"WebSocket发送控制器停止成功: {self.client_name}")
return True
except Exception as e:
logger.error(f"WebSocket发送控制器停止失败: {self.client_name} - {e}")
return False
async def _unified_send_loop(self):
"""统一发送循环
单一职责:只负责从Channel获取消息并发送到WebSocket
"""
logger.info(f"WebSocket发送控制器开始统一发送循环: {self.client_name}")
try:
while self._running and self.client.is_connected:
try:
# 检查Channel是否存在且已连接
if not self.heartbeat_channel or not self.send_channel:
logger.warning(f"Channel不存在,等待重试: {self.client_name}")
await asyncio.sleep(1)
continue
if not self.heartbeat_channel.is_connected or not self.send_channel.is_connected:
logger.warning(f"Channel未连接,等待重试: {self.client_name}")
await asyncio.sleep(1)
continue
# 优先级发送:先发送业务数据,再发送心跳
message_sent = False
# 1. 优先发送业务数据
if self.send_channel.queue_size > 0:
try:
message = await self.send_channel.receive_message()
if message:
success = await self._send_message(message)
if success:
logger.debug(f"WebSocket发送控制器发送业务消息成功: {self.client_name} -> {message.type}")
message_sent = True
else:
logger.warning(f"WebSocket发送控制器发送业务消息失败: {self.client_name} -> {message.type}")
except Exception as e:
logger.error(f"WebSocket发送控制器发送业务消息异常: {self.client_name} - {e}")
# 2. 如果没有业务数据,发送心跳
if not message_sent and self.heartbeat_channel.queue_size > 0:
try:
message = await self.heartbeat_channel.receive_message()
if message:
success = await self._send_message(message)
if success:
logger.debug(f"WebSocket发送控制器发送心跳消息成功: {self.client_name} -> {message.type}")
message_sent = True
else:
logger.warning(f"WebSocket发送控制器发送心跳消息失败: {self.client_name} -> {message.type}")
except Exception as e:
logger.error(f"WebSocket发送控制器发送心跳消息异常: {self.client_name} - {e}")
# 3. 如果没有消息需要发送,短暂等待
if not message_sent:
await asyncio.sleep(0.1) # 100ms
except asyncio.CancelledError:
logger.info(f"WebSocket发送控制器发送循环被取消: {self.client_name}")
break
except Exception as e:
logger.error(f"WebSocket发送控制器发送循环异常: {self.client_name} - {e}")
await asyncio.sleep(1) # 异常时等待1秒再重试
logger.info(f"WebSocket发送控制器统一发送循环结束: {self.client_name}")
except Exception as e:
logger.error(f"WebSocket发送控制器发送循环严重异常: {self.client_name} - {e}")
async def _send_message(self, message: ChannelMessage) -> bool:
"""发送消息到WebSocket
单一职责:只负责将消息发送到WebSocket客户端
"""
try:
if not self.client.is_connected:
logger.warning(f"WebSocket客户端未连接,无法发送消息: {self.client_name}")
return False
# 在发送时添加Type字段
send_data = {
"Type": message.type,
**message.data
}
# 使用序列化器序列化消息
from app.core.websocket.serializer import websocket_serializer
payload = websocket_serializer.serialize(send_data)
# 发送数据到WebSocket
success = await self.client.send_raw(payload)
if success:
logger.debug(f"WebSocket发送控制器消息发送成功: {self.client_name} -> {message.type}")
else:
logger.warning(f"WebSocket发送控制器消息发送失败: {self.client_name} -> {message.type}")
return success
except Exception as e:
logger.error(f"WebSocket发送控制器发送消息异常: {self.client_name} -> {message.type} - {e}")
return False
def is_running(self) -> bool:
"""检查发送控制器是否在运行"""
return self._running
def get_stats(self) -> Dict[str, Any]:
"""获取发送控制器统计信息"""
return {
"client_name": self.client_name,
"is_running": self._running,
"is_connected": self.client.is_connected,
"created_at": self._created_at.isoformat(),
"heartbeat_channel": self.heartbeat_channel.name,
"send_channel": self.send_channel.name
}