import time import re from dataclasses import dataclass from yuxi.channel.extensions.bluebubbles.client import BlueBubblesClient @dataclass class ServerInfo: os_version: str | None = None macos_major: int | None = None private_api_enabled: bool = False imessage_logged_in: bool = False fetched_at: float = 0.0 _info_cache: dict[str, ServerInfo] = {} _CACHE_TTL = 600 async def probe_server(client: BlueBubblesClient) -> bool: return await client.ping() async def fetch_server_info(client: BlueBubblesClient) -> ServerInfo: now = time.time() cached = _info_cache.get(client.account_id) if cached and (now - cached.fetched_at) < _CACHE_TTL: return cached try: resp = await client.get("/api/v1/server/info") data = resp.json().get("data", resp.json()) info = ServerInfo( os_version=data.get("os_version"), macos_major=_parse_macos_major(data.get("os_version", "")), private_api_enabled=data.get("private_api", False), imessage_logged_in=data.get("imessage", {}).get("logged_in", False), fetched_at=now, ) except Exception: info = ServerInfo(fetched_at=now) _info_cache[client.account_id] = info return info def _parse_macos_major(os_version: str) -> int | None: m = re.search(r"macOS\s+(\d+)", os_version, re.IGNORECASE) return int(m.group(1)) if m else None def is_macos26_or_higher(info: ServerInfo) -> bool: return info.macos_major is not None and info.macos_major >= 26 async def get_private_api_status(client: BlueBubblesClient) -> bool: info = await fetch_server_info(client) return info.private_api_enabled def clear_probe_cache(): _info_cache.clear()