From 7aecf8fae730be493e611eaa3a894f33463c11a6 Mon Sep 17 00:00:00 2001 From: defnax <9952056+defnax@users.noreply.github.com> Date: Wed, 9 Sep 2026 20:29:31 +0200 Subject: [PATCH] Fixed. The friend cache now belongs to the current account, server, and login session. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Responses from an old login can’t repopulate it. --- webui-src/app/network/network_data.js | 50 ++++++++++++++++++++++----- webui-src/app/rswebui.js | 3 ++ 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/webui-src/app/network/network_data.js b/webui-src/app/network/network_data.js index c2ebc8c..5697ba2 100644 --- a/webui-src/app/network/network_data.js +++ b/webui-src/app/network/network_data.js @@ -50,8 +50,34 @@ async function loadOnlineIds() { return new Set(ids); } +let cacheLogin = null; +let cachedDetails = {}; + +function currentCacheLogin() { + const login = rs.loginKey || {}; + return JSON.stringify([login.url, login.username, login.isVerified, login.generation]); +} + +function ensureCacheLogin() { + const key = currentCacheLogin(); + if (cacheLogin !== key) { + cacheLogin = key; + cachedDetails = {}; + refreshInFlight = null; + refreshedAt = 0; + } + return key; +} + const Data = { - gpgDetails: {}, + get gpgDetails() { + ensureCacheLogin(); + return cachedDetails; + }, + set gpgDetails(details) { + ensureCacheLogin(); + cachedDetails = details; + }, runQueued, }; @@ -171,19 +197,21 @@ Data.getStatusPresentation = function (statusValue, isOnline = false) { // friend. Otherwise a fresh enough result is only touched up with the online // list, one request, and concurrent callers share the sweep in flight. Data.refreshGpgDetails = function (options = {}) { + const login = ensureCacheLogin(); const force = Boolean(options && options.force); if (refreshInFlight) return refreshInFlight; if (!force && refreshedAt && Date.now() - refreshedAt < GPG_DETAILS_TTL_MS) { - return refreshOnlineFlags(); + return refreshOnlineFlags(login); } - refreshInFlight = sweepGpgDetails() - .then(() => { refreshedAt = Date.now(); }) - .finally(() => { refreshInFlight = null; }); + refreshInFlight = sweepGpgDetails(login) + .then(() => { if (currentCacheLogin() === login) refreshedAt = Date.now(); }) + .finally(() => { if (currentCacheLogin() === login) refreshInFlight = null; }); return refreshInFlight; }; -async function refreshOnlineFlags() { +async function refreshOnlineFlags(login) { const online = await loadOnlineIds(); + if (currentCacheLogin() !== login) return; Object.values(Data.gpgDetails || {}).forEach((friend) => { let anyOnline = false; (friend.locations || []).forEach((loc) => { @@ -194,10 +222,12 @@ async function refreshOnlineFlags() { }); } -async function sweepGpgDetails() { +async function sweepGpgDetails(login) { const details = {}; const sslIds = await refreshIds(); + if (currentCacheLogin() !== login) return; const online = await loadOnlineIds(); + if (currentCacheLogin() !== login) return; // A first load shows the list as it fills rather than nothing for the // whole sweep; a refresh keeps the old list on screen until it is done. @@ -256,11 +286,12 @@ async function sweepGpgDetails() { // Status string and status value only mean something for a peer that is // connected: two requests per online peer instead of two per location. const tasks = sslIds.map((sslId) => async () => { + if (currentCacheLogin() !== login) return; let data = null; await rs.rsJsonApiRequest('/rsPeers/getPeerDetails', { sslId }, (res) => { if (res && res.det) data = res.det; }); - if (!data) return; + if (!data || currentCacheLogin() !== login) return; const isOnline = online.has(sslId); let customState = ''; @@ -270,6 +301,7 @@ async function sweepGpgDetails() { await rs.rsJsonApiRequest('/rsChats/getCustomStateString', { peer_id: sslId }, (statusData) => { if (statusData && statusData.retval) customState = statusData.retval; }); + if (currentCacheLogin() !== login) return; await rs.rsJsonApiRequest('/rsStatus/getStatus', { id: sslId }, (statusData) => { if (statusData && statusData.retval && statusData.statusInfo) { statusValue = normalizeStatusValue(statusData.statusInfo.status, statusValue); @@ -277,9 +309,11 @@ async function sweepGpgDetails() { } }); } + if (currentCacheLogin() !== login) return; addLocation(data, isOnline, customState, statusValue, statusTimestamp); }); await runQueued(tasks, SWEEP_CONCURRENCY); + if (currentCacheLogin() !== login) return; const remembered = loadPendingFriends(); let rememberedChanged = false; diff --git a/webui-src/app/rswebui.js b/webui-src/app/rswebui.js index 2ed2c1a..1b4df8c 100644 --- a/webui-src/app/rswebui.js +++ b/webui-src/app/rswebui.js @@ -68,6 +68,7 @@ const RsEventsType = { const API_URL = 'http://127.0.0.1:9092'; const loginKey = { + generation: 0, username: sessionStorage.getItem('rs_username') || '', passwd: sessionStorage.getItem('rs_passwd') || '', isVerified: sessionStorage.getItem('rs_isVerified') === 'true', @@ -76,6 +77,8 @@ const loginKey = { // Make this as object property? function setKeys(username, password, url = API_URL, verified = true) { + if (loginKey.username !== username || loginKey.passwd !== password + || loginKey.url !== url || loginKey.isVerified !== verified) loginKey.generation += 1; loginKey.username = username; loginKey.passwd = password; loginKey.url = url;