108 lines
2.9 KiB
Python
108 lines
2.9 KiB
Python
|
|
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"))
|