"""消息适配器 ABC — 所有渠道适配器的基类。 与 KBAdapter 的 authenticate()/close() 生命周期方法对齐: verify_signature() 对应 authenticate()。 """ from __future__ import annotations import abc from dataclasses import dataclass, field from enum import Enum from typing import Any class ChannelType(str, Enum): """支持的消息平台渠道。""" FEISHU = "feishu" DINGTALK = "dingtalk" WECOM = "wecom" SLACK = "slack" class MessageDirection(str, Enum): """消息流向。""" INBOUND = "inbound" OUTBOUND = "outbound" @dataclass class IncomingMessage: """标准化入站消息 — 所有渠道适配器将平台特定格式转换为此结构。""" channel: ChannelType platform_message_id: str user_id: str # 平台用户 ID chat_id: str # 群组/会话 ID content: str # 消息文本 raw_event: dict[str, Any] = field(default_factory=dict) # 原始事件 timestamp: str = "" @dataclass class OutgoingMessage: """标准化出站消息。""" channel: ChannelType chat_id: str content: str reply_to_message_id: str | None = None class MessageAdapter(abc.ABC): """消息适配器 ABC。 生命周期: __init__ → verify_signature() → receive_message() → send_message() → close() 子类必须实现全部抽象方法。verify_signature 失败时调用方应拒绝处理 (webhook 端点 fail-closed:Redis 不可用或签名校验失败均返回 503/401, 不可跳过 nonce dedup 直接处理消息)。 """ @abc.abstractmethod async def verify_signature(self, headers: dict[str, str], body: bytes) -> bool: """验证平台签名/token。返回 True 表示请求可信。""" @abc.abstractmethod async def receive_message(self, headers: dict[str, str], body: bytes) -> IncomingMessage: """从 webhook 请求中解析标准化消息。""" @abc.abstractmethod async def send_message(self, message: OutgoingMessage) -> bool: """向平台发送消息。返回 True 表示发送成功。""" @abc.abstractmethod async def close(self) -> None: """释放资源(HTTP 客户端、连接池等)。"""