848f804169
- FastAPI 后端 + Vue 3 前端 - Docker Compose 一键部署 - Casdoor OAuth 认证集成 - LogHive 集中式日志 - 设备批量 CSV 导入/导出 - WebSocket 实时状态推送 - 企业微信告警通知 - fping 高性能并发 Ping 检测 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
71 lines
1.7 KiB
Python
71 lines
1.7 KiB
Python
"""WebSocket 实时推送"""
|
|
import json
|
|
import asyncio
|
|
import logging
|
|
|
|
from fastapi import APIRouter, WebSocket, WebSocketDisconnect
|
|
|
|
logger = logging.getLogger("pingwatch.ws")
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
class ConnectionManager:
|
|
"""WebSocket 连接管理器"""
|
|
|
|
def __init__(self):
|
|
self._connections: set[WebSocket] = set()
|
|
|
|
async def connect(self, ws: WebSocket):
|
|
await ws.accept()
|
|
self._connections.add(ws)
|
|
|
|
def disconnect(self, ws: WebSocket):
|
|
self._connections.discard(ws)
|
|
|
|
async def broadcast(self, message: dict):
|
|
"""向所有客户端广播消息"""
|
|
dead = set()
|
|
for ws in self._connections:
|
|
try:
|
|
await ws.send_json(message)
|
|
except Exception:
|
|
dead.add(ws)
|
|
self._connections -= dead
|
|
|
|
@property
|
|
def count(self) -> int:
|
|
return len(self._connections)
|
|
|
|
|
|
manager = ConnectionManager()
|
|
|
|
|
|
@router.websocket("/ws")
|
|
async def websocket_endpoint(ws: WebSocket):
|
|
"""WebSocket 端点,用于前端实时接收状态更新"""
|
|
await manager.connect(ws)
|
|
try:
|
|
while True:
|
|
# 保持连接,接收心跳 pong
|
|
data = await ws.receive_text()
|
|
if data == "ping":
|
|
await ws.send_text("pong")
|
|
except WebSocketDisconnect:
|
|
pass
|
|
except Exception as e:
|
|
logger.error(f"WebSocket 异常: {e}")
|
|
finally:
|
|
manager.disconnect(ws)
|
|
|
|
|
|
async def broadcast_status_change(device_id: int, status: str, name: str):
|
|
"""广播设备状态变化"""
|
|
await manager.broadcast({
|
|
"type": "device_status_change",
|
|
"device_id": device_id,
|
|
"status": status,
|
|
"name": name,
|
|
"timestamp": asyncio.get_event_loop().time(),
|
|
})
|