# -*- coding: utf-8 -*- """ =================================== 平台适配器基类 =================================== 定义平台适配器的抽象基类,各平台必须继承此类。 """ from abc import ABC, abstractmethod from typing import Dict, Any, Optional, Tuple from bot.models import BotMessage, BotResponse, WebhookResponse class BotPlatform(ABC): """ 平台适配器抽象基类 负责: 1. 验证 Webhook 请求签名 2. 解析平台消息为统一格式 3. 将响应转换为平台格式 使用示例: class MyPlatform(BotPlatform): @property def platform_name(self) -> str: return "myplatform" def verify_request(self, headers, body) -> bool: # 验证签名逻辑 return True def parse_message(self, data) -> Optional[BotMessage]: # 解析消息逻辑 return BotMessage(...) def format_response(self, response, message) -> WebhookResponse: # 格式化响应逻辑 return WebhookResponse.success({"text": response.text}) """ @property @abstractmethod def platform_name(self) -> str: """ 平台标识名称 用于路由匹配和日志标识,如 "feishu", "dingtalk" """ pass @abstractmethod def verify_request(self, headers: Dict[str, str], body: bytes) -> bool: """ 验证请求签名 各平台有不同的签名验证机制,需要单独实现。 Args: headers: HTTP 请求头 body: 请求体原始字节 Returns: 签名是否有效 """ pass @abstractmethod def parse_message(self, data: Dict[str, Any]) -> Optional[BotMessage]: """ 解析平台消息为统一格式 将平台特定的消息格式转换为 BotMessage。 如果不是需要处理的消息类型(如事件回调),返回 None。 Args: data: 解析后的 JSON 数据 Returns: BotMessage 对象,或 None(不需要处理) """ pass @abstractmethod def format_response( self, response: BotResponse, message: BotMessage ) -> WebhookResponse: """ 将统一响应转换为平台格式 Args: response: 统一响应对象 message: 原始消息对象(用于获取回复目标等信息) Returns: WebhookResponse 对象 """ pass def handle_challenge(self, data: Dict[str, Any]) -> Optional[WebhookResponse]: """ 处理平台验证请求 部分平台在配置 Webhook 时会发送验证请求,需要返回特定响应。 子类可重写此方法。 Args: data: 请求数据 Returns: 验证响应,或 None(不是验证请求) """ return None def handle_webhook( self, headers: Dict[str, str], body: bytes, data: Dict[str, Any] ) -> Tuple[Optional[BotMessage], Optional[WebhookResponse]]: """ 处理 Webhook 请求 这是主入口方法,协调验证、解析等流程。 Args: headers: HTTP 请求头 body: 请求体原始字节 data: 解析后的 JSON 数据 Returns: (BotMessage, WebhookResponse) 元组 - 如果是验证请求:(None, challenge_response) - 如果是普通消息:(message, None) - 响应将在命令处理后生成 - 如果验证失败或无需处理:(None, error_response 或 None) """ # 1. 检查是否是验证请求 challenge_response = self.handle_challenge(data) if challenge_response: return None, challenge_response # 2. 验证请求签名 if not self.verify_request(headers, body): return None, WebhookResponse.error("Invalid signature", 403) # 3. 解析消息 message = self.parse_message(data) return message, None