新增 iMessage 通道适配器完整实现,包含: 1. 核心适配器与工具工厂导出 2. 运行时存储、反射防护、会话路由等基础组件 3. 消息信封、线程管理、回复上下文格式化 4. Tapback 表情反应处理、自定义异常体系 5. 审批按钮、联系人解析、速率限制功能 6. 文本净化、目标解析、缓存管理模块 7. 配置 schema、多账户支持、安装向导等配置模块 8. 审计日志、媒体AI处理等扩展功能
103 lines
4.0 KiB
Python
103 lines
4.0 KiB
Python
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),
|
||
)
|