refactor(gateway): fold pairing dir merge, bool-default table in GatewayConfig.from_dict
This commit is contained in:
@@ -506,22 +506,17 @@ def format_directory_for_display(platforms: Optional[Dict[str, Any]] = None) ->
|
||||
f"{plat_name}:<chat_id>, or bare '{plat_name}' for the home channel)"
|
||||
)
|
||||
elif plat_name == "discord":
|
||||
# Group Discord channels by guild; DMs last.
|
||||
# Group Discord channels by guild (sorted by name); DMs last, in discovery order.
|
||||
guilds: Dict[str, List] = {}
|
||||
dms: List = []
|
||||
for ch in channels:
|
||||
guild = ch.get("guild")
|
||||
(guilds.setdefault(guild, []) if guild else dms).append(ch)
|
||||
|
||||
for guild_name, guild_channels in sorted(guilds.items()):
|
||||
lines.append(f"Discord ({guild_name}):")
|
||||
lines.extend(
|
||||
f" discord:{_channel_target_name(plat_name, ch)}"
|
||||
for ch in sorted(guild_channels, key=lambda c: c["name"])
|
||||
)
|
||||
(guilds.setdefault(ch["guild"], []) if ch.get("guild") else dms).append(ch)
|
||||
groups = [(f"Discord ({g}):", sorted(chs, key=lambda c: c["name"])) for g, chs in sorted(guilds.items())]
|
||||
if dms:
|
||||
lines.append("Discord (DMs):")
|
||||
lines.extend(f" discord:{_channel_target_name(plat_name, ch)}" for ch in dms)
|
||||
groups.append(("Discord (DMs):", dms))
|
||||
for header, group in groups:
|
||||
lines.append(header)
|
||||
lines.extend(f" discord:{_channel_target_name(plat_name, ch)}" for ch in group)
|
||||
else:
|
||||
lines.append(f"{plat_name.title()}:")
|
||||
lines.extend(f" {plat_name}:{_channel_target_name(plat_name, ch)}" for ch in channels)
|
||||
|
||||
+9
-8
@@ -158,9 +158,7 @@ def coerce_systemd_watchdog_seconds(
|
||||
if parsed is None:
|
||||
logger.warning("Ignoring invalid %s (expected a positive integer)", key)
|
||||
return 0
|
||||
if parsed == 0:
|
||||
return 0
|
||||
if not 0 < parsed <= _SYSTEMD_WATCHDOG_MAX_SECONDS:
|
||||
if parsed and not 0 < parsed <= _SYSTEMD_WATCHDOG_MAX_SECONDS:
|
||||
logger.warning("Ignoring invalid %s (expected an integer from 1 to %d)", key, _SYSTEMD_WATCHDOG_MAX_SECONDS)
|
||||
return 0
|
||||
return parsed
|
||||
@@ -562,6 +560,13 @@ _PLATFORM_CONNECTED_CHECKERS: dict[Platform, Callable[[PlatformConfig], bool]] =
|
||||
}
|
||||
|
||||
|
||||
# Top-level bool-ish keys read verbatim (no nested ``gateway.`` fallback) with their defaults.
|
||||
_TOPLEVEL_BOOL_DEFAULTS = {
|
||||
"write_sessions_json": True, "always_log_local": True, "filter_silence_narration": True,
|
||||
"group_sessions_per_user": True, "thread_sessions_per_user": False,
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class GatewayConfig:
|
||||
"""Main gateway configuration: platform connections, session policies, delivery settings."""
|
||||
@@ -772,13 +777,9 @@ class GatewayConfig:
|
||||
reset_triggers=data.get("reset_triggers", ["/new", "/reset"]),
|
||||
quick_commands=_coerce_dict(data.get("quick_commands", {})),
|
||||
sessions_dir=Path(data["sessions_dir"]) if "sessions_dir" in data else get_hermes_home() / "sessions",
|
||||
write_sessions_json=_coerce_bool(data.get("write_sessions_json"), True),
|
||||
always_log_local=_coerce_bool(data.get("always_log_local"), True),
|
||||
filter_silence_narration=_coerce_bool(data.get("filter_silence_narration"), True),
|
||||
**{name: _coerce_bool(data.get(name), default) for name, default in _TOPLEVEL_BOOL_DEFAULTS.items()},
|
||||
stt_enabled=_coerce_bool(stt_setting("stt_enabled", "enabled"), True),
|
||||
stt_echo_transcripts=_coerce_bool(stt_setting("stt_echo_transcripts", "echo_transcripts"), True),
|
||||
group_sessions_per_user=_coerce_bool(data.get("group_sessions_per_user"), True),
|
||||
thread_sessions_per_user=_coerce_bool(data.get("thread_sessions_per_user"), False),
|
||||
multiplex_profiles=_coerce_bool(multiplex_profiles, False),
|
||||
multiplex_profile_allowlist=pick("multiplex_profile_allowlist"),
|
||||
room_link_url=room_link_url if isinstance(room_link_url, str) else None,
|
||||
|
||||
+15
-29
@@ -297,41 +297,27 @@ def _save_json_file(path: Path, data: dict) -> None:
|
||||
_secure_write(path, json.dumps(data, indent=2, ensure_ascii=False))
|
||||
|
||||
|
||||
def _merge_pairing_dir(active_dir: Path, alternate_dir: Path) -> None:
|
||||
def _migrate_split_pairing_dirs(*, home: Optional[Path] = None, active: Optional[Path] = None) -> None:
|
||||
"""Merge split legacy (``pairing``) / new (``platforms/pairing``) data into the active dir.
|
||||
|
||||
If both exist, approved users in the inactive location must not be
|
||||
silently ignored (they would be asked for a fresh code).
|
||||
If both exist, approved users in the inactive location must not be silently
|
||||
ignored (they would be asked for a fresh code). Active data wins on key conflict.
|
||||
"""
|
||||
if not alternate_dir.exists() or active_dir.resolve() == alternate_dir.resolve():
|
||||
return
|
||||
active_dir.mkdir(parents=True, exist_ok=True)
|
||||
for src in alternate_dir.glob("*.json"):
|
||||
if not src.is_file():
|
||||
continue
|
||||
dest = active_dir / src.name
|
||||
merged = _load_json_file(src)
|
||||
if not merged:
|
||||
continue
|
||||
current = _load_json_file(dest)
|
||||
before = dict(current)
|
||||
# Active data wins on key conflict; otherwise union the inactive data.
|
||||
merged.update(current)
|
||||
if merged != before:
|
||||
_save_json_file(dest, merged)
|
||||
|
||||
|
||||
def _migrate_split_pairing_dirs(
|
||||
*,
|
||||
home: Optional[Path] = None,
|
||||
active: Optional[Path] = None,
|
||||
) -> None:
|
||||
home = home or get_hermes_home()
|
||||
old_dir = home / "pairing"
|
||||
new_dir = home / "platforms" / "pairing"
|
||||
active = active if active is not None else _default_pairing_dir()
|
||||
alternate = new_dir if active.resolve() == old_dir.resolve() else old_dir
|
||||
_merge_pairing_dir(active, alternate)
|
||||
alternate = home / "platforms" / "pairing" if active.resolve() == old_dir.resolve() else old_dir
|
||||
if not alternate.exists() or active.resolve() == alternate.resolve():
|
||||
return
|
||||
active.mkdir(parents=True, exist_ok=True)
|
||||
for src in alternate.glob("*.json"):
|
||||
merged = _load_json_file(src) if src.is_file() else {}
|
||||
if not merged:
|
||||
continue
|
||||
current = _load_json_file(active / src.name)
|
||||
merged.update(current)
|
||||
if merged != current:
|
||||
_save_json_file(active / src.name, merged)
|
||||
|
||||
|
||||
def _secure_write(path: Path, data: str) -> None:
|
||||
|
||||
Reference in New Issue
Block a user