import logging import os import time import httpx logger = logging.getLogger("pops") _cache: dict[str, tuple[float, list]] = {} _TTL = 300 # seconds def _base() -> str: return os.environ.get("FILAMENTDB_URL", "https://web.filamentdb.orb.local").rstrip("/") def _get(path: str, params: dict | None = None) -> list | dict: r = httpx.get(f"{_base()}{path}", params=params, timeout=5, verify=False) r.raise_for_status() return r.json() def _cached(key: str, fetch): now = time.monotonic() if key in _cache and now - _cache[key][0] < _TTL: return _cache[key][1] try: result = fetch() _cache[key] = (now, result) return result except Exception: logger.warning("FilamentDB unreachable — using cached/fallback data") return _cache.get(key, (0, []))[1] def get_stock() -> list[dict]: """All filament types with stock counts from /reports/stock.""" return _cached("stock", lambda: _get("/reports/stock")) def available_materials() -> list[str]: """Unique materials that have at least one roll in stock.""" rows = get_stock() seen, out = set(), [] for r in rows: m = r.get("material", "") if m and r.get("rolls_in_stock", 0) > 0 and m not in seen: seen.add(m) out.append(m) return sorted(out) def available_colors(material: str | None = None) -> list[str]: """Unique color names in stock, optionally filtered by material.""" rows = get_stock() seen, out = set(), [] for r in rows: if r.get("rolls_in_stock", 0) <= 0: continue if material and r.get("material") != material: continue c = r.get("color_name") or "" if c and c not in seen: seen.add(c) out.append(c) return sorted(out)