ForcePilot/backend/package/yuxi/channels/adapters/imessage/accounts.py

103 lines
4.0 KiB
Python
Raw Normal View History

from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any
@dataclass
class IMessageAccount:
account_id: str
name: str = ""
server_url: str = "http://localhost:1234"
password: str = ""
dm_policy: str = "pairing"
group_policy: str = "allowlist"
allow_from: list[str] = field(default_factory=list)
group_allow_from: list[str] = field(default_factory=list)
require_mention: bool = False
default_to: str = ""
enabled: bool = True
def resolve_accounts(config: dict[str, Any]) -> list[IMessageAccount]:
"""解析多账户配置。
支持两种配置模式
1. 顶层单账户config 直接包含 server_url / password
2. accounts config["accounts"] {accountId: {...}, ...}
返回扁平化的 IMessageAccount 列表
"""
accounts_raw = config.get("accounts")
if not accounts_raw:
account = _account_from_top_level(config)
return [account] if account.server_url else []
result: list[IMessageAccount] = []
default_account_id = config.get("defaultAccount", config.get("default_account", ""))
for account_id, acct_config in accounts_raw.items():
if not isinstance(acct_config, dict):
continue
merged = _merge_account_config(config, account_id, acct_config)
result.append(merged)
if default_account_id:
result.sort(key=lambda a: 0 if a.account_id == default_account_id else 1)
return result
def list_enabled_accounts(config: dict[str, Any]) -> list[IMessageAccount]:
accounts = resolve_accounts(config)
return [a for a in accounts if a.enabled]
def resolve_default_account(config: dict[str, Any]) -> IMessageAccount | None:
accounts = list_enabled_accounts(config)
if not accounts:
return None
default_id = config.get("defaultAccount", config.get("default_account", ""))
for acct in accounts:
if acct.account_id == default_id:
return acct
return accounts[0]
def _account_from_top_level(config: dict[str, Any]) -> IMessageAccount:
return IMessageAccount(
account_id="default",
name=config.get("name", "iMessage"),
server_url=config.get("server_url", "http://localhost:1234"),
password=config.get("password", ""),
dm_policy=config.get("dmPolicy", config.get("dm_policy", "pairing")),
group_policy=config.get("groupPolicy", config.get("group_policy", "allowlist")),
allow_from=config.get("allowFrom", config.get("allow_from", [])),
group_allow_from=config.get("groupAllowFrom", config.get("group_allow_from", [])),
require_mention=config.get("requireMention", config.get("require_mention", False)),
default_to=config.get("defaultTo", config.get("default_to", "")),
)
def _merge_account_config(top: dict[str, Any], account_id: str, acct: dict[str, Any]) -> IMessageAccount:
return IMessageAccount(
account_id=account_id,
name=acct.get("name", account_id),
server_url=acct.get("server_url", top.get("server_url", "http://localhost:1234")),
password=acct.get("password", top.get("password", "")),
dm_policy=acct.get("dmPolicy", acct.get("dm_policy", top.get("dmPolicy", top.get("dm_policy", "pairing")))),
group_policy=acct.get(
"groupPolicy", acct.get("group_policy", top.get("groupPolicy", top.get("group_policy", "allowlist")))
),
allow_from=acct.get("allowFrom", acct.get("allow_from", top.get("allowFrom", top.get("allow_from", [])))),
group_allow_from=acct.get(
"groupAllowFrom", acct.get("group_allow_from", top.get("groupAllowFrom", top.get("group_allow_from", [])))
),
require_mention=acct.get(
"requireMention", acct.get("require_mention", top.get("requireMention", top.get("require_mention", False)))
),
default_to=acct.get("defaultTo", acct.get("default_to", top.get("defaultTo", top.get("default_to", "")))),
enabled=acct.get("enabled", True),
)