新增IRC协议相关的全套工具模块,包括: - 核心协议解析与CTCP处理 - 消息发送缓存与文本 sanitize - 账号配置管理与运行时状态 - 命令处理与权限控制 - 服务发现与诊断工具 - 多账号网关与配置加载
132 lines
3.6 KiB
Python
132 lines
3.6 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
from copy import deepcopy
|
|
from typing import Any
|
|
|
|
|
|
def resolve_merged_account_config(
|
|
base_config: dict[str, Any],
|
|
account_config: dict[str, Any],
|
|
) -> dict[str, Any]:
|
|
merged = deepcopy(base_config)
|
|
_deep_merge(merged, account_config)
|
|
return merged
|
|
|
|
|
|
def _deep_merge(base: dict, override: dict) -> None:
|
|
for key, value in override.items():
|
|
if key in base and isinstance(base[key], dict) and isinstance(value, dict):
|
|
_deep_merge(base[key], value)
|
|
else:
|
|
base[key] = value
|
|
|
|
|
|
def list_irc_account_ids(config: dict[str, Any]) -> list[str]:
|
|
accounts = config.get("accounts", {})
|
|
if not isinstance(accounts, dict):
|
|
return []
|
|
return list(accounts.keys())
|
|
|
|
|
|
def list_enabled_irc_accounts(config: dict[str, Any]) -> list[dict[str, Any]]:
|
|
accounts = config.get("accounts", {})
|
|
if not isinstance(accounts, dict):
|
|
return []
|
|
|
|
result: list[dict[str, Any]] = []
|
|
base_config = _extract_base_config(config)
|
|
|
|
for account_id, account_config in accounts.items():
|
|
if not isinstance(account_config, dict):
|
|
continue
|
|
if account_config.get("enabled") is False:
|
|
continue
|
|
|
|
merged = resolve_merged_account_config(base_config, account_config)
|
|
merged["_account_id"] = account_id
|
|
result.append(merged)
|
|
|
|
return result
|
|
|
|
|
|
def _extract_base_config(config: dict[str, Any]) -> dict[str, Any]:
|
|
top_level_keys = {
|
|
"server",
|
|
"port",
|
|
"use_tls",
|
|
"nick",
|
|
"username",
|
|
"realname",
|
|
"password",
|
|
"sasl_username",
|
|
"sasl_password",
|
|
"use_sasl",
|
|
"nickserv_service",
|
|
"nickserv_password",
|
|
"nickserv_password_file",
|
|
"nickserv_register",
|
|
"nickserv_register_email",
|
|
"nickserv_enabled",
|
|
"auto_join_channels",
|
|
"nick_recovery",
|
|
"dm_policy",
|
|
"group_policy",
|
|
"allowFrom",
|
|
"groupAllowFrom",
|
|
"groups",
|
|
"dangerouslyAllowNameMatching",
|
|
"groupAllowFromFallbackToAllowFrom",
|
|
"connect_timeout",
|
|
"probe_timeout",
|
|
"chunker_mode",
|
|
"commands",
|
|
"reply_enabled",
|
|
"markdown",
|
|
"server_password",
|
|
"server_password_file",
|
|
}
|
|
return {k: v for k, v in config.items() if k in top_level_keys and v}
|
|
|
|
|
|
def get_account_config(
|
|
config: dict[str, Any],
|
|
account_id: str,
|
|
) -> dict[str, Any] | None:
|
|
accounts = config.get("accounts", {})
|
|
if not isinstance(accounts, dict):
|
|
return None
|
|
account_config = accounts.get(account_id)
|
|
if not isinstance(account_config, dict):
|
|
return None
|
|
if account_config.get("enabled") is False:
|
|
return None
|
|
|
|
base_config = _extract_base_config(config)
|
|
merged = resolve_merged_account_config(base_config, account_config)
|
|
merged["_account_id"] = account_id
|
|
return merged
|
|
|
|
|
|
def is_configured(config: dict[str, Any]) -> bool:
|
|
host = config.get("server", "") or os.environ.get("IRC_HOST", "")
|
|
nick = config.get("nick", "") or os.environ.get("IRC_NICK", "")
|
|
return bool(host and nick)
|
|
|
|
|
|
def has_configured_state() -> bool:
|
|
return bool(os.environ.get("IRC_HOST", "") and os.environ.get("IRC_NICK", ""))
|
|
|
|
|
|
def resolve_default_irc_account_id(
|
|
config: dict[str, Any],
|
|
default: str = "default",
|
|
) -> str:
|
|
accounts = config.get("accounts", {})
|
|
if isinstance(accounts, dict) and default in accounts:
|
|
return default
|
|
account_ids = list_irc_account_ids(config)
|
|
if account_ids:
|
|
return account_ids[0]
|
|
return default
|