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)