新增 IRC 渠道的完整扩展实现,包括客户端连接管理、消息收发与流式处理、安全策略与配对验证、消息去重与规范化、状态监控与健康探测、配置模型与账户管理、错误处理等模块。
78 lines
2.1 KiB
Python
78 lines
2.1 KiB
Python
import asyncio
|
|
import logging
|
|
import time
|
|
import uuid
|
|
|
|
from yuxi.channel.extensions.irc.client import (
|
|
connect_irc_client,
|
|
graceful_disconnect,
|
|
send_privmsg,
|
|
)
|
|
from yuxi.channel.extensions.irc.normalize import normalize_irc_target
|
|
from yuxi.channel.extensions.irc.protocol import sanitize_irc_text, split_irc_text
|
|
from yuxi.channel.extensions.irc.types import ResolvedIrcAccount, SendIrcResult
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
IRC_SEND_DELAY = 0.3
|
|
|
|
|
|
async def send_irc_message(
|
|
to: str,
|
|
text: str,
|
|
account: ResolvedIrcAccount,
|
|
reply_to_id: str | None = None,
|
|
client=None,
|
|
) -> SendIrcResult:
|
|
target = normalize_irc_target(to)
|
|
text = sanitize_irc_text(text)
|
|
|
|
if reply_to_id:
|
|
text = f"{text}\n\n[reply:{reply_to_id}]"
|
|
|
|
chunk_limit = 350
|
|
if account.config is not None:
|
|
chunk_limit = account.config.text_chunk_limit or 350
|
|
chunks = split_irc_text(text, chunk_limit)
|
|
|
|
writer = None
|
|
own_client = None
|
|
|
|
try:
|
|
if client is not None and client.writer is not None:
|
|
writer = client.writer
|
|
else:
|
|
own_client = await connect_irc_client(account, timeout=12.0)
|
|
await asyncio.sleep(1.5)
|
|
writer = own_client.writer
|
|
|
|
for i, chunk in enumerate(chunks):
|
|
if i > 0:
|
|
await asyncio.sleep(IRC_SEND_DELAY)
|
|
await send_privmsg(writer, target, chunk)
|
|
|
|
except Exception as e:
|
|
logger.error("Failed to send IRC message to %s: %s", target, e)
|
|
return SendIrcResult(ok=False, error=str(e), chunk_count=0)
|
|
finally:
|
|
if own_client is not None:
|
|
await graceful_disconnect(own_client)
|
|
|
|
return SendIrcResult(
|
|
ok=True,
|
|
message_id=str(uuid.uuid4()),
|
|
chunk_count=len(chunks),
|
|
)
|
|
|
|
|
|
async def send_irc_media(
|
|
to: str,
|
|
media_url: str,
|
|
media_type: str,
|
|
account: ResolvedIrcAccount,
|
|
reply_to_id: str | None = None,
|
|
client=None,
|
|
) -> SendIrcResult:
|
|
caption = f"[{media_type}]" if media_type else "[Attachment]"
|
|
text = f"{caption}\n{media_url}"
|
|
return await send_irc_message(to, text, account, reply_to_id=reply_to_id, client=client) |