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

85 lines
2.5 KiB
Python

from __future__ import annotations
_IRC_PROTOCOL_PREFIX = "irc:"
def resolve_chat_id(target: str, sender_nick: str) -> str:
is_channel = target.startswith("#") or target.startswith("&")
return target if is_channel else f"dm_{sender_nick}"
def resolve_channel_user_id(nick: str) -> str:
return nick
def resolve_thread_id(agent_id: str, chat_id: str) -> str:
is_channel = chat_id.startswith("#") or chat_id.startswith("&")
if is_channel:
channel_name = chat_id.lstrip("#&")
return f"agent:{agent_id}:irc:channel:{channel_name}"
dm_nick = chat_id.removeprefix("dm_")
return f"agent:{agent_id}:irc:dm:{dm_nick}"
def is_channel(target: str) -> bool:
return target.startswith("#") or target.startswith("&")
def normalize_irc_messaging_target(target: str) -> dict[str, str] | None:
"""Parse IRC messaging target with optional protocol prefix.
Handles:
- raw channel: ``#channel``, ``&channel``
- protocol prefix: ``irc:channel:#channel``, ``irc:user:nick``
- DM target: plain nick (no prefix)
Returns ``{"kind": "group"|"user", "target": "..."}`` or None.
"""
clean = target.strip()
if not clean:
return None
if clean.startswith(_IRC_PROTOCOL_PREFIX):
clean = clean.removeprefix(_IRC_PROTOCOL_PREFIX)
if clean.startswith("channel:"):
ch = clean.removeprefix("channel:")
if ch:
return {"kind": "group", "target": ch}
return None
if clean.startswith("user:"):
u = clean.removeprefix("user:")
if u:
return {"kind": "user", "target": u}
return None
return None
if clean.startswith("#") or clean.startswith("&"):
return {"kind": "group", "target": clean}
return {"kind": "user", "target": clean}
def resolve_targets(kind: str, target: str) -> dict[str, str] | None:
"""Resolve a target string based on its kind.
- ``kind="group"``: auto-prepend ``#`` if missing, reject bare nick.
- ``kind="user"``: reject channel targets (``#``/``&``).
Returns ``{"kind": "...", "target": "..."}`` or None on error.
"""
t = target.strip()
if not t:
return None
if kind == "group":
if not t.startswith("#") and not t.startswith("&"):
t = f"#{t}"
return {"kind": "group", "target": t}
if kind == "user":
if t.startswith("#") or t.startswith("&"):
return None
return {"kind": "user", "target": t}
return None