Files
v6ole 848f804169 PingWatch 网络设备离线监控系统
- FastAPI 后端 + Vue 3 前端
- Docker Compose 一键部署
- Casdoor OAuth 认证集成
- LogHive 集中式日志
- 设备批量 CSV 导入/导出
- WebSocket 实时状态推送
- 企业微信告警通知
- fping 高性能并发 Ping 检测

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 15:02:04 +08:00

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(),
})