From b0fe6e6c593eff675029959452418d86dee47dcd Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Mon, 25 Nov 2024 14:04:28 +0800 Subject: [PATCH] WebUI: ensure cached info are initialized properly PR #21893. --- src/webui/www/private/scripts/cache.js | 125 +++++++++++++----------- src/webui/www/private/scripts/client.js | 22 ++++- 2 files changed, 84 insertions(+), 63 deletions(-) diff --git a/src/webui/www/private/scripts/cache.js b/src/webui/www/private/scripts/cache.js index 67d718a1f..4d2ac096c 100644 --- a/src/webui/www/private/scripts/cache.js +++ b/src/webui/www/private/scripts/cache.js @@ -53,19 +53,20 @@ window.qBittorrent.Cache ??= (() => { class BuildInfoCache { #m_store = {}; - init() { - new Request.JSON({ - url: "api/v2/app/buildInfo", - method: "get", - noCache: true, - onSuccess: (responseJSON) => { - if (!responseJSON) + async init() { + return fetch("api/v2/app/buildInfo", { + method: "GET", + cache: "no-store" + }) + .then(async (response) => { + if (!response.ok) return; + const responseText = await response.text(); + const responseJSON = JSON.parse(responseText); deepFreeze(responseJSON); this.#m_store = responseJSON; - } - }).send(); + }); } get() { @@ -80,26 +81,27 @@ window.qBittorrent.Cache ??= (() => { // onFailure: () => {}, // onSuccess: () => {} // } - init(obj = {}) { - new Request.JSON({ - url: "api/v2/app/preferences", - method: "get", - noCache: true, - onFailure: (xhr) => { - if (typeof obj.onFailure === "function") - obj.onFailure(xhr); - }, - onSuccess: (responseJSON, responseText) => { - if (!responseJSON) - return; + async init(obj = {}) { + return fetch("api/v2/app/preferences", { + method: "GET", + cache: "no-store" + }) + .then(async (response) => { + if (!response.ok) + return; - deepFreeze(responseJSON); - this.#m_store = responseJSON; + const responseText = await response.text(); + const responseJSON = JSON.parse(responseText); + deepFreeze(responseJSON); + this.#m_store = responseJSON; - if (typeof obj.onSuccess === "function") - obj.onSuccess(responseJSON, responseText); - } - }).send(); + if (typeof obj.onSuccess === "function") + obj.onSuccess(responseJSON, responseText); + }, + (error) => { + if (typeof obj.onFailure === "function") + obj.onFailure(error); + }); } get() { @@ -117,48 +119,53 @@ window.qBittorrent.Cache ??= (() => { if (typeof obj.data !== "object") throw new Error("`data` is not an object."); - new Request({ - url: "api/v2/app/setPreferences", - method: "post", - data: { - "json": JSON.stringify(obj.data) - }, - onFailure: (xhr) => { - if (typeof obj.onFailure === "function") - obj.onFailure(xhr); - }, - onSuccess: (responseText, responseXML) => { - this.#m_store = structuredClone(this.#m_store); - for (const key in obj.data) { - if (!Object.hasOwn(obj.data, key)) - continue; + fetch("api/v2/app/setPreferences", { + method: "POST", + body: new URLSearchParams({ + "json": JSON.stringify(obj.data) + }) + }) + .then(async (response) => { + if (!response.ok) + return; - const value = obj.data[key]; - this.#m_store[key] = value; - } - deepFreeze(this.#m_store); + this.#m_store = structuredClone(this.#m_store); + for (const key in obj.data) { + if (!Object.hasOwn(obj.data, key)) + continue; - if (typeof obj.onSuccess === "function") - obj.onSuccess(responseText, responseXML); - } - }).send(); + const value = obj.data[key]; + this.#m_store[key] = value; + } + deepFreeze(this.#m_store); + + if (typeof obj.onSuccess === "function") { + const responseText = await response.text(); + obj.onSuccess(responseText); + } + }, + (error) => { + if (typeof obj.onFailure === "function") + obj.onFailure(error); + }); } } class QbtVersionCache { #m_store = ""; - init() { - new Request({ - url: "api/v2/app/version", - method: "get", - noCache: true, - onSuccess: (responseText) => { - if (!responseText) + async init() { + return fetch("api/v2/app/version", { + method: "GET", + cache: "no-store" + }) + .then(async (response) => { + if (!response.ok) return; + + const responseText = await response.text(); this.#m_store = responseText; - } - }).send(); + }); } get() { diff --git a/src/webui/www/private/scripts/client.js b/src/webui/www/private/scripts/client.js index f0e4771ba..6817df461 100644 --- a/src/webui/www/private/scripts/client.js +++ b/src/webui/www/private/scripts/client.js @@ -30,6 +30,7 @@ window.qBittorrent.Client ??= (() => { const exports = () => { return { setup: setup, + initializeCaches: initializeCaches, closeWindow: closeWindow, closeFrameWindow: closeFrameWindow, getSyncMainDataInterval: getSyncMainDataInterval, @@ -45,11 +46,22 @@ window.qBittorrent.Client ??= (() => { }; }; + let cacheAllSettled; const setup = () => { // fetch various data and store it in memory - window.qBittorrent.Cache.buildInfo.init(); - window.qBittorrent.Cache.preferences.init(); - window.qBittorrent.Cache.qbtVersion.init(); + cacheAllSettled = Promise.allSettled([ + window.qBittorrent.Cache.buildInfo.init(), + window.qBittorrent.Cache.preferences.init(), + window.qBittorrent.Cache.qbtVersion.init() + ]); + }; + + const initializeCaches = async () => { + const results = await cacheAllSettled; + for (const [idx, result] of results.entries()) { + if (result.status === "rejected") + console.error(`Failed to initialize cache. Index: ${idx}. Reason: "${result.reason}".`); + } }; const closeWindow = (windowID) => { @@ -1771,7 +1783,9 @@ window.addEventListener("DOMContentLoaded", () => { }); }); -window.addEventListener("load", () => { +window.addEventListener("load", async () => { + await window.qBittorrent.Client.initializeCaches(); + // switch to previously used tab const previouslyUsedTab = LocalPreferences.get("selected_window_tab", "transfers"); switch (previouslyUsedTab) {