From e75891e75dae80ff2de5b8c3d8a3b1a39bf97ffc Mon Sep 17 00:00:00 2001 From: Luke Hoersten Date: Sat, 20 Jun 2026 12:23:34 -0500 Subject: scrypted: settings page /state fetch — sequence + 3s timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two reasons the Status (live) section was showing "offline / unreachable (fetch failed)" intermittently: 1. /state and /config were fetched in parallel, eating both available httpd sockets simultaneously (Phase 2 dropped max_open_sockets from 4 to 2). Any other inbound HTTP at the same instant would either queue or error. 2. The 1.5s timeout was tight given the firmware now juggles a live stream socket on port 81 (with occasional cap-flush reconnects) alongside the httpd workers on port 80. Sequence the two fetches and bump the timeout to 3s. Total worst-case 6s if both are slow; that's fine for a Settings page, far from "feels offline." --- scrypted/scrypted-viewport.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/scrypted/scrypted-viewport.ts b/scrypted/scrypted-viewport.ts index 6d554cd..fdcc01b 100644 --- a/scrypted/scrypted-viewport.ts +++ b/scrypted/scrypted-viewport.ts @@ -6,7 +6,7 @@ // short git hash of the commit that added this constant — if the // hash in the log doesn't match the HEAD this file came from, the // Scrypted Script editor is still on stale code. -const SCRIPT_VERSION = "e3bccca"; +const SCRIPT_VERSION = "pending"; // // Architecture // ------------ @@ -238,17 +238,18 @@ class Viewport extends ScryptedDeviceBase implements Settings { } as any, ]; - // Live device snapshot: GET /state + /config in parallel with a - // short timeout, then render as a read-only "Status" section. If - // the device is offline we still surface the binding fields so the - // operator can change them — the status fields just say "offline". + // Live device snapshot: GET /state then /config sequentially + // (parallel ate both httpd slots simultaneously after Phase 2 + // dropped max_open_sockets to 2, and could collide with an + // in-flight stream-socket cap-flush reconnect). 3s timeout is + // generous but not so long that an offline device feels + // unresponsive in the UI. if (this.host) { try { - const ctrl = AbortSignal.timeout(1500); - const [stateRes, configRes] = await Promise.all([ - fetch(`http://${this.host}/state`, { signal: ctrl }).then(r => r.json()), - fetch(`http://${this.host}/config`, { signal: ctrl }).then(r => r.json()), - ]); + const stateRes = await fetch(`http://${this.host}/state`, + { signal: AbortSignal.timeout(3000) }).then(r => r.json()); + const configRes = await fetch(`http://${this.host}/config`, + { signal: AbortSignal.timeout(3000) }).then(r => r.json()); settings.push( { group: "Status (live)", key: "_st_name", title: "name", value: stateRes.name, readonly: true } as any, { group: "Status (live)", key: "_st_mac", title: "mac", value: stateRes.mac, readonly: true } as any, -- cgit v1.2.3