from __future__ import annotations import base64 from typing import Any import httpx from yuxi.channels.models import DeliveryResult from yuxi.channels.adapters.wechat.format import truncate_text class BridgeClient: def __init__(self, http_client: httpx.AsyncClient, bridge_url: str): self._http_client = http_client self._bridge_url = bridge_url.rstrip("/") @property def bridge_url(self) -> str: return self._bridge_url async def health_check(self) -> bool: try: resp = await self._http_client.get( f"{self._bridge_url}/health", timeout=5.0, ) return resp.status_code == 200 except Exception: return False async def get_login_status(self) -> dict: try: resp = await self._http_client.get( f"{self._bridge_url}/login/status", timeout=5.0, ) return resp.json() except Exception: return {"logged_in": False} async def get_qr_code(self) -> dict: try: resp = await self._http_client.post( f"{self._bridge_url}/login/qr", timeout=10.0, ) return resp.json() except Exception as e: return {"error": str(e)} async def send_message(self, payload: dict[str, Any]) -> DeliveryResult: try: resp = await self._http_client.post( f"{self._bridge_url}/send", json=payload, timeout=10.0, ) data = resp.json() if data.get("success"): return DeliveryResult(success=True, message_id=data.get("msg_id")) else: return DeliveryResult( success=False, error=data.get("error", "Bridge send failed"), ) except httpx.HTTPError as e: return DeliveryResult(success=False, error=f"Bridge error: {e}") async def send_media_message(self, payload: dict[str, Any]) -> DeliveryResult: try: resp = await self._http_client.post( f"{self._bridge_url}/send", json=payload, timeout=30.0, ) data = resp.json() if data.get("success"): return DeliveryResult(success=True, message_id=data.get("msg_id")) else: return DeliveryResult( success=False, error=data.get("error", "Bridge media send failed"), ) except httpx.HTTPError as e: return DeliveryResult(success=False, error=f"Bridge media error: {e}") async def fetch_events(self) -> list[dict]: try: resp = await self._http_client.get( f"{self._bridge_url}/events", timeout=10.0, ) return resp.json() except Exception: return [] def build_bridge_text_payload( chat_id: str, content: str, is_group: bool = False, at_list: list[str] | None = None, ) -> dict[str, Any]: payload: dict[str, Any] = { "chat_id": chat_id, "content": truncate_text(content, 4096), "msg_type": 1, "is_group": is_group, } if at_list: payload["at_list"] = at_list return payload def build_bridge_image_payload( chat_id: str, image_data: bytes, is_group: bool = False, ) -> dict[str, Any]: return { "chat_id": chat_id, "msg_type": 3, "is_group": is_group, "image_data": base64.b64encode(image_data).decode("ascii"), } def build_bridge_file_payload( chat_id: str, file_data: bytes, filename: str, is_group: bool = False, ) -> dict[str, Any]: return { "chat_id": chat_id, "msg_type": 6, "is_group": is_group, "file_data": base64.b64encode(file_data).decode("ascii"), "filename": filename, "size": len(file_data), }