新增 Tlon 渠道扩展,支持在 Yuxi 平台中集成 Tlon/Urbit 去中心化通讯平台。 包含以下功能模块: - tlon_api: Tlon API 客户端封装 - config: 渠道配置管理 - gateway: SSE/WebSocket 网关接入 - sse_client: SSE 客户端 - outbound: 外发消息管理 - send: 消息发送 - security: 安全校验 - auth: 认证管理 - monitor: 渠道状态监控 - status: 会话状态管理 - session: 会话管理 - approval: 审批流程 - channel_mgmt: 频道管理 - channel_ops: 频道操作 - contacts: 联系人管理 - discovery: 服务发现 - doctor: 健康诊断 - expose: 服务暴露 - gallery: 图库管理 - history: 历史记录 - hooks: 钩子管理 - media: 媒体资源处理 - notebook: 笔记本功能 - settings_store: 设置存储 - setup: 初始化设置 - story: 故事功能 - targets: 目标管理 - cite_parser: 引用解析 - utils: 工具函数 - types: 类型定义
71 lines
2.2 KiB
Python
71 lines
2.2 KiB
Python
import asyncio
|
|
import logging
|
|
|
|
from yuxi.channel.extensions.twitch.client import client_manager_registry
|
|
from yuxi.channel.extensions.twitch.config import (
|
|
TwitchConfig,
|
|
get_account_config,
|
|
is_account_configured,
|
|
normalize_twitch_channel,
|
|
)
|
|
from yuxi.channel.extensions.twitch.markdown import chunk_text_for_twitch, strip_markdown_for_twitch
|
|
from yuxi.channel.extensions.twitch.types import TwitchSendResult
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def send_message_twitch_internal(
|
|
channel: str,
|
|
text: str,
|
|
cfg: TwitchConfig,
|
|
account_id: str = "default",
|
|
strip_markdown: bool = True,
|
|
reply_to_id: str | None = None,
|
|
) -> TwitchSendResult:
|
|
account = get_account_config(cfg, account_id)
|
|
if not is_account_configured(account):
|
|
return TwitchSendResult(ok=False, error=f"Account not found: {account_id}")
|
|
|
|
normalized_channel = normalize_twitch_channel(channel or account.channel)
|
|
|
|
if strip_markdown:
|
|
text = strip_markdown_for_twitch(text)
|
|
if not text:
|
|
return TwitchSendResult(ok=True, message_id="skipped")
|
|
|
|
manager = client_manager_registry.get(account_id)
|
|
if manager is None:
|
|
return TwitchSendResult(ok=False, error="Please start the Twitch gateway first")
|
|
|
|
return await manager.send_message(account, normalized_channel, text, reply_to_id=reply_to_id)
|
|
|
|
|
|
async def deliver_twitch_reply(
|
|
channel: str,
|
|
text: str,
|
|
cfg: TwitchConfig,
|
|
account_id: str = "default",
|
|
reply_to_id: str | None = None,
|
|
):
|
|
chunks = chunk_text_for_twitch(text, 500)
|
|
interval = (cfg.send_chunk_interval_ms / 1000) if cfg.send_chunk_interval_ms > 0 else 0
|
|
for i, chunk in enumerate(chunks):
|
|
if i > 0 and interval > 0:
|
|
await asyncio.sleep(interval)
|
|
result = await send_message_twitch_internal(
|
|
channel=channel,
|
|
text=chunk,
|
|
cfg=cfg,
|
|
account_id=account_id,
|
|
strip_markdown=False,
|
|
reply_to_id=reply_to_id,
|
|
)
|
|
if not result.ok:
|
|
logger.warning(
|
|
"Twitch send failed for chunk %d/%d: channel=%s error=%s",
|
|
i + 1,
|
|
len(chunks),
|
|
channel,
|
|
result.error,
|
|
)
|