ForcePilot/backend/package/yuxi/channels/adapters/wechat/config_schema.py
Kris 05abecc02b feat(wechat): 新增完整微信渠道适配器实现
该提交实现了支持企业微信、微信公众号、个人微信桥接三种模式的完整微信渠道适配器,包含以下核心模块:
1. 基础认证与配置相关:auth_adapter、config_reload、setup_contract等
2. 消息处理与格式转换:format、attachment_adapter、outbound_adapter等
3. 多模式客户端支持:wecom/mp子模块,包含加解密、消息收发能力
4. 辅助能力:限速器、防抖、会话绑定、事件映射、模板渲染等
5. 扩展能力:二维码登录、消息读取、特权用户、心跳监控等

实现了完整的微信生态对接能力,支持消息收发、事件处理、API调用限流、配置热重载等功能。
2026-05-12 00:51:04 +08:00

121 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
from typing import Any
WECHAT_CONFIG_SCHEMA: dict[str, Any] = {
"type": "object",
"additionalProperties": False,
"properties": {
"enabled": {"type": "boolean"},
"accounts": {
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9_-]+$": {
"type": "object",
"oneOf": [
{
"required": ["corp_id", "corp_secret", "agent_id"],
"properties": {
"corp_id": {"type": "string", "minLength": 1},
"corp_secret": {"type": "string", "minLength": 1},
"agent_id": {"type": "string", "minLength": 1},
},
},
{
"required": ["app_id", "app_secret"],
"properties": {
"app_id": {"type": "string", "minLength": 1},
"app_secret": {"type": "string", "minLength": 1},
},
},
{
"required": ["bridge_url"],
"properties": {
"bridge_url": {"type": "string", "format": "uri"},
},
},
],
},
},
},
"dmPolicy": {"enum": ["open", "pairing", "allowlist", "disabled"]},
"groupPolicy": {"enum": ["open", "allowlist", "disabled"]},
"retry_attempts": {"type": "integer", "minimum": 1, "maximum": 10},
"retry_min_delay": {"type": "number", "minimum": 0.1, "maximum": 60.0},
"retry_max_delay": {"type": "number", "minimum": 1.0, "maximum": 120.0},
"outbound_priority_enabled": {"type": "boolean"},
"exec_approval_timeout": {"type": "integer", "minimum": 1, "maximum": 30},
"ban_backoff_intervals": {
"type": "array",
"items": {"type": "integer", "minimum": 1},
"minItems": 1,
"maxItems": 5,
},
},
}
def validate_wechat_config(config: dict[str, Any]) -> list[str]:
errors: list[str] = []
if not isinstance(config, dict):
return ["配置必须是对象(dict)"]
enabled = config.get("enabled")
if enabled is not None and not isinstance(enabled, bool):
errors.append("enabled 必须是布尔值")
dm_policy = config.get("dm_policy", "pairing")
if dm_policy not in ("open", "pairing", "allowlist", "disabled"):
errors.append(f"dm_policy 值无效: {dm_policy}(可选: open/pairing/allowlist/disabled")
group_policy = config.get("group_policy", "allowlist")
if group_policy not in ("open", "allowlist", "disabled"):
errors.append(f"group_policy 值无效: {group_policy}(可选: open/allowlist/disabled")
retry_attempts = config.get("retry_attempts")
if retry_attempts is not None and (not isinstance(retry_attempts, int) or retry_attempts < 0):
errors.append("retry_attempts 必须是非负整数")
retry_min_delay = config.get("retry_min_delay")
if retry_min_delay is not None and (not isinstance(retry_min_delay, (int, float)) or retry_min_delay < 0):
errors.append("retry_min_delay 必须是非负数")
retry_max_delay = config.get("retry_max_delay")
if retry_max_delay is not None and (not isinstance(retry_max_delay, (int, float)) or retry_max_delay < 0):
errors.append("retry_max_delay 必须是非负数")
outbound_priority_enabled = config.get("outbound_priority_enabled")
if outbound_priority_enabled is not None and not isinstance(outbound_priority_enabled, bool):
errors.append("outbound_priority_enabled 必须是布尔值")
exec_approval_timeout = config.get("exec_approval_timeout")
if exec_approval_timeout is not None and (not isinstance(exec_approval_timeout, int) or exec_approval_timeout < 0):
errors.append("exec_approval_timeout 必须是非负整数")
ban_backoff_intervals = config.get("ban_backoff_intervals")
if ban_backoff_intervals is not None:
if not isinstance(ban_backoff_intervals, list) or not all(
isinstance(x, int) and x > 0 for x in ban_backoff_intervals
):
errors.append("ban_backoff_intervals 必须是正整数列表")
has_corp = all(config.get(k) for k in ("corp_id", "corp_secret", "agent_id"))
has_mp = all(config.get(k) for k in ("app_id", "app_secret"))
has_bridge = bool(config.get("bridge_url"))
if not (has_corp or has_mp or has_bridge):
errors.append("缺少有效的微信配置 (wecom/mp/bridge)")
accounts = config.get("accounts", {})
if accounts and isinstance(accounts, dict):
for account_id, account_cfg in accounts.items():
if not isinstance(account_id, str) or not account_id.replace("-", "").replace("_", "").isalnum():
errors.append(f"账户 ID 格式无效: {account_id}")
return errors
def get_schema() -> dict[str, Any]:
return dict(WECHAT_CONFIG_SCHEMA)