ForcePilot/backend/package/yuxi/channel/extensions/wechat_ilink/config.py
Kris 7b5d1e5c69 feat(channel): 添加 Webex、微信 iLink 和微信小程序渠道扩展
新增 Webex、微信 iLink、微信小程序三个渠道扩展。

Webex 渠道扩展功能模块:
- config: 渠道配置管理
- gateway: SSE/WebSocket 网关接入
- webhook: Webhook 事件处理
- outbound: 外发消息管理
- streaming: 流式消息处理
- pairing: 用户配对与绑定
- security: 安全校验
- dedupe: 消息去重
- monitor: 渠道状态监控
- status: 会话状态管理
- media: 媒体资源处理

微信 iLink 渠道扩展功能模块:
- config: 渠道配置管理
- gateway: SSE/WebSocket 网关接入
- outbound: 外发消息管理
- streaming: 流式消息处理
- pairing: 用户配对与绑定
- security: 安全校验
- dedupe: 消息去重
- monitor: 渠道状态监控
- status: 会话状态管理
- context_store: 上下文存储
- aes_ecb: AES-ECB 加解密
- media: 媒体资源处理
- typing: 输入状态

微信小程序渠道扩展功能模块:
- config: 渠道配置管理
- gateway: SSE/WebSocket 网关接入
- webhook: Webhook 事件处理
- outbound: 外发消息管理
- streaming: 流式消息处理
- pairing: 用户配对与绑定
- security: 安全校验
- crypto: 加解密处理
- dedupe: 消息去重
- message: 消息处理
- passive_reply: 被动回复
- media: 媒体资源处理
- status: 会话状态管理
2026-05-21 11:59:04 +08:00

130 lines
5.4 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
from yuxi.channel.extensions.wechat_ilink.types import ILinkAccount
def resolve_account(config: dict[str, Any], account_id: str | None = None) -> ILinkAccount | None:
accounts: list[dict[str, Any]] = config.get("accounts", [])
if not accounts:
return None
if account_id:
for acct in accounts:
if acct.get("account_id") == account_id:
return _parse_account(acct)
else:
return _parse_account(accounts[0])
return None
def list_accounts(config: dict[str, Any]) -> list[ILinkAccount]:
accounts: list[dict[str, Any]] = config.get("accounts", [])
return [_parse_account(acct) for acct in accounts]
def _parse_account(data: dict[str, Any]) -> ILinkAccount:
return ILinkAccount(
account_id=data.get("account_id", "default"),
bot_token=data.get("bot_token", ""),
refresh_token=data.get("refresh_token", ""),
bot_user_id=data.get("bot_user_id", ""),
bot_nickname=data.get("bot_nickname", ""),
token_expires_at=data.get("token_expires_at", 0.0),
dm_policy=data.get("dm_policy", "open"),
group_policy=data.get("group_policy", "open"),
allow_from=data.get("allow_from", []),
enabled=data.get("enabled", True),
proxy=data.get("proxy"),
poll_timeout=data.get("poll_timeout", 25),
poll_interval=data.get("poll_interval", 0.25),
max_retries=data.get("max_retries", 100),
ilink_bot_id=data.get("ilink_bot_id", ""),
ilink_user_id=data.get("ilink_user_id", ""),
base_url=data.get("base_url", "https://ilinkai.weixin.qq.com"),
)
def serialize_account(account: ILinkAccount) -> dict[str, Any]:
return {
"account_id": account.account_id,
"bot_token": account.bot_token,
"refresh_token": account.refresh_token,
"bot_user_id": account.bot_user_id,
"bot_nickname": account.bot_nickname,
"token_expires_at": account.token_expires_at,
"dm_policy": account.dm_policy,
"group_policy": account.group_policy,
"allow_from": account.allow_from,
"enabled": account.enabled,
"proxy": account.proxy,
"poll_timeout": account.poll_timeout,
"poll_interval": account.poll_interval,
"max_retries": account.max_retries,
"ilink_bot_id": account.ilink_bot_id,
"ilink_user_id": account.ilink_user_id,
"base_url": account.base_url,
}
def config_schema() -> dict:
return {
"type": "object",
"title": "微信个人号 (iLink) 渠道配置",
"properties": {
"enabled": {"type": "boolean", "default": True},
"dm_policy": {
"type": "string",
"enum": ["open", "allowlist", "pairing", "disabled"],
"default": "open",
"description": "私聊策略open=无限制, allowlist=白名单, pairing=配对验证, disabled=禁用",
},
"group_policy": {
"type": "string",
"enum": ["open", "allowlist", "disabled"],
"default": "open",
"description": "群聊策略",
},
"allow_from": {
"type": "array",
"items": {"type": "string"},
"description": "白名单用户/群组 ID 列表",
},
"poll_timeout": {"type": "integer", "default": 25, "description": "长轮询超时(秒)"},
"poll_interval": {"type": "number", "default": 0.25, "description": "轮询间隔(秒)"},
"max_retries": {"type": "integer", "default": 100, "description": "最大重试次数"},
"proxy": {"type": "string", "description": "HTTP 代理地址"},
"base_url": {
"type": "string",
"default": "https://ilinkai.weixin.qq.com",
"description": "iLink API 基础地址",
},
"accounts": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"bot_token": {"type": "string", "description": "Bot Token"},
"refresh_token": {"type": "string"},
"bot_user_id": {"type": "string"},
"bot_nickname": {"type": "string"},
"token_expires_at": {"type": "number"},
"dm_policy": {"type": "string", "enum": ["open", "allowlist", "pairing", "disabled"]},
"group_policy": {"type": "string", "enum": ["open", "allowlist", "disabled"]},
"allow_from": {"type": "array", "items": {"type": "string"}},
"enabled": {"type": "boolean", "default": True},
"proxy": {"type": "string"},
"poll_timeout": {"type": "integer", "default": 25},
"poll_interval": {"type": "number", "default": 0.25},
"max_retries": {"type": "integer", "default": 100},
"ilink_bot_id": {"type": "string"},
"ilink_user_id": {"type": "string"},
"base_url": {"type": "string", "default": "https://ilinkai.weixin.qq.com"},
},
},
},
},
}