| import asyncio |
| from typing import Any |
|
|
| from fastapi import WebSocket |
|
|
| from core.logger import logger |
|
|
|
|
| class ConnectionManager: |
| def __init__(self): |
| self._connections: set[WebSocket] = set() |
| self._lock = asyncio.Lock() |
|
|
| async def connect(self, websocket: WebSocket) -> None: |
| await websocket.accept() |
|
|
| async with self._lock: |
| self._connections.add(websocket) |
|
|
| async def disconnect(self, websocket: WebSocket) -> None: |
| async with self._lock: |
| self._connections.discard(websocket) |
|
|
| async def send_json(self, websocket: WebSocket, payload: dict[str, Any]) -> None: |
| await websocket.send_json(payload) |
|
|
| async def broadcast(self, payload: dict[str, Any]) -> None: |
| async with self._lock: |
| connections = list(self._connections) |
|
|
| stale_connections: list[WebSocket] = [] |
|
|
| for connection in connections: |
| try: |
| await connection.send_json(payload) |
| except Exception as exc: |
| logger.warning(f"WebSocket broadcast failed: {exc}") |
| stale_connections.append(connection) |
|
|
| if stale_connections: |
| async with self._lock: |
| for connection in stale_connections: |
| self._connections.discard(connection) |
|
|
|
|
| manager = ConnectionManager() |
|
|