49 lines
1.5 KiB
Python
Executable File
49 lines
1.5 KiB
Python
Executable File
"""
|
|
WebSocketStream — legacy bridge between the EventBus and WebSocket clients.
|
|
|
|
NOTE: The real broadcasting is now done in backend/main.py via
|
|
`_ws_broadcast` which properly awaits the async send. This class is kept
|
|
for backward compatibility with the api.py facade, but its `attach_bus`
|
|
method is a no-op (the actual wiring happens in main.py).
|
|
|
|
F-15 remediation: the shared ``clients`` list is now guarded by a lock
|
|
so concurrent register/unregister calls from multiple WS handlers
|
|
can't race.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import threading
|
|
from typing import Any, List
|
|
|
|
from backend.events.bus import EventBus
|
|
|
|
|
|
class WebSocketStream:
|
|
def __init__(self) -> None:
|
|
self._lock = threading.Lock()
|
|
self.clients: List[Any] = [] # shared with main.py's hub.clients
|
|
|
|
def attach_bus(self, bus: EventBus) -> None:
|
|
"""No-op — broadcasting is wired in backend/main.py via _ws_broadcast.
|
|
|
|
Kept for backward compat with api.py's attach_ws_stream().
|
|
"""
|
|
pass
|
|
|
|
def register_client(self, client: Any) -> None:
|
|
with self._lock:
|
|
self.clients.append(client)
|
|
|
|
def unregister_client(self, client: Any) -> None:
|
|
with self._lock:
|
|
try:
|
|
self.clients.remove(client)
|
|
except ValueError:
|
|
pass
|
|
|
|
def snapshot_clients(self) -> List[Any]:
|
|
"""Return a snapshot copy of the client list (safe for iteration)."""
|
|
with self._lock:
|
|
return list(self.clients)
|