ForcePilot/backend/package/yuxi/channels/adapters/irc/gateway.py
Kris 4e07292a81 refactor(irc): 整理导入并修复代码风格
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. 修复配置读取逻辑,适配新的配置结构
2026-05-13 16:10:40 +08:00

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)