77 lines
3.7 KiB
Python
77 lines
3.7 KiB
Python
|
|
from dataclasses import dataclass
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class CatchupConfig:
|
||
|
|
enabled: bool = True
|
||
|
|
max_age_minutes: int = 120
|
||
|
|
per_run_limit: int = 50
|
||
|
|
first_run_lookback_minutes: int = 30
|
||
|
|
max_failure_retries: int = 10
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class GroupConfig:
|
||
|
|
require_mention: bool = False
|
||
|
|
tools: dict | None = None
|
||
|
|
system_prompt: str | None = None
|
||
|
|
|
||
|
|
|
||
|
|
class BlueBubblesConfigAdapter:
|
||
|
|
CHANNEL_KEY = "bluebubbles"
|
||
|
|
|
||
|
|
def _get_channel_config(self, config: dict) -> dict:
|
||
|
|
return config.get("channels", {}).get(self.CHANNEL_KEY, {})
|
||
|
|
|
||
|
|
def list_account_ids(self, config: dict) -> list[str]:
|
||
|
|
channel_config = self._get_channel_config(config)
|
||
|
|
accounts = channel_config.get("accounts", {})
|
||
|
|
if accounts:
|
||
|
|
return list(accounts.keys())
|
||
|
|
return ["default"]
|
||
|
|
|
||
|
|
async def resolve_account(self, config: dict, account_id: str = "default") -> dict | None:
|
||
|
|
channel_config = self._get_channel_config(config)
|
||
|
|
accounts = channel_config.get("accounts", {})
|
||
|
|
account = accounts.get(account_id, {}) if account_id != "default" else {}
|
||
|
|
|
||
|
|
server_url = account.get("serverUrl") or channel_config.get("serverUrl")
|
||
|
|
password = account.get("password") or channel_config.get("password")
|
||
|
|
|
||
|
|
if not server_url or not password:
|
||
|
|
return None
|
||
|
|
|
||
|
|
return {
|
||
|
|
"account_id": account_id,
|
||
|
|
"server_url": server_url,
|
||
|
|
"password": password,
|
||
|
|
"dm_policy": account.get("dmPolicy") or channel_config.get("dmPolicy", "pairing"),
|
||
|
|
"allow_from": account.get("allowFrom") or channel_config.get("allowFrom", []),
|
||
|
|
"group_policy": account.get("groupPolicy") or channel_config.get("groupPolicy", "allowlist"),
|
||
|
|
"group_allow_from": account.get("groupAllowFrom") or channel_config.get("groupAllowFrom", []),
|
||
|
|
"groups": {**channel_config.get("groups", {}), **account.get("groups", {})},
|
||
|
|
"media_max_mb": account.get("mediaMaxMb") or channel_config.get("mediaMaxMb"),
|
||
|
|
"media_local_roots": account.get("mediaLocalRoots") or channel_config.get("mediaLocalRoots", []),
|
||
|
|
"text_chunk_limit": account.get("textChunkLimit") or channel_config.get("textChunkLimit", 4000),
|
||
|
|
"chunk_mode": account.get("chunkMode") or channel_config.get("chunkMode", "newline"),
|
||
|
|
"send_timeout_ms": account.get("sendTimeoutMs") or channel_config.get("sendTimeoutMs", 30000),
|
||
|
|
"send_read_receipts": account.get("sendReadReceipts", channel_config.get("sendReadReceipts", True)),
|
||
|
|
"coalesce_same_sender_dms": account.get(
|
||
|
|
"coalesceSameSenderDms", channel_config.get("coalesceSameSenderDms", False)
|
||
|
|
),
|
||
|
|
"enrich_group_participants_from_contacts": account.get(
|
||
|
|
"enrichGroupParticipantsFromContacts",
|
||
|
|
channel_config.get("enrichGroupParticipantsFromContacts", True),
|
||
|
|
),
|
||
|
|
"allow_private_network": account.get("network", {}).get("dangerouslyAllowPrivateNetwork")
|
||
|
|
or channel_config.get("network", {}).get("dangerouslyAllowPrivateNetwork", False),
|
||
|
|
"catchup": CatchupConfig(**{**channel_config.get("catchup", {}), **account.get("catchup", {})}),
|
||
|
|
"webhook_path": account.get("webhookPath") or channel_config.get("webhookPath", "/bluebubbles-webhook"),
|
||
|
|
"webhook_secret": account.get("webhookSecret") or channel_config.get("webhookSecret", ""),
|
||
|
|
"enabled": account.get("enabled", channel_config.get("enabled", True)),
|
||
|
|
"config": {**channel_config, **account},
|
||
|
|
}
|
||
|
|
|
||
|
|
def is_configured(self, account: dict | None) -> bool:
|
||
|
|
return bool(account and account.get("server_url") and account.get("password"))
|