新增IRC协议相关的全套工具模块,包括: - 核心协议解析与CTCP处理 - 消息发送缓存与文本 sanitize - 账号配置管理与运行时状态 - 命令处理与权限控制 - 服务发现与诊断工具 - 多账号网关与配置加载
114 lines
4.0 KiB
Python
114 lines
4.0 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
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:
|
|
def __init__(self, config: dict[str, Any]):
|
|
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)
|