← Commit history

0.5.36: widget helper with bounded polling (interval cache, hidden pause, error backoff)

John Lauer ·939b32d5bb ·1mo ago ·parent e2e7c8b
3 files changed +23−8
bin/hydrogen-widget-lib.py+20−5
@@ -25,19 +25,25 @@ html,body{margin:0;height:100%%;background:transparent;color:#e6ebef;font-family const R=%(refresh_ms)d; function bar(l,p){const c=p>=90?'hot':p>=70?'warn':'';return `<span class="lbl">${l}</span><span class="bar ${c}"><i style="width:${Math.max(0,Math.min(100,p))}%%"></i></span><span class="v">${Math.round(p)}%%</span>`;} async function tick(){try{const r=await fetch('/data.json',{cache:'no-store'});const d=await r.json();document.getElementById('w').innerHTML=%(render_js)s;}catch(e){document.getElementById('w').innerHTML='<span class="err">no data</span>';}}-tick();setInterval(tick,R);+let tm=null;function arm(){if(tm)return;tm=setInterval(tick,R);}function disarm(){if(tm){clearInterval(tm);tm=null;}}+document.addEventListener('visibilitychange',()=>{if(document.hidden)disarm();else{tick();arm();}});+tick();if(!document.hidden)arm(); </script></body>"""  def serve(title, data_fn, render_js, refresh_ms=60000, mark=None):     mark = mark or {'svg': '', 'color': 'currentColor'}     port = int(os.environ.get('HYDROGEN_WIDGET_PORT') or (sys.argv[sys.argv.index('--port')+1] if '--port' in sys.argv else 8930))-    cache = {'t': 0, 'v': {'error': 'starting'}}+    # One upstream call per interval at most, however often the page asks; on an upstream+    # error the interval doubles up to 15 minutes and returns to normal on the next success.+    cache = {'t': 0, 'v': {'error': 'starting'}, 'wait': refresh_ms/1000}     lock = threading.Lock()     def data():         with lock:-            if time.time() - cache['t'] > refresh_ms/1000 - 1:-                try: cache['v'] = data_fn()-                except Exception as e: cache['v'] = {'error': str(e)[:120]}+            if time.time() - cache['t'] >= cache['wait'] - 1:+                try:+                    cache['v'] = data_fn(); cache['wait'] = refresh_ms/1000+                except Exception as e:+                    cache['v'] = {'error': str(e)[:120]}; cache['wait'] = min(900, max(refresh_ms/1000, cache['wait']) * 2)                 cache['t'] = time.time()             return cache['v']     class H(BaseHTTPRequestHandler):@@ -63,6 +69,15 @@ def serve(title, data_fn, render_js, refresh_ms=60000, mark=None):         threading.Timer(0.5, announce).start()     srv.serve_forever() +_creds = {}+def read_json_if_changed(path):+    """Parse a JSON file only when its mtime moved; the parsed value is cached otherwise."""+    path = os.path.expanduser(path)+    st = os.stat(path)+    ent = _creds.get(path)+    if ent and ent[0] == st.st_mtime_ns: return ent[1]+    v = json.load(open(path)); _creds[path] = (st.st_mtime_ns, v); return v+ def http_json(url, headers):     req = urllib.request.Request(url, headers=headers)     with urllib.request.urlopen(req, timeout=15) as r: return json.loads(r.read().decode())
package.json+1−1
@@ -4,7 +4,7 @@   "type": "bootstrap",   "title": "Adom Hydrogen (platform base)",   "brief": "Layer Hydrogen's workspace onto a standard Adom workstation.",-  "version": "0.5.35",+  "version": "0.5.36",   "description": "Hydrogen's PLATFORM-GENERIC workspace layer on top of adom/core. Installs adom/core for the full Adom ecosystem, then adds everything common to running inside Hydrogen on ANY platform: the runtime-neutral hydrogen-* skills and the generic editor configuration (Claude Code CLI + extension, VS Code settings, trusted domains). Platform-specific layers depend on THIS: adom/hydrogen-windows-bootstrap (WSL2), adom/hydrogen-mac-bootstrap, adom/hydrogen-ubuntu-bootstrap. The reference design other orgs copy to build their own bootstrap on adom/core.",   "org": "adom",   "tags": [
page.json+2−2
@@ -4,7 +4,7 @@   "type": "bootstrap",   "title": "Adom Hydrogen (platform base)",   "brief": "Layer Hydrogen's workspace onto a standard Adom workstation.",-  "version": "0.5.35",+  "version": "0.5.36",   "description": "Hydrogen's PLATFORM-GENERIC workspace layer on top of adom/core. Installs adom/core for the full Adom ecosystem, then adds everything common to running inside Hydrogen on ANY platform: the runtime-neutral hydrogen-* skills and the generic editor configuration (Claude Code CLI + extension, VS Code settings, trusted domains). Platform-specific layers depend on THIS: adom/hydrogen-windows-bootstrap (WSL2), adom/hydrogen-mac-bootstrap, adom/hydrogen-ubuntu-bootstrap. The reference design other orgs copy to build their own bootstrap on adom/core.",   "org": "adom",   "tags": [@@ -49,4 +49,4 @@     "hydrogen editor configuration",     "where do hydrogen skills come from"   ]-}\ No newline at end of file+}