113 lines
3.3 KiB
Python
113 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Any
|
|
|
|
|
|
@dataclass
|
|
class MatrixAccountPatch:
|
|
user_id: str | None = None
|
|
display_name: str | None = None
|
|
avatar_url: str | None = None
|
|
homeserver: str | None = None
|
|
access_token: str | None = None
|
|
device_id: str | None = None
|
|
dm_policy: str | None = None
|
|
group_policy: str | None = None
|
|
allow_bots: bool | None = None
|
|
auto_join: str | None = None
|
|
sync_timeout_ms: int | None = None
|
|
loop_sleep_ms: int | None = None
|
|
probe_timeout_s: float | None = None
|
|
response_prefix: str | None = None
|
|
require_mention: bool | None = None
|
|
chunk_mode: str | None = None
|
|
media_max_mb: int | None = None
|
|
crypto_store_dir: str | None = None
|
|
rooms: dict[str, Any] | None = None
|
|
dm_allow_from: list[str] | None = None
|
|
group_allow_from: list[str] | None = None
|
|
extra: dict[str, Any] = field(default_factory=dict)
|
|
|
|
_KNOWN_FIELDS = frozenset(
|
|
{
|
|
"user_id",
|
|
"display_name",
|
|
"avatar_url",
|
|
"homeserver",
|
|
"access_token",
|
|
"device_id",
|
|
"dm_policy",
|
|
"group_policy",
|
|
"allow_bots",
|
|
"auto_join",
|
|
"sync_timeout_ms",
|
|
"loop_sleep_ms",
|
|
"probe_timeout_s",
|
|
"response_prefix",
|
|
"require_mention",
|
|
"chunk_mode",
|
|
"media_max_mb",
|
|
"crypto_store_dir",
|
|
"rooms",
|
|
"dm_allow_from",
|
|
"group_allow_from",
|
|
}
|
|
)
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
result: dict[str, Any] = {}
|
|
for name in self._KNOWN_FIELDS:
|
|
value = getattr(self, name)
|
|
if value is not None:
|
|
result[name] = value
|
|
result.update(self.extra)
|
|
return result
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: dict[str, Any]) -> MatrixAccountPatch:
|
|
known: dict[str, Any] = {}
|
|
extra: dict[str, Any] = {}
|
|
for k, v in data.items():
|
|
if k in cls._KNOWN_FIELDS:
|
|
known[k] = v
|
|
else:
|
|
extra[k] = v
|
|
return cls(**known, extra=extra)
|
|
|
|
@property
|
|
def has_changes(self) -> bool:
|
|
return any(getattr(self, name) is not None for name in self._KNOWN_FIELDS) or bool(self.extra)
|
|
|
|
|
|
def apply_patch(config: dict[str, Any], patch: MatrixAccountPatch) -> dict[str, Any]:
|
|
result = dict(config)
|
|
fields = patch.to_dict()
|
|
|
|
for key, value in fields.items():
|
|
if key in ("rooms", "dm_allow_from", "group_allow_from"):
|
|
if isinstance(value, (list, dict)):
|
|
result[key] = value
|
|
else:
|
|
result[key] = value
|
|
|
|
return result
|
|
|
|
|
|
def merge_patches(base: MatrixAccountPatch, overlay: MatrixAccountPatch) -> MatrixAccountPatch:
|
|
base_dict = base.to_dict()
|
|
overlay_dict = overlay.to_dict()
|
|
base_dict.update(overlay_dict)
|
|
return MatrixAccountPatch.from_dict(base_dict)
|
|
|
|
|
|
def diff_config(old: dict[str, Any], new: dict[str, Any]) -> dict[str, tuple[Any, Any]]:
|
|
all_keys = set(old.keys()) | set(new.keys())
|
|
diff: dict[str, tuple[Any, Any]] = {}
|
|
for key in all_keys:
|
|
old_val = old.get(key)
|
|
new_val = new.get(key)
|
|
if old_val != new_val:
|
|
diff[key] = (old_val, new_val)
|
|
return diff
|