from __future__ import annotations import json import os from pathlib import Path from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from asterisk_mcp.targets import TargetRegistry def targets_path() -> Path: from asterisk_mcp.config import settings return Path(os.path.expanduser(settings.targets_path)) def load_registry(registry: TargetRegistry) -> None: path = targets_path() if not path.exists(): return try: data = json.loads(path.read_text()) except (OSError, json.JSONDecodeError): return registry._loading = True loaded_active: str | None = None for entry in data.get("targets", []): if not isinstance(entry, dict): continue name = str(entry.get("name", "")).strip() host = str(entry.get("ssh_host", "")).strip() if not name or not host: continue try: registry.register( name=name, ssh_host=host, ssh_user=str(entry.get("ssh_user", "root")), ssh_port=int(entry.get("ssh_port", 22)), ssh_key_path=str(entry.get("ssh_key_path", "")), container=str(entry.get("container", "asterisk")), description=str(entry.get("description", "")), registered_at=str(entry.get("registered_at", "")), set_active=False, ) except Exception: continue active = str(data.get("active", "")).strip() if active: try: registry.set_active(active) loaded_active = active except Exception: pass if not loaded_active and registry.list(): registry.set_active(registry.list()[0]["name"]) registry._loading = False def save_registry(registry: TargetRegistry) -> None: path = targets_path() path.parent.mkdir(parents=True, exist_ok=True) targets: list[dict[str, Any]] = [] for cfg in registry._targets.values(): targets.append( { "name": cfg.name, "ssh_host": cfg.ssh_host, "ssh_user": cfg.ssh_user, "ssh_port": cfg.ssh_port, "ssh_key_path": cfg.ssh_key_path, "container": cfg.container, "description": cfg.description, "registered_at": cfg.registered_at, } ) payload = {"active": registry._active, "targets": sorted(targets, key=lambda r: r["name"])} path.write_text(json.dumps(payload, indent=2) + "\n") try: path.chmod(0o600) except OSError: pass