新增IRC协议相关的全套工具模块,包括: - 核心协议解析与CTCP处理 - 消息发送缓存与文本 sanitize - 账号配置管理与运行时状态 - 命令处理与权限控制 - 服务发现与诊断工具 - 多账号网关与配置加载
128 lines
4.1 KiB
Python
128 lines
4.1 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Any
|
|
|
|
|
|
@dataclass
|
|
class DirectoryUser:
|
|
id: str
|
|
display_name: str
|
|
source: str = ""
|
|
metadata: dict[str, Any] = field(default_factory=dict)
|
|
|
|
|
|
@dataclass
|
|
class DirectoryGroup:
|
|
id: str
|
|
display_name: str
|
|
member_count: int = 0
|
|
source: str = ""
|
|
metadata: dict[str, Any] = field(default_factory=dict)
|
|
|
|
|
|
def list_users(config: dict[str, Any]) -> list[DirectoryUser]:
|
|
users: dict[str, DirectoryUser] = {}
|
|
allow_from = config.get("allowFrom", [])
|
|
if isinstance(allow_from, list):
|
|
for entry in allow_from:
|
|
nick = _extract_nick_from_entry(entry)
|
|
if nick and nick not in users:
|
|
users[nick] = DirectoryUser(
|
|
id=nick,
|
|
display_name=nick,
|
|
source="allowFrom",
|
|
)
|
|
|
|
group_allow_from = config.get("groupAllowFrom", [])
|
|
if isinstance(group_allow_from, list):
|
|
for entry in group_allow_from:
|
|
nick = _extract_nick_from_entry(entry)
|
|
if nick and nick not in users:
|
|
users[nick] = DirectoryUser(
|
|
id=nick,
|
|
display_name=nick,
|
|
source="groupAllowFrom",
|
|
)
|
|
|
|
groups = config.get("groups", {})
|
|
if isinstance(groups, dict):
|
|
for _channel_name, channel_config in groups.items():
|
|
if isinstance(channel_config, dict):
|
|
channel_allow = channel_config.get("allowFrom", [])
|
|
if isinstance(channel_allow, list):
|
|
for entry in channel_allow:
|
|
nick = _extract_nick_from_entry(entry)
|
|
if nick and nick not in users:
|
|
users[nick] = DirectoryUser(
|
|
id=nick,
|
|
display_name=nick,
|
|
source="groups.allowFrom",
|
|
)
|
|
|
|
return sorted(users.values(), key=lambda u: u.display_name.lower())
|
|
|
|
|
|
def list_groups(config: dict[str, Any]) -> list[DirectoryGroup]:
|
|
group_list: list[DirectoryGroup] = []
|
|
|
|
channels = _resolve_channel_list(config)
|
|
groups = config.get("groups", {})
|
|
if isinstance(groups, dict):
|
|
group_config_keys = set(groups.keys())
|
|
|
|
for channel in channels:
|
|
channel_str = channel if isinstance(channel, str) else channel.get("name", "")
|
|
if channel_str:
|
|
metadata: dict[str, Any] = {}
|
|
if channel_str in group_config_keys:
|
|
ch_config = groups[channel_str]
|
|
if isinstance(ch_config, dict):
|
|
metadata = {
|
|
"skills": ch_config.get("skills"),
|
|
"systemPrompt": ch_config.get("systemPrompt"),
|
|
"enabled": ch_config.get("enabled", True),
|
|
}
|
|
group_list.append(
|
|
DirectoryGroup(
|
|
id=channel_str,
|
|
display_name=channel_str,
|
|
source="channels",
|
|
metadata=metadata,
|
|
)
|
|
)
|
|
|
|
for key in group_config_keys:
|
|
if key == "*" or key.startswith("#") or key.startswith("&"):
|
|
continue
|
|
group_list.append(
|
|
DirectoryGroup(
|
|
id=key,
|
|
display_name=key,
|
|
source="groups",
|
|
)
|
|
)
|
|
|
|
return group_list
|
|
|
|
|
|
def _resolve_channel_list(config: dict[str, Any]) -> list:
|
|
import os
|
|
|
|
channels = config.get("auto_join_channels", [])
|
|
if not channels:
|
|
channels_env = os.environ.get("IRC_CHANNELS", "")
|
|
if channels_env:
|
|
channels = [ch.strip() for ch in channels_env.split(",") if ch.strip()]
|
|
return channels
|
|
|
|
|
|
def _extract_nick_from_entry(entry: str) -> str:
|
|
if not entry or entry == "*":
|
|
return ""
|
|
if "!" in entry:
|
|
return entry.split("!", 1)[0]
|
|
if "@" in entry:
|
|
return entry.split("@", 1)[0]
|
|
return entry
|