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

97 lines
3.6 KiB
Python

from __future__ import annotations
import os
from typing import Any
async def diagnose(adapter: Any) -> dict[str, Any]:
issues: list[str] = []
warnings: list[str] = []
checks: dict[str, bool] = {}
config = (adapter.config or {}) if adapter else {}
server_url = (
config.get("server_url", "") or os.getenv("MATTERMOST_SERVER_URL", "") or os.getenv("MATTERMOST_URL", "")
)
bot_token = config.get("bot_token", "") or os.getenv("MATTERMOST_BOT_TOKEN", "")
checks["server_url_configured"] = bool(server_url)
checks["bot_token_configured"] = bool(bot_token)
if not server_url:
issues.append("server_url not configured (config.server_url or MATTERMOST_SERVER_URL)")
if not bot_token:
issues.append("bot_token not configured (config.bot_token or MATTERMOST_BOT_TOKEN)")
if checks["server_url_configured"] and checks["bot_token_configured"]:
from .adapter import probe_mattermost
try:
probe_result = await probe_mattermost(server_url, bot_token, timeout_s=30.0)
if probe_result.get("status") == "ok":
checks["connection_ok"] = True
checks["bot_verified"] = True
else:
checks["connection_ok"] = False
issues.append(f"Connection probe failed: {probe_result.get('message', 'unknown')}")
except Exception as e:
checks["connection_ok"] = False
issues.append(f"Connection probe exception: {e}")
signing_secret = os.getenv("MATTERMOST_SIGNING_SECRET", "")
checks["signing_secret_configured"] = bool(signing_secret)
if not signing_secret:
warnings.append("MATTERMOST_SIGNING_SECRET not set — interactive messages may fail")
dm_policy = config.get("dm_policy", "open")
group_policy = config.get("group_policy", "open")
if dm_policy == "disabled" and group_policy == "disabled":
warnings.append("Both DM and group policies are disabled — bot will not respond")
result = {
"channel": "mattermost",
"status": "error" if issues else ("warning" if warnings else "ok"),
"checks": checks,
"issues": issues,
"warnings": warnings,
"server_url": server_url,
"configured": checks["server_url_configured"] and checks["bot_token_configured"],
}
if adapter:
snapshot = adapter.snapshot() if hasattr(adapter, "snapshot") else {}
result["connected"] = adapter._is_connected() if hasattr(adapter, "_is_connected") else False
result["snapshot"] = snapshot
return result
async def migrate_config(adapter: Any) -> dict[str, Any]:
config = (adapter.config or {}) if adapter else {}
changes: list[str] = []
if not config.get("silence_send"):
changes.append("Added silence_send default")
if "commands" not in config or not isinstance(config.get("commands"), dict):
from .slash import SlashCommandConfig
slash_cfg = SlashCommandConfig.from_config(config.get("slash_commands", {}))
config["commands"] = {
"native": slash_cfg.auto_register,
"callback_url": slash_cfg.callback_url,
}
changes.append("Migrated slash_commands to commands config")
if "interactions" not in config:
config["interactions"] = {"allowedSourceIps": []}
changes.append("Added default interactions config")
if "blockStreamingCoalesce" not in config:
config["blockStreamingCoalesce"] = {"minChars": 1500, "idleMs": 1000}
changes.append("Added default block streaming coalesce config")
return {"migrated": bool(changes), "changes": changes, "config": config}