import time import logging from yuxi.channel.extensions.intercom.client import IntercomClient from yuxi.channel.extensions.intercom.types import IntercomProbeResult from yuxi.channel.protocols import ChannelAccountSnapshot, ChannelStatusIssue logger = logging.getLogger(__name__) class IntercomStatus: default_runtime: ChannelAccountSnapshot | None = None async def probe(self, account: dict | None = None) -> bool: if not account: return False access_token = account.get("access_token", "") if not access_token: return False probe_result = await self._probe_intercom(access_token) return probe_result.ok async def _probe_intercom(self, access_token: str, timeout: float = 10.0) -> IntercomProbeResult: client = IntercomClient(access_token, timeout=timeout) start = time.monotonic() try: me = await client.get_me() latency_ms = (time.monotonic() - start) * 1000 return IntercomProbeResult( ok=bool(me.get("id")), admin_id=str(me.get("id", "")), app_id=str(me.get("app", {}).get("id_code", "")), name=me.get("name", ""), email=me.get("email", ""), latency_ms=latency_ms, ) except Exception as e: latency_ms = (time.monotonic() - start) * 1000 return IntercomProbeResult(ok=False, error=str(e), latency_ms=latency_ms) finally: await client.close() def build_summary(self, snapshot: object) -> dict: return { "channel": "intercom", "account_id": getattr(snapshot, "account_id", ""), "status": getattr(snapshot, "status_state", "unknown"), } def build_channel_summary( self, account: dict, config: dict, default_account_id: str, snapshot: ChannelAccountSnapshot, ) -> dict: account_id = account.get("account_id", "") return { "channel": "intercom", "account_id": account_id, "is_default": account_id == default_account_id, "configured": snapshot.configured, "enabled": snapshot.enabled, "connected": snapshot.connected, "running": snapshot.running, "status": snapshot.status_state, "health_state": snapshot.health_state, "dm_policy": snapshot.dm_policy, "last_error": snapshot.last_error, "probe": snapshot.probe, } def build_account_snapshot( self, account: dict, config: dict, runtime: ChannelAccountSnapshot | None = None, probe: object | None = None, audit: object | None = None, ) -> ChannelAccountSnapshot: from yuxi.channel.extensions.intercom.config import IntercomConfigAdapter adapter = IntercomConfigAdapter() account_id = account.get("account_id", "") configured = adapter.is_configured(account) enabled = adapter.is_enabled(account, config) status_state = self.resolve_account_state(account, config, configured, enabled) return ChannelAccountSnapshot( account_id=account_id, enabled=enabled, configured=configured, status_state=status_state, dm_policy=account.get("dm_policy", "open"), allow_from=account.get("allow_from", []), probe=probe, audit=audit, ) def format_capabilities_probe(self, probe: object) -> list[dict]: if probe is None: return [] return [ { "label": "Intercom 连接", "ok": getattr(probe, "ok", False), "detail": f"{getattr(probe, 'name', '')} / {getattr(probe, 'email', '')}", "latency_ms": getattr(probe, "latency_ms", None), } ] async def audit_account( self, account: dict, timeout_ms: int, config: dict, probe: object | None = None, ) -> object: access_token = account.get("access_token", "") if not access_token: return {"ok": False, "error": "No access token configured"} probe_result = await self._probe_intercom(access_token) return { "ok": probe_result.ok, "admin_id": probe_result.admin_id, "app_id": probe_result.app_id, "name": probe_result.name, "email": probe_result.email, "latency_ms": probe_result.latency_ms, "error": probe_result.error, } async def build_capabilities_diagnostics( self, account: dict, timeout_ms: int, config: dict, probe: object | None = None, audit: object | None = None, target: str | None = None, ) -> dict | None: return { "channel": "intercom", "probe": self.format_capabilities_probe(probe), "audit": audit, } def log_self_id( self, account: dict, config: dict, runtime: object, include_channel_prefix: bool = False, ) -> None: prefix = "Intercom " if include_channel_prefix else "" account_id = account.get("account_id", "default") logger.info("%sBot account loaded: id=%s", prefix, account_id) def resolve_account_state( self, account: dict, config: dict, configured: bool, enabled: bool, ) -> str: if not configured: return "unconfigured" if not enabled: return "disabled" return "enabled" def collect_status_issues(self, accounts: list[ChannelAccountSnapshot]) -> list[ChannelStatusIssue]: issues: list[ChannelStatusIssue] = [] for snapshot in accounts: if snapshot.status_state == "unconfigured": issues.append( ChannelStatusIssue( channel="intercom", account_id=snapshot.account_id, kind="unconfigured", message=f"Intercom 账户 {snapshot.account_id} 未配置凭证", fix="在管理面板中配置 Intercom Access Token", ) ) return issues