ForcePilot/backend/package/yuxi/channels/accounts/base.py

108 lines
2.9 KiB
Python
Raw Normal View History

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"))