"""Connection manager for Socket.io rooms (one room per update job).""" from app.core.logging import get_logger logger = get_logger(__name__) class WSManager: """Tracks active Socket.io sessions and job-room subscriptions.""" def __init__(self) -> None: # sid -> set of job rooms the client subscribed to self._subscriptions: dict[str, set[str]] = {} def register(self, sid: str) -> None: self._subscriptions.setdefault(sid, set()) logger.info("ws.client_connected", sid=sid) def unregister(self, sid: str) -> None: self._subscriptions.pop(sid, None) logger.info("ws.client_disconnected", sid=sid) def subscribe(self, sid: str, job_id: int) -> str: room = self.room_for(job_id) self._subscriptions.setdefault(sid, set()).add(room) return room def unsubscribe(self, sid: str, job_id: int) -> str: room = self.room_for(job_id) if sid in self._subscriptions: self._subscriptions[sid].discard(room) return room @staticmethod def room_for(job_id: int) -> str: return f"job:{job_id}" @property def client_count(self) -> int: return len(self._subscriptions) ws_manager = WSManager()