1. 调整导入顺序和移除多余空行 2. 重构IRC NAMES命令的成员解析逻辑,正确剥离所有前缀 3. 更新配置schema:修改默认消息块大小为350字节,新增disableBlockStreaming配置项 4. 完善CTCP处理:新增ACTION支持,提取CTCP动作文本 5. 新增IRC线程上下文模拟器类 6. 新增SRV记录解析支持,自动解析IRC服务器域名 7. 新增多种IRC通知处理:ACCOUNT、AWAY、INVITE、CAP 8. 重构消息发送逻辑,添加熔断器和重试机制 9. 重写流式消息合并逻辑,新增智能合并缓冲 10. 扩展IRC CAP支持,新增多个常用扩展能力 11. 修复配置读取逻辑,适配新的配置结构
130 lines
4.6 KiB
Python
130 lines
4.6 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import warnings
|
|
from typing import Any
|
|
|
|
from yuxi.utils.logging_config import logger
|
|
|
|
from .accounts import get_account_config, list_enabled_irc_accounts, list_irc_account_ids
|
|
|
|
|
|
class IRCGateway:
|
|
"""
|
|
DEPRECATED: Use ChannelManager with ``irc:<account_id>`` channel_id suffix instead.
|
|
|
|
IRCGateway implements multi-account IRC management independently of
|
|
ChannelManager, creating a parallel code path that may result in
|
|
duplicate connections to the same IRC server. This class is kept for
|
|
backward compatibility but will be removed in a future version.
|
|
"""
|
|
|
|
def __init__(self, config: dict[str, Any]):
|
|
warnings.warn(
|
|
"IRCGateway is deprecated. Use ChannelManager with 'irc:<account_id>' "
|
|
"channel IDs for multi-account support.",
|
|
DeprecationWarning,
|
|
stacklevel=2,
|
|
)
|
|
self._config = config
|
|
self._adapters: dict[str, Any] = {}
|
|
self._tasks: dict[str, asyncio.Task] = {}
|
|
self._running = False
|
|
self._reload_lock = asyncio.Lock()
|
|
|
|
@property
|
|
def account_ids(self) -> list[str]:
|
|
return list(self._adapters.keys())
|
|
|
|
@property
|
|
def is_running(self) -> bool:
|
|
return self._running
|
|
|
|
async def start_all(self) -> None:
|
|
self._running = True
|
|
accounts = list_enabled_irc_accounts(self._config)
|
|
|
|
if not accounts:
|
|
logger.info("IRC gateway: no accounts configured, using single-adapter mode")
|
|
return
|
|
|
|
for account_config in accounts:
|
|
account_id = account_config.get("_account_id", "default")
|
|
await self._start_account(account_id, account_config)
|
|
|
|
logger.info(f"IRC gateway started with {len(self._adapters)} accounts")
|
|
|
|
async def start_account(self, account_id: str) -> None:
|
|
account_config = get_account_config(self._config, account_id)
|
|
if account_config is None:
|
|
raise ValueError(f"IRC account '{account_id}' not found or disabled")
|
|
await self._start_account(account_id, account_config)
|
|
|
|
async def stop_account(self, account_id: str) -> None:
|
|
adapter = self._adapters.pop(account_id, None)
|
|
if adapter is None:
|
|
return
|
|
try:
|
|
await adapter.disconnect()
|
|
except Exception as e:
|
|
logger.warning(f"IRC gateway: error stopping account '{account_id}': {e}")
|
|
|
|
task = self._tasks.pop(account_id, None)
|
|
if task and not task.done():
|
|
task.cancel()
|
|
logger.info(f"IRC gateway: stopped account '{account_id}'")
|
|
|
|
async def stop_all(self) -> None:
|
|
self._running = False
|
|
for account_id in list(self._adapters.keys()):
|
|
await self.stop_account(account_id)
|
|
logger.info("IRC gateway: all accounts stopped")
|
|
|
|
async def reload(self, new_config: dict[str, Any]) -> None:
|
|
async with self._reload_lock:
|
|
self._config = new_config
|
|
new_ids = set(list_irc_account_ids(new_config))
|
|
old_ids = set(self._adapters.keys())
|
|
|
|
for removed_id in old_ids - new_ids:
|
|
await self.stop_account(removed_id)
|
|
|
|
for existing_id in old_ids & new_ids:
|
|
account_config = get_account_config(new_config, existing_id)
|
|
if account_config:
|
|
logger.info(f"IRC gateway: reloading account '{existing_id}'")
|
|
await self.stop_account(existing_id)
|
|
await self._start_account(existing_id, account_config)
|
|
|
|
for added_id in new_ids - old_ids:
|
|
account_config = get_account_config(new_config, added_id)
|
|
if account_config:
|
|
await self._start_account(added_id, account_config)
|
|
|
|
logger.info(f"IRC gateway: config reloaded ({len(self._adapters)} accounts)")
|
|
|
|
async def _start_account(self, account_id: str, account_config: dict[str, Any]) -> None:
|
|
if account_id in self._adapters:
|
|
logger.warning(f"IRC gateway: account '{account_id}' already running")
|
|
return
|
|
|
|
from .adapter import IRCAdapter
|
|
|
|
adapter = IRCAdapter(account_config)
|
|
self._adapters[account_id] = adapter
|
|
|
|
try:
|
|
await adapter.connect()
|
|
except Exception as e:
|
|
logger.error(f"IRC gateway: failed to start account '{account_id}': {e}")
|
|
self._adapters.pop(account_id, None)
|
|
raise
|
|
|
|
logger.info(f"IRC gateway: account '{account_id}' connected")
|
|
|
|
def get_adapter(self, account_id: str):
|
|
return self._adapters.get(account_id)
|
|
|
|
def get_all_adapters(self) -> dict[str, Any]:
|
|
return dict(self._adapters)
|