From 0de279926faa05ee6fc1ce607bef2043a5419d87 Mon Sep 17 00:00:00 2001 From: PTah Date: Mon, 13 Apr 2026 13:45:54 +1000 Subject: [PATCH] fix(ui): single-flight scan poll so status line does not alternate Made-with: Cursor --- internal/webui/index.html | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/internal/webui/index.html b/internal/webui/index.html index 9dd7666..64482dd 100644 --- a/internal/webui/index.html +++ b/internal/webui/index.html @@ -249,6 +249,8 @@ /** @type {{if_index:number,bridge_port:number,mac:string,learned_ip:string}[]} */ let lastPortDevItems = []; let selectedFdbKey = null; + /** Увеличивается при каждом новом pollScanUntilDone — снимает гонку createScan vs watchScan (чередование строк статуса). */ + let scanPollSeq = 0; const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); @@ -287,31 +289,47 @@ * @param {{ intervalMs?: number, maxWaitMs?: number, onDone?: function }} opts */ async function pollScanUntilDone(scanId, opts = {}) { + const mySeq = ++scanPollSeq; const intervalMs = opts.intervalMs ?? 1000; const maxWaitMs = opts.maxWaitMs ?? 20 * 60 * 1000; const started = Date.now(); while (Date.now() - started < maxWaitMs) { + if (mySeq !== scanPollSeq) { + return null; + } let job; try { job = await fetchScanJob(scanId); } catch (e) { - setStatus(`Ошибка опроса скана: ${e.message}`); + if (mySeq === scanPollSeq) { + setStatus(`Ошибка опроса скана: ${e.message}`); + } + return null; + } + if (mySeq !== scanPollSeq) { return null; } setStatus(describeScanProgress(job)); if (job.status === "done" || job.status === "failed" || job.status === "canceled") { + if (mySeq !== scanPollSeq) { + return null; + } if (opts.onDone) { try { await opts.onDone(job); } catch (e) { - setStatus((statusEl.textContent || "") + ` | Ошибка в onDone: ${e.message}`); + if (mySeq === scanPollSeq) { + setStatus((statusEl.textContent || "") + ` | Ошибка в onDone: ${e.message}`); + } } } return job; } await sleep(intervalMs); } - setStatus(`Таймаут ожидания скана ${scanId} (${Math.round(maxWaitMs / 60000)} мин).`); + if (mySeq === scanPollSeq) { + setStatus(`Таймаут ожидания скана ${scanId} (${Math.round(maxWaitMs / 60000)} мин).`); + } return null; }