""" Matrix Gateway Client for City Service """ import os import httpx import logging from typing import Optional, Tuple, List, Dict, Any logger = logging.getLogger(__name__) MATRIX_GATEWAY_URL = os.getenv("MATRIX_GATEWAY_URL", "http://daarion-matrix-gateway:7025") async def create_matrix_room(slug: str, name: str, visibility: str = "public", topic: str = None) -> Tuple[Optional[str], Optional[str]]: """ Create a Matrix room via Matrix Gateway. Returns: Tuple of (matrix_room_id, matrix_room_alias) or (None, None) on failure """ async with httpx.AsyncClient(timeout=30.0) as client: try: payload = { "slug": slug, "name": name, "visibility": visibility } if topic: payload["topic"] = topic response = await client.post( f"{MATRIX_GATEWAY_URL}/internal/matrix/rooms/create", json=payload ) if response.status_code == 200: data = response.json() logger.info(f"Matrix room created: {data['matrix_room_id']}") return data["matrix_room_id"], data["matrix_room_alias"] else: logger.error(f"Failed to create Matrix room: {response.text}") return None, None except httpx.RequestError as e: logger.error(f"Matrix Gateway request error: {e}") return None, None except Exception as e: logger.error(f"Matrix room creation error: {e}") return None, None async def find_matrix_room_by_alias(alias: str) -> Tuple[Optional[str], Optional[str]]: """ Find a Matrix room by alias via Matrix Gateway. Returns: Tuple of (matrix_room_id, matrix_room_alias) or (None, None) if not found """ async with httpx.AsyncClient(timeout=10.0) as client: try: response = await client.get( f"{MATRIX_GATEWAY_URL}/internal/matrix/rooms/find-by-alias", params={"alias": alias} ) if response.status_code == 200: data = response.json() return data["matrix_room_id"], data["matrix_room_alias"] elif response.status_code == 404: return None, None else: logger.error(f"Failed to find Matrix room: {response.text}") return None, None except httpx.RequestError as e: logger.error(f"Matrix Gateway request error: {e}") return None, None async def join_user_to_room(room_id: str, user_id: str) -> bool: """ Join a Matrix user to a room. Args: room_id: Matrix room ID (!abc:daarion.space) user_id: Matrix user ID (@user:daarion.space) Returns: True if joined successfully, False otherwise """ async with httpx.AsyncClient(timeout=30.0) as client: try: response = await client.post( f"{MATRIX_GATEWAY_URL}/internal/matrix/room/join", json={ "room_id": room_id, "user_id": user_id } ) if response.status_code == 200: data = response.json() logger.info(f"User {user_id} joined room {room_id}") return data.get("ok", False) else: logger.error(f"Failed to join room: {response.text}") return False except httpx.RequestError as e: logger.error(f"Matrix Gateway request error: {e}") return False async def send_message_to_room(room_id: str, body: str, sender: str = None) -> Optional[str]: """ Send a message to a Matrix room. Args: room_id: Matrix room ID body: Message text sender: Optional sender Matrix user ID Returns: Event ID if sent successfully, None otherwise """ async with httpx.AsyncClient(timeout=30.0) as client: try: payload = { "room_id": room_id, "body": body, "sender": sender or "@daarion-bot:daarion.space" } response = await client.post( f"{MATRIX_GATEWAY_URL}/internal/matrix/message/send", json=payload ) if response.status_code == 200: data = response.json() logger.info(f"Message sent to {room_id}: {data.get('event_id')}") return data.get("event_id") else: logger.error(f"Failed to send message: {response.text}") return None except httpx.RequestError as e: logger.error(f"Matrix Gateway request error: {e}") return None async def get_room_messages(room_id: str, limit: int = 50) -> List[Dict[str, Any]]: """ Get recent messages from a Matrix room. Args: room_id: Matrix room ID limit: Max number of messages to fetch Returns: List of message dicts with event_id, sender, body, timestamp """ async with httpx.AsyncClient(timeout=30.0) as client: try: response = await client.get( f"{MATRIX_GATEWAY_URL}/internal/matrix/rooms/{room_id}/messages", params={"limit": limit} ) if response.status_code == 200: data = response.json() return data.get("messages", []) else: logger.error(f"Failed to get messages: {response.text}") return [] except httpx.RequestError as e: logger.error(f"Matrix Gateway request error: {e}") return [] async def check_matrix_gateway_health() -> bool: """Check if Matrix Gateway is available.""" async with httpx.AsyncClient(timeout=5.0) as client: try: response = await client.get(f"{MATRIX_GATEWAY_URL}/healthz") return response.status_code == 200 except Exception: return False async def ensure_room_has_matrix(room_slug: str, room_name: str, visibility: str = "public") -> Tuple[Optional[str], Optional[str]]: """ Ensure a room has a Matrix room ID. Creates one if it doesn't exist. Returns: Tuple of (matrix_room_id, matrix_room_alias) or (None, None) on failure """ # First try to find existing room alias = f"#city_{room_slug}:daarion.space" matrix_room_id, matrix_room_alias = await find_matrix_room_by_alias(alias) if matrix_room_id: return matrix_room_id, matrix_room_alias # Create new room return await create_matrix_room(room_slug, room_name, visibility)