Console: the last OTA state per machine and app run is remembered (console_ota_memo) and shown when the upload's 256 KiB tail no longer holds it
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
0855c44338
commit
699d0d8da9
1 changed files with 27 additions and 1 deletions
|
|
@ -55,6 +55,31 @@ function parseNodeTail(tail) {
|
|||
n.last_warning = errs.length ? errs[errs.length - 1].replace(/^\S+ \S+ /, '').slice(0, 200) : null;
|
||||
return n;
|
||||
}
|
||||
// The app uploads at most the last 256 KiB of its log, so an update line scrolls out of the tail in about half an hour
|
||||
// on a PC that logs every block (4 October 2026: PC 1's "installing 0.3.4" left its card while the install was still
|
||||
// stuck). The last OTA state seen per machine and app run is kept in console_ota_memo and read back, for the same run,
|
||||
// when the tail has none; a new run (the app relaunched) starts clean.
|
||||
async function otaMemo(sql, groups) {
|
||||
try {
|
||||
await sql(`CREATE TABLE IF NOT EXISTS console_ota_memo (id8 text PRIMARY KEY, run_id text NOT NULL, ota jsonb NOT NULL, updated_at timestamptz NOT NULL DEFAULT now())`);
|
||||
const live = [...groups.values()].filter(g => g.app && !g.id.startsWith('legacy:'));
|
||||
if (!live.length) return;
|
||||
const rows = await sql(`SELECT id8, run_id, ota FROM console_ota_memo WHERE id8 = ANY($1)`, [live.map(g => g.id)]);
|
||||
const memo = new Map(rows.map(r => [r.id8, r]));
|
||||
for (const g of live) {
|
||||
const m = memo.get(g.id);
|
||||
if (g.app.ota) {
|
||||
if (!m || m.run_id !== g.app.run_id || JSON.stringify(m.ota) !== JSON.stringify(g.app.ota)) {
|
||||
await sql(`INSERT INTO console_ota_memo (id8, run_id, ota, updated_at) VALUES ($1, $2, $3::jsonb, now())
|
||||
ON CONFLICT (id8) DO UPDATE SET run_id = EXCLUDED.run_id, ota = EXCLUDED.ota, updated_at = now()`, [g.id, g.app.run_id, JSON.stringify(g.app.ota)]);
|
||||
}
|
||||
} else if (m && m.run_id === g.app.run_id && m.ota) {
|
||||
g.app.ota = { ...m.ota, remembered: true };
|
||||
}
|
||||
}
|
||||
} catch (e) { /* a convenience: the cards render without it */ }
|
||||
}
|
||||
|
||||
async function machines(sql) {
|
||||
// node logs get a longer tail: the connection-manager (peers) line is rare on a busy node
|
||||
// the app log's tail is wide (400 KB, about three hours on a PC that logs every block) so a stuck update's lines do
|
||||
|
|
@ -75,7 +100,7 @@ async function machines(sql) {
|
|||
g.labels.push({ label: r.label, at, run_id: r.run_id });
|
||||
if (p.stream === 'node') { g.node = { ...parseNodeTail(r.tail), at, run_id: r.run_id }; }
|
||||
else if (p.stream === 'miner') g.cards.push({ label: r.label.replace(/^miner-/, ''), vendor: p.vendor, card: p.card, at, ...parseMinerTail(r.tail) });
|
||||
else if (p.stream === 'app') g.app = { at, ...parseAppTail(r.tail) };
|
||||
else if (p.stream === 'app') g.app = { at, run_id: r.run_id, ...parseAppTail(r.tail) };
|
||||
groups.set(p.id, g);
|
||||
}
|
||||
// node version lives in the first upload of a run (the tail may have lost the banner): one cheap query for the current runs
|
||||
|
|
@ -88,6 +113,7 @@ async function machines(sql) {
|
|||
const hd = parseHeader(h.head); if (hd && !g.header) g.header = hd;
|
||||
}
|
||||
}
|
||||
await otaMemo(sql, groups);
|
||||
const now = Date.now();
|
||||
const out = [...groups.values()].map(g => {
|
||||
const id8 = g.id.startsWith('legacy:') ? null : g.id;
|
||||
|
|
|
|||
Loading…
Reference in a new issue