import httpx import logging from config import settings from security import get_redis logger = logging.getLogger("rocketchat") HEADERS: dict[str, str] = {} # Cache: session_id -> room_id _room_cache: dict[str, str] = {} def _get_headers() -> dict[str, str]: if not HEADERS: HEADERS.update({ "X-Auth-Token": settings.rocketchat_auth_token, "X-User-Id": settings.rocketchat_user_id, "Content-Type": "application/json", }) return HEADERS async def get_or_create_room(session_id: str, visitor_name: str = "Website Visitor") -> str | None: """Get or create a Rocket.Chat livechat room for a session.""" if not settings.rocketchat_auth_token: return None # Return cached room if session_id in _room_cache: return _room_cache[session_id] try: async with httpx.AsyncClient() as http: # Register visitor resp = await http.post( f"{settings.rocketchat_url}/api/v1/livechat/visitor", headers=_get_headers(), json={ "visitor": { "token": session_id, "name": visitor_name, } }, timeout=10, ) resp.raise_for_status() # Get or create room resp = await http.get( f"{settings.rocketchat_url}/api/v1/livechat/room", headers=_get_headers(), params={"token": session_id}, timeout=10, ) resp.raise_for_status() room_id = resp.json().get("room", {}).get("_id") if room_id: _room_cache[session_id] = room_id # Store reverse mapping for webhook delivery r = await get_redis() await r.set(f"chat:room_session:{room_id}", session_id, ex=86400) return room_id except Exception as e: logger.error(f"RC get_or_create_room error: {e}") return None async def send_message(room_id: str, session_id: str, text: str, sender: str = "bot") -> None: """Send a message to a Rocket.Chat livechat room.""" if not room_id or not settings.rocketchat_auth_token: return try: async with httpx.AsyncClient() as http: if sender == "visitor": # Visitor sends via livechat visitor API resp = await http.post( f"{settings.rocketchat_url}/api/v1/livechat/message", headers={"Content-Type": "application/json"}, json={ "token": session_id, "rid": room_id, "msg": text, }, timeout=10, ) if resp.status_code != 200: logger.error(f"RC visitor msg error: {resp.status_code} {resp.text}") else: # Bot/agent sends via authenticated API resp = await http.post( f"{settings.rocketchat_url}/api/v1/chat.sendMessage", headers=_get_headers(), json={ "message": { "rid": room_id, "msg": f"🤖 {text}", } }, timeout=10, ) if resp.status_code != 200: logger.error(f"RC bot msg error: {resp.status_code} {resp.text}") # Fallback: try livechat/message as agent resp2 = await http.post( f"{settings.rocketchat_url}/api/v1/livechat/message", headers=_get_headers(), json={ "token": session_id, "rid": room_id, "msg": f"🤖 {text}", }, timeout=10, ) if resp2.status_code != 200: logger.error(f"RC bot msg fallback error: {resp2.status_code} {resp2.text}") except Exception as e: logger.error(f"RC send_message exception: {e}")