ForcePilot/backend/package/yuxi/channels/accounts/base.py
Kris 7a972055b7 feat: 新增渠道服务基础框架与核心工具类
新增大量渠道适配器相关的协议、策略、工具类与基础设施代码,包括:
1.  多协议定义:认证、消息、配置、网关等核心接口
2.  策略模块:上下文、群聊、去重、防抖等业务策略
3.  工具集:重试、去重、文本分块、消息格式化等SDK工具
4.  基础设施:外部进程管理、事件广播、熔断机制等
5.  账户与管道系统:账户管理、消息处理管道实现
6.  运行时服务:状态收集、维护任务、日志等后台服务
2026-05-12 00:53:57 +08:00

108 lines
2.9 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 abc import ABC, abstractmethod
from dataclasses import dataclass
@dataclass
class BaseChannelAccount:
"""渠道账户基类(所有可多账户的适配器共用)"""
account_id: str = "default"
enabled: bool = True
dm_policy: str = "allowlist"
group_policy: str = "allowlist"
name: str = ""
upgrade_url: str = ""
upgrade_mode: str = ""
class BaseAccountManager(ABC):
"""多账户管理器基类
定义四个标准接口:
- resolve_account(cfg, account_id) → BaseChannelAccount
- is_configured(account_id) → bool
- default_account_id(cfg) → str
- list_account_ids(cfg) → list[str]
"""
@abstractmethod
def resolve_account(self, cfg: dict, account_id: str = "default") -> BaseChannelAccount: ...
@abstractmethod
def is_configured(self, account_id: str = "default") -> bool: ...
@abstractmethod
def default_account_id(self, cfg: dict) -> str: ...
@abstractmethod
def list_account_ids(self, cfg: dict) -> list[str]: ...
def resolve_account_from_config_section(
config: dict,
account_id: str,
section_key: str = "accounts",
) -> dict:
"""从配置中提取指定账户的配置段
兼容两种配置结构:
1. 多账户(推荐):
{ accounts: { default: {...}, second: {...} }, defaultAccount: 'default' }
2. 单账户(兼容旧格式):
{ app_id: "...", client_secret: "..." } — 平铺格式
返回:账户配置 dict可能为空
"""
accounts = config.get(section_key, {})
if not accounts:
return config
account_cfg = accounts.get(account_id, {})
if not account_cfg and account_id == "default":
first = next(iter(accounts.values()), {})
return first
return account_cfg
def resolve_account_ids(
config: dict,
section_key: str = "accounts",
) -> list[str]:
"""从配置中提取所有账户 ID"""
accounts = config.get(section_key, {})
if not accounts:
return ["default"]
return list(accounts.keys())
def resolve_default_account_id(
config: dict,
section_key: str = "accounts",
) -> str:
"""解析默认账户 ID
优先级defaultAccount > 'default' > 第一个账户
"""
explicit = config.get("defaultAccount", config.get("default_account", ""))
if explicit:
return explicit
accounts = config.get(section_key, {})
if not accounts:
return "default"
if "default" in accounts:
return "default"
return next(iter(accounts.keys()), "default")
def resolve_effective_dm_scope(config: dict) -> str:
"""解析会话隔离策略(多账户场景的关键配置)
- 'merged': 所有账户的 DM 合并到同一个会话
- 'per-account-channel-peer': 按 账户/渠道/发送者 独立隔离会话(推荐默认值)
"""
return config.get("dmScope", config.get("dm_scope", "per-account-channel-peer"))