ForcePilot/backend/package/yuxi/channels/adapters/irc/directory.py
Kris 2dd1a075f2 feat(irc): 实现完整的IRC适配器基础功能模块
新增IRC协议相关的全套工具模块,包括:
- 核心协议解析与CTCP处理
- 消息发送缓存与文本 sanitize
- 账号配置管理与运行时状态
- 命令处理与权限控制
- 服务发现与诊断工具
- 多账号网关与配置加载
2026-05-12 00:45:10 +08:00

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