From 2d9c3275f1b66c9fd917cf2a0de6bf9b9213d8fa Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sun, 22 Feb 2026 17:54:00 +0100 Subject: [PATCH] improve ui connection monitor Signed-off-by: Vladimir Mandic --- CHANGELOG.md | 7 +-- javascript/logMonitor.js | 1 - javascript/monitor.js | 95 ++++++++++++++++++++++++---------------- javascript/startup.js | 24 +++++----- javascript/ui.js | 1 - 5 files changed, 74 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cd53b1ab..e0de868b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,12 @@ # Change Log for SD.Next -## Update for 2026-02-21 +## Update for 2026-02-22 -### Highlights for 2026-02-21 +### Highlights for 2026-02-22 TBD -### Details for 2026-02-21 +### Details for 2026-02-22 - **Models** - [FireRed Image Edit](https://huggingface.co/FireRedTeam/FireRed-Image-Edit-1.0) @@ -88,6 +88,7 @@ TBD - gallery over remote/unsecure connections - ltx2-i2v - handle missing preview image + - ui connection monitor ## Update for 2026-02-04 diff --git a/javascript/logMonitor.js b/javascript/logMonitor.js index ee3bf9369..70472ced0 100644 --- a/javascript/logMonitor.js +++ b/javascript/logMonitor.js @@ -82,7 +82,6 @@ async function logMonitor() { for (const line of lines) addLogLine(line); if (!logConnected) { logConnected = true; - monitorConnection(); xhrPost(`${window.api}/log`, { debug: 'connected' }); } } else { diff --git a/javascript/monitor.js b/javascript/monitor.js index abc3c38ab..c2905377b 100644 --- a/javascript/monitor.js +++ b/javascript/monitor.js @@ -3,6 +3,8 @@ class ConnectionMonitorState { static version = ''; static commit = ''; static branch = ''; + static model = ''; + static startup = ''; static online = false; static getModel() { @@ -11,66 +13,85 @@ class ConnectionMonitorState { } static trimModelName(name) { - // remove trailing [hash], split on / or \, return last segment, trim return name.replace(/\s*\[.*\]\s*$/, '').split(/[\\/]/).pop().trim() || 'unknown model'; } - static setData({ online, updated, commit, branch }) { + static setData({ online, data }) { this.online = online; - this.version = updated; - this.commit = commit; - this.branch = branch; + if (data?.version) this.version = data.version; + if (data?.commit) this.commit = data.commit; + if (data?.branch) this.branch = data.branch; + if (data?.model) this.model = this.trimModelName(data.model); } - static setElement(el) { - this.element = el; - } - - static toHTML(modelOverride) { + static toHTML() { + if (!this.model) this.model = this.getModel(); return ` Version: ${this.version}
Commit: ${this.commit}
Branch: ${this.branch}
Status: ${this.online ? 'online' : 'offline'}
- Model: ${modelOverride ? this.trimModelName(modelOverride) : this.getModel()}
- Since: ${new Date().toLocaleString()}
+ Model: ${this.model}
+ Since: ${this.startup.toLocaleString()}
`; } - static updateState(incomingModel) { - this.element.dataset.hint = this.toHTML(incomingModel); + static updateState() { + if (!this.element) { + const el = document.getElementById('logo_nav'); + if (el) this.element = el; + else return; + } + this.element.dataset.hint = this.toHTML(); this.element.style.backgroundColor = this.online ? 'var(--sd-main-accent-color)' : 'var(--color-error)'; } } -let monitorAutoUpdating = false; - -async function updateIndicator(online, data, msg) { - const el = document.getElementById('logo_nav'); - if (!el || !data) return; - ConnectionMonitorState.setElement(el); - if (!monitorAutoUpdating) { - monitorOption('sd_model_checkpoint', (newVal) => { ConnectionMonitorState.updateState(newVal); }); // Runs before opt actually changes - monitorAutoUpdating = true; - } - ConnectionMonitorState.setData({ online, ...data }); +async function updateIndicator(online, data = {}, msg = undefined) { + ConnectionMonitorState.setData({ online, data }); ConnectionMonitorState.updateState(); - if (online) { - log('monitorConnection: online', data); - } else { - log('monitorConnection: offline', msg); + if (msg) log('monitorConnection:', { online, data, msg }); +} + +async function wsMonitorLoop(url) { + try { + const ws = new WebSocket(`${url}/queue/join`); + ws.onopen = () => {}; + ws.onmessage = (evt) => updateIndicator(true); + ws.onclose = () => setTimeout(() => wsMonitorLoop(url), 10000); + ws.onerror = (e) => { + updateIndicator(false, {}, e.message); + setTimeout(() => monitorConnection(url), 10000); // eslint-disable-line no-use-before-define + }; + } catch (e) { + updateIndicator(false, {}, e.message); + setTimeout(() => monitorConnection(url), 10000); // eslint-disable-line no-use-before-define } } +let monitorActive = false; + async function monitorConnection() { + if (!monitorActive) { // start monitor loop only once on startup + monitorActive = true; + monitorOption('sd_model_checkpoint', (newVal) => { // runs before opt actually changes + ConnectionMonitorState.model = newVal; + ConnectionMonitorState.updateState(); + }); + } + ConnectionMonitorState.startup = new Date(); + + let data = {}; try { const res = await authFetch(`${window.api}/version`); - const data = await res.json(); - const url = res.url.split('/sdapi')[0].replace('http', 'ws'); // update global url as ws need fqdn - const ws = new WebSocket(`${url}/queue/join`); - ws.onopen = () => updateIndicator(true, data, ''); - ws.onclose = () => updateIndicator(false, data, ''); - ws.onerror = (e) => updateIndicator(false, data, e.message); - ws.onmessage = (evt) => log('monitorConnection: message', evt.data); - } catch { /**/ } + data = await res.json(); + log('monitorConnection:', { data }); + ConnectionMonitorState.startup = new Date(); + updateIndicator(true, data); + const url = res.url.split('/sdapi')[0].replace('https:', 'wss:').replace('http:', 'ws:'); // update global url as ws need fqdn + wsMonitorLoop(url); + } catch { + monitorConnection(false, data); + setTimeout(monitorConnection, 10000); + } } diff --git a/javascript/startup.js b/javascript/startup.js index 8f512572b..5f6b3f926 100644 --- a/javascript/startup.js +++ b/javascript/startup.js @@ -30,22 +30,21 @@ async function initStartup() { if (window.setupLogger) await setupLogger(); // all items here are non-blocking async calls - await initModels(); - await getUIDefaults(); - await initPromptChecker(); - await initContextMenu(); - await initDragDrop(); - await initAccordions(); - await initSettings(); - await initImageViewer(); - await initiGenerationParams(); - await initChangelog(); - await setupControlUI(); + initModels(); + getUIDefaults(); + initPromptChecker(); + initContextMenu(); + initDragDrop(); + initAccordions(); + initSettings(); + initImageViewer(); + initiGenerationParams(); + initChangelog(); + setupControlUI(); // reconnect server session await reconnectUI(); await waitForOpts(); - await initGallery(); log('mountURL', window.opts.subpath); @@ -60,6 +59,7 @@ async function initStartup() { // optinally wait for modern ui if (window.waitForUiReady) await waitForUiReady(); + monitorConnection(); removeSplash(); // post startup tasks that may take longer but are not critical diff --git a/javascript/ui.js b/javascript/ui.js index 27f159385..e76d55611 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -630,5 +630,4 @@ async function reconnectUI() { const sd_model_observer = new MutationObserver(sd_model_callback); sd_model_observer.observe(sd_model, { attributes: true, childList: true, subtree: true }); log('reconnectUI'); - monitorConnection(); }