From 5a3b65d544adb46e8317a9781ad74a8c6a6efee0 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Fri, 27 Jun 2025 04:38:41 +0200 Subject: [PATCH] chore(webui): keep config in sync over multiple tabs Adding "wsid" to uniquely identify a given tab (by the websocket connection) so we can avoid needless refreshing on the same tab. --- src/controllers/custom/configController.ts | 2 ++ src/services/webService.ts | 26 ++++++++++++++++++++++ static/webui/script.js | 12 ++++++---- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/controllers/custom/configController.ts b/src/controllers/custom/configController.ts index 2c1e10ac..2249f48f 100644 --- a/src/controllers/custom/configController.ts +++ b/src/controllers/custom/configController.ts @@ -2,6 +2,7 @@ import { RequestHandler } from "express"; import { config } from "@/src/services/configService"; import { getAccountForRequest, isAdministrator } from "@/src/services/loginService"; import { saveConfig } from "@/src/services/configWatcherService"; +import { sendWsBroadcastExcept } from "@/src/services/webService"; export const getConfigController: RequestHandler = async (req, res) => { const account = await getAccountForRequest(req); @@ -24,6 +25,7 @@ export const setConfigController: RequestHandler = async (req, res) => { const [obj, idx] = configIdToIndexable(id); obj[idx] = value; } + sendWsBroadcastExcept(parseInt(String(req.query.wsid)), { config_reloaded: true }); await saveConfig(); res.end(); } else { diff --git a/src/services/webService.ts b/src/services/webService.ts index ecc5a494..11ff2654 100644 --- a/src/services/webService.ts +++ b/src/services/webService.ts @@ -136,7 +136,10 @@ export const stopWebServer = async (): Promise => { await Promise.all(promises); }; +let lastWsid: number = 0; + interface IWsCustomData extends ws { + id?: number; accountId?: string; } @@ -150,6 +153,7 @@ interface IWsMsgFromClient { } interface IWsMsgToClient { + //wsid?: number; reload?: boolean; ports?: { http: number | undefined; @@ -174,6 +178,10 @@ const wsOnConnect = (ws: ws, req: http.IncomingMessage): void => { ws.close(); return; } + + (ws as IWsCustomData).id = ++lastWsid; + ws.send(JSON.stringify({ wsid: lastWsid })); + // eslint-disable-next-line @typescript-eslint/no-misused-promises ws.on("message", async msg => { const data = JSON.parse(String(msg)) as IWsMsgFromClient; @@ -268,3 +276,21 @@ export const sendWsBroadcastTo = (accountId: string, data: IWsMsgToClient): void } } }; + +export const sendWsBroadcastExcept = (wsid: number | undefined, data: IWsMsgToClient): void => { + const msg = JSON.stringify(data); + if (wsServer) { + for (const client of wsServer.clients) { + if ((client as IWsCustomData).id != wsid) { + client.send(msg); + } + } + } + if (wssServer) { + for (const client of wssServer.clients) { + if ((client as IWsCustomData).id != wsid) { + client.send(msg); + } + } + } +}; diff --git a/static/webui/script.js b/static/webui/script.js index 479f0014..dd49f356 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -10,7 +10,8 @@ let auth_pending = false, did_initial_auth = false, - ws_is_open = false; + ws_is_open = false, + wsid = 0; const sendAuth = isRegister => { if (ws_is_open && localStorage.getItem("email") && localStorage.getItem("password")) { auth_pending = true; @@ -34,6 +35,9 @@ function openWebSocket() { }; window.ws.onmessage = e => { const msg = JSON.parse(e.data); + if ("wsid" in msg) { + wsid = msg.wsid; + } if ("reload" in msg) { setTimeout(() => { getWebSocket().then(() => { @@ -1858,7 +1862,7 @@ for (const id of uiConfigs) { value = parseInt(value); } $.post({ - url: "/custom/setConfig?" + window.authz, + url: "/custom/setConfig?" + window.authz + "&wsid=" + wsid, contentType: "application/json", data: JSON.stringify({ [id]: value }) }); @@ -1866,7 +1870,7 @@ for (const id of uiConfigs) { } else if (elm.type == "checkbox") { elm.onchange = function () { $.post({ - url: "/custom/setConfig?" + window.authz, + url: "/custom/setConfig?" + window.authz + "&wsid=" + wsid, contentType: "application/json", data: JSON.stringify({ [id]: this.checked }) }).then(() => { @@ -1881,7 +1885,7 @@ for (const id of uiConfigs) { function doSaveConfig(id) { const elm = document.getElementById(id); $.post({ - url: "/custom/setConfig?" + window.authz, + url: "/custom/setConfig?" + window.authz + "&wsid=" + wsid, contentType: "application/json", data: JSON.stringify({ [id]: parseInt(elm.value) }) });