From f3f2d1f76e03fbe66db0d7a2fcb66c9aac8c006a Mon Sep 17 00:00:00 2001 From: ioj4 <69911332+ioj4@users.noreply.github.com> Date: Thu, 9 Jan 2025 08:41:52 +0100 Subject: [PATCH] [shelter] improve bundle fetching this also fixes shelter failing to load when there's no internet connection right on launch --- CHANGELOG.md | 3 ++ branches/mod/shelter/patch.js | 85 ++++++++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96e0e62..580476d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## r18 +Improve shelter bundle fetching + ## r17 - Make the new dashboard look nicer - Replace useless last module time with cache hit rates diff --git a/branches/mod/shelter/patch.js b/branches/mod/shelter/patch.js index 45e138e..3d805aa 100644 --- a/branches/mod/shelter/patch.js +++ b/branches/mod/shelter/patch.js @@ -1,14 +1,13 @@ const electron = require("electron"); const path = require("path"); const Module = require("module"); -const fs = require("original-fs"); // using electron's fs causes app.asar to be locked during host updates +const fs = require("original-fs"); // "fs" module without electron modifications const https = require("https"); const { EOL } = require("os"); const logger = new Proxy(console, { get: (target, key) => function (...args) { - //logFile?.write(`[${new Date().toISOString()}] [${key}] ${args.join(" ")}${EOL}`); return target[key].apply(console, ["[shelter]", ...args]); }, }); @@ -18,42 +17,63 @@ logger.log("Loading..."); // #region Bundle const remoteUrl = process.env.SHELTER_BUNDLE_URL || "https://raw.githubusercontent.com/uwu/shelter-builds/main/shelter.js"; -const localBundle = process.env.SHELTER_DIST_PATH; +const distPath = process.env.SHELTER_DIST_PATH; -let fetchPromise; // only fetch once +let localBundle; -if (!localBundle) - fetchPromise = new Promise((resolve, reject) => { +if (distPath) { + localBundle = + fs.readFileSync(path.join(distPath, "shelter.js"), "utf8") + + `\n//# sourceMappingURL=file://${process.platform === "win32" ? "/" : ""}${path.join(distPath, "shelter.js.map")}`; +} + +let remoteBundle; +let remoteBundlePromise; + +const fetchRemoteBundleIfNeeded = () => { + if (localBundle || remoteBundle) return Promise.resolve(); + + remoteBundlePromise ??= new Promise((resolve) => { const req = https.get(remoteUrl); req.on("response", (res) => { + if (res.statusCode !== 200) { + remoteBundlePromise = null; + resolve(); + return; + } const chunks = []; res.on("data", (chunk) => chunks.push(chunk)); res.on("end", () => { - let data = Buffer.concat(chunks).toString("utf-8"); + let script = Buffer.concat(chunks).toString("utf-8"); - if (!data.includes("//# sourceMappingURL=")) data += `\n//# sourceMappingURL=${remoteUrl + ".map"}`; - - resolve(data); + if (!script.includes("//# sourceMappingURL=")) script += `\n//# sourceMappingURL=${remoteUrl + ".map"}`; + remoteBundle = script; + remoteBundlePromise = null; + resolve(); }); }); - req.on("error", reject); + req.on("error", (e) => { + logger.error("Error fetching remote bundle:", e); + remoteBundlePromise = null; + resolve(); + }); req.end(); }); -const getShelterBundle = () => - !localBundle - ? fetchPromise - : Promise.resolve( - fs.readFileSync(path.join(localBundle, "shelter.js"), "utf8") + - `\n//# sourceMappingURL=file://${process.platform === "win32" ? "/" : ""}${path.join( - localBundle, - "shelter.js.map", - )}`, - ); + return remoteBundlePromise; +}; + +fetchRemoteBundleIfNeeded(); + +const getShelterBundle = () => { + if (localBundle) return localBundle; + if (remoteBundle) return remoteBundle; + return `console.error("[shelter] Bundle could not be fetched in time. Aborting!");`; +}; // #endregion // #region IPC @@ -157,5 +177,28 @@ Module.prototype.require = function (path) { } return loadedModule; }; +// #endregion + +// #region Patch BrowserWindow +const ProxiedBrowserWindow = new Proxy(electron.BrowserWindow, { + construct(target, args) { + const window = new target(...args); + const originalLoadURL = window.loadURL; + window.loadURL = async function (url) { + if (url.includes("discord.com/app")) { + await fetchRemoteBundleIfNeeded(); + } + return await originalLoadURL.apply(this, arguments); + }; + + return window; + }, +}); +const electronPath = require.resolve("electron"); +delete require.cache[electronPath].exports; +require.cache[electronPath].exports = { + ...electron, + BrowserWindow: ProxiedBrowserWindow, +}; // #endregion