Refactor: restructure market module with services, stores, and utils
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
工具模块
|
||||
"""
|
||||
|
||||
from .ws_manager import WebSocketManager
|
||||
|
||||
__all__ = ['WebSocketManager']
|
||||
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
WebSocket 连接管理器
|
||||
可复用的 WebSocket 客户端管理和消息广播
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import threading
|
||||
from typing import Set, Dict, Any, Optional
|
||||
|
||||
|
||||
class WebSocketManager:
|
||||
"""
|
||||
WebSocket 连接管理器
|
||||
|
||||
职责:
|
||||
- 管理客户端连接(添加/移除)
|
||||
- 线程安全操作
|
||||
- 异步广播消息
|
||||
- 同步广播(从非异步上下文)
|
||||
"""
|
||||
|
||||
def __init__(self, name: str = "default"):
|
||||
self._name = name
|
||||
self._clients: Set = set()
|
||||
self._lock = threading.Lock()
|
||||
self._main_loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
|
||||
print(f"[WebSocketManager:{name}] 已初始化")
|
||||
|
||||
# ==================== 事件循环 ====================
|
||||
|
||||
def set_event_loop(self, loop: asyncio.AbstractEventLoop):
|
||||
"""设置主事件循环引用"""
|
||||
self._main_loop = loop
|
||||
print(f"[WebSocketManager:{self._name}] 已设置事件循环")
|
||||
|
||||
# ==================== 客户端管理 ====================
|
||||
|
||||
def add_client(self, client) -> int:
|
||||
"""
|
||||
添加客户端连接
|
||||
|
||||
Args:
|
||||
client: WebSocket 连接对象
|
||||
|
||||
Returns:
|
||||
当前连接数
|
||||
"""
|
||||
with self._lock:
|
||||
self._clients.add(client)
|
||||
count = len(self._clients)
|
||||
print(f"[WebSocketManager:{self._name}] 客户端已连接, 当前: {count}")
|
||||
return count
|
||||
|
||||
def remove_client(self, client) -> int:
|
||||
"""
|
||||
移除客户端连接
|
||||
|
||||
Args:
|
||||
client: WebSocket 连接对象
|
||||
|
||||
Returns:
|
||||
当前连接数
|
||||
"""
|
||||
with self._lock:
|
||||
self._clients.discard(client)
|
||||
count = len(self._clients)
|
||||
print(f"[WebSocketManager:{self._name}] 客户端已断开, 当前: {count}")
|
||||
return count
|
||||
|
||||
def get_client_count(self) -> int:
|
||||
"""获取客户端数量"""
|
||||
with self._lock:
|
||||
return len(self._clients)
|
||||
|
||||
# ==================== 消息广播 ====================
|
||||
|
||||
async def broadcast(self, message: Dict[str, Any]):
|
||||
"""
|
||||
异步广播消息到所有客户端
|
||||
|
||||
Args:
|
||||
message: 消息字典,自动转为 JSON
|
||||
"""
|
||||
with self._lock:
|
||||
clients = list(self._clients)
|
||||
|
||||
if not clients:
|
||||
return
|
||||
|
||||
text = json.dumps(message, ensure_ascii=False)
|
||||
|
||||
for client in clients:
|
||||
try:
|
||||
await client.send_text(text)
|
||||
except Exception as e:
|
||||
print(f"[WebSocketManager:{self._name}] 发送失败: {e}")
|
||||
self.remove_client(client)
|
||||
|
||||
async def send_to_client(self, client, message: Dict[str, Any]):
|
||||
"""
|
||||
发送消息到单个客户端
|
||||
|
||||
Args:
|
||||
client: WebSocket 连接对象
|
||||
message: 消息字典
|
||||
"""
|
||||
try:
|
||||
text = json.dumps(message, ensure_ascii=False)
|
||||
await client.send_text(text)
|
||||
except Exception as e:
|
||||
print(f"[WebSocketManager:{self._name}] 发送到客户端失败: {e}")
|
||||
self.remove_client(client)
|
||||
|
||||
def broadcast_sync(self, message: Dict[str, Any]):
|
||||
"""
|
||||
同步方式广播(从非异步上下文调用)
|
||||
|
||||
用于在线程中向主事件循环提交广播任务
|
||||
|
||||
Args:
|
||||
message: 消息字典
|
||||
"""
|
||||
if self._main_loop and self._main_loop.is_running():
|
||||
asyncio.run_coroutine_threadsafe(
|
||||
self.broadcast(message),
|
||||
self._main_loop
|
||||
)
|
||||
else:
|
||||
print(f"[WebSocketManager:{self._name}] 事件循环未运行,无法广播")
|
||||
|
||||
# ==================== 状态查询 ====================
|
||||
|
||||
def get_status(self) -> Dict[str, Any]:
|
||||
"""获取状态"""
|
||||
return {
|
||||
"name": self._name,
|
||||
"clients": self.get_client_count(),
|
||||
"loop_set": self._main_loop is not None
|
||||
}
|
||||
Reference in New Issue
Block a user