"""NapCat 通知事件编解码器。""" from __future__ import annotations from typing import Any, Dict, Optional from uuid import uuid4 import time from ...services import NapCatQueryService from ...types import NapCatPayload, NapCatPayloadDict from .enricher import NapCatNoticeEntityResolver from .helpers import build_payload_digest, resolve_actor_user_id from .meta_event_logger import NapCatMetaEventObserver from .renderer import NapCatNoticeTextRenderer class NapCatNoticeCodec: """NapCat QQ 通知事件编码器。""" def __init__(self, logger: Any, query_service: NapCatQueryService) -> None: """初始化通知事件编码器。 Args: logger: 插件日志对象。 query_service: QQ 查询服务。 """ self._entity_resolver = NapCatNoticeEntityResolver(query_service) self._meta_event_observer = NapCatMetaEventObserver(logger) self._renderer = NapCatNoticeTextRenderer() async def build_notice_message_dict(self, payload: NapCatPayload) -> Optional[NapCatPayloadDict]: """将 NapCat ``notice`` 事件转换为 Host 可接受的消息字典。 Args: payload: NapCat 推送的原始通知事件。 Returns: Optional[NapCatPayloadDict]: 成功时返回标准 ``MessageDict``;无法识别时返回 ``None``。 """ notice_type = str(payload.get("notice_type") or "").strip() if not notice_type: return None group_id = str(payload.get("group_id") or "").strip() user_id = resolve_actor_user_id(payload) self_id = str(payload.get("self_id") or "").strip() user_info = await self._entity_resolver.build_user_info(group_id=group_id, user_id=user_id) group_info = await self._entity_resolver.build_group_info(group_id) actor_name = user_info.get("user_nickname") or user_id or "系统" notice_text = self._renderer.build_notice_text(payload, actor_name) if not notice_text: return None additional_config: Dict[str, Any] = { "self_id": self_id, "napcat_notice_type": notice_type, "napcat_notice_sub_type": str(payload.get("sub_type") or "").strip(), "napcat_notice_payload": dict(payload), } if group_id: additional_config["platform_io_target_group_id"] = group_id elif user_id: additional_config["platform_io_target_user_id"] = user_id message_info: Dict[str, Any] = {"user_info": user_info, "additional_config": additional_config} if group_info is not None: message_info["group_info"] = group_info timestamp_seconds = payload.get("time") if not isinstance(timestamp_seconds, (int, float)): timestamp_seconds = time.time() return { "message_id": f"napcat-notice-{uuid4().hex}", "timestamp": str(float(timestamp_seconds)), "platform": "qq", "message_info": message_info, "raw_message": [{"type": "text", "data": notice_text}], "is_mentioned": False, "is_at": False, "is_emoji": False, "is_picture": False, "is_command": False, "is_notify": True, "session_id": "", "processed_plain_text": notice_text, "display_message": notice_text, } def build_notice_dedupe_key(self, payload: NapCatPayload) -> Optional[str]: """为 NapCat ``notice`` 事件构造稳定的技术性去重键。 Args: payload: NapCat 推送的原始通知事件。 Returns: Optional[str]: 若可以构造稳定去重键则返回该键,否则返回 ``None``。 """ external_message_id = str(payload.get("message_id") or "").strip() if external_message_id: return external_message_id notice_type = str(payload.get("notice_type") or "").strip() if not notice_type: return None sub_type = str(payload.get("sub_type") or "").strip() payload_digest = build_payload_digest(payload) suffix = f":{sub_type}" if sub_type else "" return f"notice:{notice_type}{suffix}:{payload_digest}" async def handle_meta_event(self, payload: NapCatPayload) -> None: """处理 ``meta_event`` 事件的日志与状态观测。 Args: payload: NapCat 推送的原始元事件。 """ await self._meta_event_observer.handle_meta_event(payload)