ForcePilot/backend/package/yuxi/channels/adapters/mattermost/slash_http.py
Kris 002d601d1b feat(mattermost): 实现完整的 Mattermost 适配器模块
新增 Mattermost 渠道完整实现,包含适配器核心、消息处理、交互回调、命令支持、安全校验、多账号管理等功能,支持机器人消息发送、交互按钮、命令注册、投票功能以及配置动态修改等特性。
2026-05-12 00:46:12 +08:00

96 lines
3.1 KiB
Python

from __future__ import annotations
import hashlib
import hmac
import os
from typing import Any
from yuxi.channels.models import ChannelIdentity, ChannelMessage, ChannelType, EventType, MessageType
from yuxi.utils.logging_config import logger
def verify_slash_hmac(body: bytes, signature: str, secret: str) -> bool:
if not secret or not signature:
return False
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
async def handle_slash_command(
body: bytes,
headers: dict,
adapter: Any,
) -> dict:
signing_secret = os.getenv("MATTERMOST_SIGNING_SECRET", "")
signature = headers.get("X-Mattermost-Signature", "") or headers.get("x-mattermost-signature", "")
if not verify_slash_hmac(body, signature, signing_secret):
return {"response_type": "ephemeral", "text": "签名验证失败"}
import json
try:
data = json.loads(body)
except json.JSONDecodeError:
return {"response_type": "ephemeral", "text": "无效的请求数据"}
command = data.get("command", "").strip()
text = data.get("text", "").strip()
user_id = data.get("user_id", "")
channel_id = data.get("channel_id", "")
team_id = data.get("team_id", "")
logger.info(f"[Mattermost] Slash command received: {command} '{text}' from {user_id} in channel {channel_id}")
if command in ("/forcepilot", "/fp"):
msg = ChannelMessage(
identity=ChannelIdentity(
channel_id="mattermost",
channel_type=ChannelType.MATTERMOST,
channel_user_id=user_id,
channel_chat_id=f"channel_{channel_id}",
),
event_type=EventType.MESSAGE_RECEIVED,
message_type=MessageType.COMMAND,
content=text or "你好",
metadata={"slash_command": command, "team_id": team_id},
)
await adapter._handle_message(msg)
return {
"response_type": "in_channel",
"text": f"已收到命令 `{command}`,正在处理…",
}
if command == "/help":
return {
"response_type": "ephemeral",
"text": (
"**ForcePilot Mattermost 命令**\n\n"
"| 命令 | 说明 |\n"
"|------|------|\n"
"| `/forcepilot <msg>` | 与 AI 助手对话 |\n"
"| `/fp <msg>` | 快捷对话 |\n"
"| `/model` | 切换 AI 模型 |\n"
"| `/clear` | 清除对话上下文 |\n"
"| `/help` | 显示帮助信息 |"
),
}
if command == "/clear":
return {
"response_type": "ephemeral",
"text": "对话上下文已清除 ✅",
}
if command == "/model":
from .model_picker import build_model_picker_attachment
attachments = [build_model_picker_attachment()]
return {
"response_type": "in_channel",
"text": "选择一个 AI 模型:",
"attachments": attachments,
}
return {"response_type": "ephemeral", "text": f"未知命令: {command}"}