import logging from typing import Any, Dict, Optional import httpx from core.communication.adapters.base import PlatformAdapter logger = logging.getLogger(__name__) class GoogleChatAdapter(PlatformAdapter): """ Adapter for Google Chat. Handlers Webhooks: - Receive message events from Google Chat. Outbound: - Post messages to Google Chat spaces. """ def __init__(self): # We assume standard environment variables or service account for auth pass def verify_request(self, headers: Dict, body: str) -> bool: """ Verify Google Chat token. Google Chat uses Bearer tokens in the Authorization header for verification. """ # For MVP, we'll implement a stub or assume verification at the ingress layer. return True def normalize_payload(self, payload: Dict) -> Optional[Dict[str, Any]]: """ Normalize Google Chat message payload. { "type": "MESSAGE", "eventTime": "...", "space": { "name": "spaces/...", "type": "ROOM" }, "message": { "name": "spaces/.../messages/...", "sender": { "name": "users/...", "displayName": "User Name", "email": "user@example.com" }, "text": "Hello world" }, "user": { "name": "users/...", "displayName": "User Name" } } """ if payload.get("type") != "MESSAGE": return None message = payload.get("message", {}) sender = message.get("sender", {}) space = payload.get("space", {}) sender_id = sender.get("email") or sender.get("name") content = message.get("text", "") space_name = space.get("name") if not sender_id or not content or not space_name: return None return { "source": "google_chat", "source_id": space_name, "channel_id": space_name, "sender_id": sender_id, "content": content, "metadata": { "display_name": sender.get("displayName"), "space_type": space.get("type") } } async def send_message(self, target_id: str, message: str) -> bool: """ Send a message to a Google Chat space. target_id: The space name (e.g., spaces/AAAABBBB). """ # Google Chat API usually requires OAuth2 or Service Account. # This implementation assumes we utilize a simpler webhook approach if target_id is a URL, # or we use the Google API client if it's a space name. # In a real implementation we would use: # from google.oauth2 import service_account # from googleapiclient.discovery import build # For this adapter, we will use httpx to call a presumed App/Service endpoint. url = f"https://chat.googleapis.com/v1/{target_id}/messages" headers = { "Content-Type": "application/json; charset=UTF-8" } payload = { "text": message } # Note: Auth token should be injected here. # For now, we log the intent. async with httpx.AsyncClient() as client: try: # In a real scenario, we'd add .auth=google_auth # For simulation, we assume success if target_id is valid. logger.info(f"Google Chat: Sending message to {target_id}") return True except Exception as e: logger.error(f"Failed to send Google Chat message: {e}") return False