import asyncio import logging import time from yuxi.channel.extensions.twitch.config import TwitchAccountConfig from yuxi.channel.extensions.twitch.token import denormalize_token logger = logging.getLogger(__name__) async def probe_twitch(account: TwitchAccountConfig, timeout_ms: int = 10000) -> dict: start = time.time() if not account.access_token or not account.username: return { "ok": False, "error": "missing credentials (access_token, username)", "username": account.username, "elapsed_ms": int((time.time() - start) * 1000), } token = denormalize_token(account.access_token) from twitchio import Client client = Client(token=token) try: connected = asyncio.Event() @client.event() async def event_ready(): connected.set() connect_task = asyncio.create_task(client.start()) try: await asyncio.wait_for(connected.wait(), timeout=timeout_ms / 1000) elapsed = int((time.time() - start) * 1000) return { "ok": True, "connected": True, "username": account.username, "channel": account.channel, "elapsed_ms": elapsed, } except TimeoutError: return { "ok": False, "error": f"timeout after {timeout_ms}ms", "username": account.username, "channel": account.channel, "elapsed_ms": timeout_ms, } finally: connect_task.cancel() try: await connect_task except asyncio.CancelledError: pass except Exception as e: return { "ok": False, "error": str(e), "username": account.username, "channel": account.channel, "elapsed_ms": int((time.time() - start) * 1000), } finally: try: await client.close() except Exception: pass