from __future__ import annotations from datetime import datetime, timezone import json from pathlib import Path from typing import Any from app.persistence import atomic_write_bytes OTA_STATE_SCHEMA_VERSION = 1 def utc_now() -> str: return datetime.now(timezone.utc).isoformat(timespec="seconds").replace("+00:00", "Z") def read_json(path: Path) -> dict[str, Any] | None: try: value = json.loads(Path(path).read_text(encoding="utf-8")) except (OSError, UnicodeError, json.JSONDecodeError): return None return value if isinstance(value, dict) else None def write_json(path: Path, document: dict[str, Any]) -> None: atomic_write_bytes( Path(path), (json.dumps(document, ensure_ascii=False, indent=2, sort_keys=True) + "\n").encode("utf-8"), ) def read_last_result(data_root: Path) -> dict[str, Any] | None: document = read_json(Path(data_root) / "ota" / "state.json") if not document or document.get("schema_version") != OTA_STATE_SCHEMA_VERSION: return None result = document.get("last_result") return dict(result) if isinstance(result, dict) else None def write_last_result(data_root: Path, result: dict[str, Any]) -> None: write_json( Path(data_root) / "ota" / "state.json", {"schema_version": OTA_STATE_SCHEMA_VERSION, "last_result": dict(result)}, )