import hashlib import json import os from datetime import datetime, timezone from pathlib import Path CACHE_DIR = Path.home() / ".cache" / "tmview" def _cache_path(key: str) -> Path: return CACHE_DIR / f"{key}.json" def cache_key(payload: dict) -> str: canonical = json.dumps(payload, sort_keys=True, separators=(",", ":")) return hashlib.sha256(canonical.encode()).hexdigest() def load(key: str): path = _cache_path(key) if not path.exists(): return None try: with path.open() as f: entry = json.load(f) return entry["result"], entry["fetched_at"] except (KeyError, json.JSONDecodeError, OSError): return None def save(key: str, result: dict, fetched_at: str) -> None: CACHE_DIR.mkdir(parents=True, exist_ok=True) path = _cache_path(key) entry = {"fetched_at": fetched_at, "result": result} tmp = path.with_suffix(".tmp") try: with tmp.open("w") as f: json.dump(entry, f, separators=(",", ":")) tmp.replace(path) except OSError: tmp.unlink(missing_ok=True) def now_iso() -> str: return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")