""" Manages persistent per-user WebSocket connections for the notification channel. The DB is the source of truth — this layer just delivers live pushes to connected clients. """ import logging from fastapi import WebSocket logger = logging.getLogger("app") # user_id (str) -> active WebSocket; replaced on reconnect connections: dict[str, WebSocket] = {} def register(user_id: str, ws: WebSocket) -> None: connections[user_id] = ws def unregister(user_id: str) -> None: connections.pop(user_id, None) async def send_notification(user_id: str, notification: dict) -> None: """Push a single notification to the user if they're connected. No-op otherwise.""" ws = connections.get(user_id) if ws: try: await ws.send_json({"type": "push", "notification": notification}) except Exception as e: # Stale connection — the disconnect handler will clean it up logger.debug(f"WebSocket send failed (stale connection): {e}") async def send_delete(user_id: str, notification_id: str) -> None: """Tell the client to remove a notification from its local list.""" ws = connections.get(user_id) if ws: try: await ws.send_json({"type": "delete", "notification_id": notification_id}) except Exception as e: logger.debug(f"WebSocket send failed (stale connection): {e}")