新增IRC协议相关的全套工具模块,包括: - 核心协议解析与CTCP处理 - 消息发送缓存与文本 sanitize - 账号配置管理与运行时状态 - 命令处理与权限控制 - 服务发现与诊断工具 - 多账号网关与配置加载
93 lines
2.5 KiB
Python
93 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
import time
|
|
import uuid
|
|
from typing import Any
|
|
|
|
from yuxi.channels.models import (
|
|
ChannelIdentity,
|
|
ChannelMessage,
|
|
ChannelType,
|
|
ChatType,
|
|
EventType,
|
|
MentionsInfo,
|
|
MessageType,
|
|
)
|
|
|
|
|
|
def _parse_irc_time_tag(time_tag: str) -> int:
|
|
"""解析 IRCv3 server-time 标签为毫秒时间戳"""
|
|
import datetime
|
|
|
|
try:
|
|
ts_str = time_tag.replace("Z", "+00:00")
|
|
dt = datetime.datetime.fromisoformat(ts_str)
|
|
return int(dt.timestamp() * 1000)
|
|
except (ValueError, TypeError):
|
|
return int(time.time() * 1000)
|
|
|
|
|
|
def normalize_inbound(
|
|
raw: dict[str, Any],
|
|
channel_id: str,
|
|
channel_type: ChannelType,
|
|
nick: str,
|
|
) -> ChannelMessage | None:
|
|
sender_nick = raw.get("sender_nick", "unknown")
|
|
target = raw.get("target", "")
|
|
text = raw.get("text", "")
|
|
|
|
if not text or not text.strip():
|
|
return None
|
|
|
|
is_channel = target.startswith("#") or target.startswith("&")
|
|
|
|
chat_id = target if is_channel else f"dm_{sender_nick}"
|
|
chat_type = ChatType.GROUP if is_channel else ChatType.DIRECT
|
|
|
|
mentioned_user_ids: list[str] = []
|
|
is_bot_mentioned = _check_bot_mention(text, nick)
|
|
if is_channel:
|
|
for word in text.split():
|
|
if word.startswith("@"):
|
|
mentioned_user_ids.append(word[1:])
|
|
|
|
server_time = raw.get("time")
|
|
ts = _parse_irc_time_tag(server_time) if server_time else int(time.time() * 1000)
|
|
|
|
return ChannelMessage(
|
|
identity=ChannelIdentity(
|
|
channel_id=channel_id,
|
|
channel_type=channel_type,
|
|
channel_user_id=sender_nick,
|
|
channel_chat_id=chat_id,
|
|
channel_message_id=f"{sender_nick}:{ts}:{uuid.uuid4().hex[:8]}",
|
|
),
|
|
event_type=EventType.MESSAGE_RECEIVED,
|
|
message_type=MessageType.TEXT,
|
|
chat_type=chat_type,
|
|
content=text,
|
|
mentions=MentionsInfo(
|
|
mentioned_user_ids=mentioned_user_ids,
|
|
is_bot_mentioned=is_bot_mentioned,
|
|
),
|
|
metadata={
|
|
"irc_target": target,
|
|
"is_channel": is_channel,
|
|
"account": raw.get("account"),
|
|
},
|
|
)
|
|
|
|
|
|
def resolve_chat_id(target: str, sender_nick: str) -> str:
|
|
from .session import resolve_chat_id as _resolve
|
|
|
|
return _resolve(target, sender_nick)
|
|
|
|
|
|
def _check_bot_mention(text: str, nick: str) -> bool:
|
|
"""Check if bot nick is mentioned with word boundary awareness."""
|
|
pattern = rf"\b{re.escape(nick)}\b[:,]?"
|
|
return bool(re.search(pattern, text))
|