"""Read / write the device config file at ~/assistant/state/config.json.""" import json import os from dataclasses import asdict, dataclass from pathlib import Path class ConfigMissingError(RuntimeError): """Raised when config.json is missing or malformed.""" @dataclass(frozen=True) class Config: device_id: str device_token: str backend_ws: str def config_path() -> Path: return Path(os.environ["HOME"]) / "assistant" / "state" / "config.json" def load_config() -> Config: path = config_path() if not path.exists(): raise ConfigMissingError(f"{path} not found; run `python -m client.pair` first") try: raw = json.loads(path.read_text()) except json.JSONDecodeError as exc: raise ConfigMissingError(f"{path} is not valid JSON: {exc}") from exc try: return Config( device_id=str(raw["device_id"]), device_token=str(raw["device_token"]), backend_ws=str(raw["backend_ws"]), ) except KeyError as exc: raise ConfigMissingError(f"{path} missing field: {exc}") from exc def save_config(cfg: Config) -> None: path = config_path() path.parent.mkdir(parents=True, exist_ok=True) # Write to a temp file then atomically rename, so a partial write never # leaves a half-baked config on disk. tmp = path.with_suffix(".json.tmp") tmp.write_text(json.dumps(asdict(cfg), indent=2) + "\n") os.chmod(tmp, 0o600) os.replace(tmp, path)