"""Tiny disk cache for JSON over HTTP, keyed by URL, expiry by TTL seconds.""" import hashlib, json, time, urllib.error, urllib.request from .config import CACHE_DIR UA = "PuGa/0.1 (personal advisory toolkit)" def get_json(url: str, ttl: int, headers: dict[str, str] | None = None, refresh: bool = False): CACHE_DIR.mkdir(parents=True, exist_ok=True) f = CACHE_DIR / (hashlib.sha1(url.encode()).hexdigest()[:16] + ".json") if not refresh and f.exists() and time.time() - f.stat().st_mtime < ttl: return json.loads(f.read_text()) req = urllib.request.Request(url, headers={"User-Agent": UA, **(headers or {})}) for attempt in range(4): # transient SSL/connection errors happen on long scans try: with urllib.request.urlopen(req, timeout=60) as r: data = json.load(r) break except (urllib.error.URLError, ConnectionError, TimeoutError): if attempt == 3: raise time.sleep(1.5 * (attempt + 1)) f.write_text(json.dumps(data)) return data