新增Twitch IRC协议相关的全套实现,包括: 1. 基础工具类:令牌处理、消息格式化、速率限制、消息去重 2. 核心适配器组件:IRC解析器、消息归一化、外发消息处理 3. API客户端:Helix API封装、认证提供者 4. 配置与部署:配置校验、设置向导 5. 辅助功能:配对管理、健康检查、目标解析等
90 lines
2.7 KiB
Python
90 lines
2.7 KiB
Python
from __future__ import annotations
|
|
|
|
import time
|
|
from typing import Any
|
|
|
|
from yuxi.channels.models import HealthStatus
|
|
|
|
from .helix import HelixClient
|
|
|
|
|
|
async def health_check(config: dict[str, Any], timeout_ms: int = 10000) -> HealthStatus:
|
|
start = time.monotonic()
|
|
issues: list[str] = []
|
|
|
|
token = config.get("access_token", "")
|
|
client_id = config.get("client_id", "")
|
|
|
|
if not token or not client_id:
|
|
return HealthStatus(
|
|
status="unhealthy",
|
|
last_error="Missing client_id or access_token",
|
|
latency_ms=(time.monotonic() - start) * 1000,
|
|
)
|
|
|
|
helix = HelixClient(client_id, token)
|
|
try:
|
|
await helix.start()
|
|
user_info = await helix.validate_token()
|
|
if user_info is None:
|
|
issues.append("Token invalid or expired (401)")
|
|
except Exception as e:
|
|
issues.append(f"Helix API unreachable: {e}")
|
|
finally:
|
|
await helix.close()
|
|
|
|
latency_ms = (time.monotonic() - start) * 1000
|
|
probe_timeout_ms = config.get("probe_timeout_ms", timeout_ms)
|
|
if latency_ms > probe_timeout_ms:
|
|
issues.append(f"Probe timeout: {latency_ms:.0f}ms > {probe_timeout_ms}ms")
|
|
|
|
if issues:
|
|
return HealthStatus(
|
|
status="unhealthy",
|
|
last_error="; ".join(issues),
|
|
latency_ms=latency_ms,
|
|
metadata={"timeout_ms": probe_timeout_ms},
|
|
)
|
|
return HealthStatus(
|
|
status="healthy",
|
|
latency_ms=latency_ms,
|
|
metadata={"api": "helix", "timeout_ms": probe_timeout_ms},
|
|
)
|
|
|
|
|
|
async def validate_token(client_id: str, access_token: str) -> dict[str, Any] | None:
|
|
helix = HelixClient(client_id, access_token)
|
|
try:
|
|
await helix.start()
|
|
return await helix.validate_token()
|
|
finally:
|
|
await helix.close()
|
|
|
|
|
|
async def get_broadcaster_id(client_id: str, access_token: str, channel_name: str) -> str | None:
|
|
helix = HelixClient(client_id, access_token)
|
|
try:
|
|
await helix.start()
|
|
user = await helix.get_user_by_name(channel_name)
|
|
return user["id"] if user else None
|
|
finally:
|
|
await helix.close()
|
|
|
|
|
|
async def refresh_access_token(client_id: str, client_secret: str, refresh_token: str) -> dict[str, Any] | None:
|
|
helix = HelixClient(client_id, "")
|
|
try:
|
|
await helix.start()
|
|
return await helix.refresh_user_token(client_secret, refresh_token)
|
|
finally:
|
|
await helix.close()
|
|
|
|
|
|
async def get_app_access_token(client_id: str, client_secret: str) -> str | None:
|
|
helix = HelixClient(client_id, "")
|
|
try:
|
|
await helix.start()
|
|
return await helix.get_app_access_token(client_secret)
|
|
finally:
|
|
await helix.close()
|