- puga/: cached FIO + PRUNplanner clients, market view with order-book walk, econ formulas ported from PRUNplanner (tested against its suite and live FIO), saturation model v1 (reviewed by Opus) - tools/: scan (depth-aware), price, book, chain, state sync, plan_push (dry run default, [PuGa]-prefixed plans only), legacy prun_scan/prun_cxarb - docs/: mechanics (PRUNplanner is source of truth), roadmap, decisions, saturation design, archived handoff - secrets stay in .env (gitignored); ref/ holds PRUNplanner source (ignored) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
37 lines
1.5 KiB
Python
37 lines
1.5 KiB
Python
"""api.prunplanner.org. Public data endpoints need no auth; planning endpoints use `Authorization: Api-Key <key>`."""
|
|
from .cache import get_json
|
|
from . import config
|
|
|
|
BASE = "https://api.prunplanner.org"
|
|
MARKET, STATIC = 15 * 60, 24 * 3600
|
|
|
|
|
|
def _g(path: str, ttl: int, refresh: bool = False):
|
|
return get_json(BASE + path, ttl, refresh=refresh)
|
|
|
|
|
|
def exchanges(refresh=False):
|
|
"""Per ticker.CX: ask/bid/supply/demand, vwap_daily/7d/30d, traded_daily, sum/avg_traded_7d/30d, exchange_status."""
|
|
return _g("/data/exchanges/", MARKET, refresh)
|
|
def materials(refresh=False): return _g("/data/materials/", STATIC, refresh)
|
|
def recipes(refresh=False): return _g("/data/recipes/", STATIC, refresh)
|
|
def buildings(refresh=False): return _g("/data/buildings/", STATIC, refresh)
|
|
|
|
|
|
def api_key() -> str | None:
|
|
return config.get("PRUNPLANNER_API_KEY")
|
|
|
|
|
|
def request(method: str, path: str, body: dict | None = None):
|
|
"""Authenticated call (Api-Key). Callers must enforce write guardrails (see tools/plan_push.py)."""
|
|
import json, urllib.request
|
|
key = api_key()
|
|
if not key:
|
|
raise RuntimeError("PRUNPLANNER_API_KEY missing in .env")
|
|
data = json.dumps(body).encode() if body is not None else None
|
|
req = urllib.request.Request(BASE + path, data=data, method=method, headers={
|
|
"Authorization": "Api-Key " + key, "Content-Type": "application/json", "User-Agent": "PuGa/0.1"})
|
|
with urllib.request.urlopen(req, timeout=60) as r:
|
|
raw = r.read()
|
|
return json.loads(raw) if raw else None
|