chat_manager.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import json
  2. import datetime
  3. import db
  4. from typing import Dict, List, Any
  5. from fastapi import WebSocket
  6. class ChatConnectionManager:
  7. def __init__(self):
  8. # order_id -> list of active websockets
  9. # order_id -> list of dicts: {"ws": websocket, "role": str}
  10. self.active_connections: Dict[int, List[Dict[str, Any]]] = {}
  11. async def connect(self, websocket: WebSocket, order_id: int, role: str):
  12. await websocket.accept()
  13. if order_id not in self.active_connections:
  14. self.active_connections[order_id] = []
  15. self.active_connections[order_id].append({"ws": websocket, "role": role})
  16. print(f"DEBUG: Chat WS connected for Order #{order_id} (Role: {role}). Total connections: {len(self.active_connections[order_id])}")
  17. await self.broadcast_presence(order_id)
  18. def disconnect(self, websocket: WebSocket, order_id: int):
  19. if order_id in self.active_connections:
  20. self.active_connections[order_id] = [c for c in self.active_connections[order_id] if c["ws"] != websocket]
  21. print(f"DEBUG: Chat WS disconnected for Order #{order_id}. Remaining: {len(self.active_connections[order_id])}")
  22. if not self.active_connections[order_id]:
  23. del self.active_connections[order_id]
  24. else:
  25. import asyncio
  26. try:
  27. asyncio.create_task(self.broadcast_presence(order_id))
  28. except Exception:
  29. pass
  30. async def broadcast_presence(self, order_id: int):
  31. if order_id in self.active_connections:
  32. roles = [c["role"] for c in self.active_connections[order_id]]
  33. payload = json.dumps({"type": "presence", "online_roles": list(set(roles))})
  34. for connection in self.active_connections[order_id]:
  35. try:
  36. await connection["ws"].send_text(payload)
  37. except:
  38. pass
  39. async def broadcast_to_order(self, order_id: int, message: Any):
  40. if order_id in self.active_connections:
  41. # We must serialize datetime to JSON string
  42. if isinstance(message, dict) and 'created_at' in message:
  43. if isinstance(message['created_at'], datetime.datetime):
  44. message['created_at'] = message['created_at'].isoformat()
  45. if "type" not in message:
  46. message["type"] = "message"
  47. payload = json.dumps(message)
  48. print(f"DEBUG: Broadcasting to Order #{order_id} to {len(self.active_connections[order_id])} receivers")
  49. for connection in self.active_connections[order_id]:
  50. try:
  51. await connection["ws"].send_text(payload)
  52. except Exception as e:
  53. print(f"DEBUG: Failed to send WS message to a connection: {e}")
  54. else:
  55. print(f"DEBUG: Attempted broadcast to Order #{order_id} but NO active connections found")
  56. manager = ChatConnectionManager()