From 7f1d6d12c487fffc8b8e9331012c5f9a842de70a Mon Sep 17 00:00:00 2001 From: Oj Date: Fri, 11 Feb 2022 22:41:40 +0000 Subject: [PATCH] [Splash > Backend] Self-rewrite main code (not updater parts) --- src/splash/index.js | 355 +++++++++++++++--------------------------- src/splash/preload.js | 2 +- 2 files changed, 130 insertions(+), 227 deletions(-) diff --git a/src/splash/index.js b/src/splash/index.js index c5d8c72..fe6fe9d 100644 --- a/src/splash/index.js +++ b/src/splash/index.js @@ -1,43 +1,141 @@ -"use strict"; +const { join } = require('path'); +const fs = require('fs'); +const _events = require('events'); +const { BrowserWindow, app } = require('electron'); + +const paths = require('../paths'); +const Backoff = require('../utils/Backoff'); +const moduleUpdater = require("../updater/moduleUpdater"); +const updater = require("../updater/updater"); + +let splashState = {}; +let launchedMainWindow = false; +let updateAttempt = 0; +let restartRequired = false; + + +exports.initSplash = (startMinimized = false) => { + log('Splash', `Initing`); + + newUpdater = updater.getUpdater(); + + if (newUpdater == null) initOldUpdater(); -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.initSplash = initSplash; -exports.focusWindow = focusWindow; -exports.pageReady = pageReady; -exports.events = exports.APP_SHOULD_SHOW = exports.APP_SHOULD_LAUNCH = void 0; + launchSplashWindow(startMinimized); -var _electron = require("electron"); + if (newUpdater != null) { + updateUntilCurrent(); + } else { + moduleUpdater.installPendingUpdates(); + } + + if (process.env.OPENASAR_QUICKSTART || oaConfig.quickstart) setTimeout(() => { + destroySplash(); + + if (newUpdater != null) { // Manually load desktop_core module path for faster requiring + require('../utils/u2LoadModulePath')(); + } + + launchMainWindow(); + + setTimeout(() => { + events.emit(APP_SHOULD_SHOW); + }, 100); + }, 300); +}; -var _events = require("events"); +exports.focusWindow = () => splashWindow?.focus?.(); +exports.pageReady = () => destroySplash() || process.nextTick(() => events.emit(APP_SHOULD_SHOW)); -var _fs = _interopRequireDefault(require("fs")); +const destroySplash = () => { + log('Splash', 'Destroy'); -var _path = _interopRequireDefault(require("path")); + stopUpdateTimeout(); + if (!splashWindow) return; -var _url = _interopRequireDefault(require("url")); + splashWindow.setSkipTaskbar(true); + setTimeout(() => { + if (!splashWindow) return; -var _Backoff = _interopRequireDefault(require("../utils/Backoff")); + splashWindow.hide(); + splashWindow.close(); + splashWindow = null; + }, 100); +}; -var moduleUpdater = _interopRequireWildcard(require("../updater/moduleUpdater")); +const launchMainWindow = () => { + log('Splash', 'Launch main'); -var paths = _interopRequireWildcard(require("../paths")); + removeModulesListeners(); -var _updater = require("../updater/updater"); + if (!launchedMainWindow && splashWindow != null) { + launchedMainWindow = true; + events.emit(APP_SHOULD_LAUNCH); + } +}; -function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } +const updateSplashState = (status) => splashWindow && splashWindow.webContents.send('SPLASH_STATE', { status, ...splashState }); -function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const launchSplashWindow = (startMinimized) => { + const windowConfig = { + width: 300, + height: process.platform === 'darwin' ? 300 : 350, + transparent: false, + frame: false, + resizable: false, + center: true, + show: false, + backgroundColor: '#2f3136', + webPreferences: { + preload: join(__dirname, 'preload.js') + } + }; -const UPDATE_TIMEOUT_WAIT = 10000; -const RETRY_CAP_SECONDS = 60; // citron note: atom seems to add about 50px height to the frame on mac but not windows -// TODO: see if we can eliminate fudge by using useContentSize BrowserWindow option + splashWindow = new BrowserWindow(windowConfig); + const win = splashWindow; + const wc = win.webContents; + + if (process.platform !== 'darwin') win.on('closed', () => { if (!launchedMainWindow) app.quit(); }); + + wc.once('dom-ready', () => { + if (oaConfig.themeSync !== false) try { // Inject themesync CSS + wc.insertCSS(JSON.parse(fs.readFileSync(join(paths.getUserData(), 'userDataCache.json'), 'utf8')).openasarSplashCSS); + } catch (e) { } + + if (oaConfig.splashText === true) try { + const buildInfo = require('../utils/buildInfo.js'); + wc.executeJavaScript(`debug.textContent = '${buildInfo.releaseChannel} ${buildInfo.version}\\nOpenAsar ${oaVersion}'`); + } catch (e) { } + }); + if (!startMinimized) win.once('ready-to-show', () => win.show()); + + win.loadURL('file:///' + join(__dirname, 'index.html')); +}; + + +const addModulesListener = (event, listener) => { + if (newUpdater) return; + modulesListeners[event] = listener; + moduleUpdater.events.addListener(event, listener); +}; + +const removeModulesListeners = () => { + if (newUpdater) return; + for (const e in modulesListeners) moduleUpdater.events.removeListener(e, modulesListeners[e]); +}; + +const startUpdateTimeout = () => !updateTimeout && (updateTimeout = setTimeout(() => scheduleUpdateCheck(), 10000)); +const stopUpdateTimeout = () => updateTimeout && clearTimeout(updateTimeout) && (updateTimeout = null); + +const scheduleUpdateCheck = () => { + updateAttempt++; + + const wait = Math.min(updateAttempt * 10, 60); + splashState.seconds = wait; + setTimeout(() => moduleUpdater.checkForUpdates(), retryInSeconds * 1000); +}; -const LOADING_WINDOW_WIDTH = 300; -const LOADING_WINDOW_HEIGHT = process.platform === 'darwin' ? 300 : 350; // TODO: addModulesListener events should use Module's constants const CHECKING_FOR_UPDATES = 'checking-for-updates'; const UPDATE_CHECK_FINISHED = 'update-check-finished'; @@ -56,35 +154,18 @@ const INSTALLING_MODULE_PROGRESS = 'installing-module-progress'; const INSTALLING_MODULES_FINISHED = 'installing-modules-finished'; const UPDATE_MANUALLY = 'update-manually'; const APP_SHOULD_LAUNCH = 'APP_SHOULD_LAUNCH'; -exports.APP_SHOULD_LAUNCH = APP_SHOULD_LAUNCH; const APP_SHOULD_SHOW = 'APP_SHOULD_SHOW'; -exports.APP_SHOULD_SHOW = APP_SHOULD_SHOW; const events = new _events.EventEmitter(); -exports.events = events; -function webContentsSend(win, event, ...args) { - // log('Splash', `Sending to webcontents:`, event, args); - - if (splashWindow != null && !splashWindow.isDestroyed() && !splashWindow.webContents.isDestroyed()) { - try { - win.webContents.send(`DISCORD_${event}`, ...args); - } catch (e) { // Mostly ignore, probably just destroyed - log('Splash', 'Failed to send to webcontents'); - } - } -} +exports.APP_SHOULD_LAUNCH = APP_SHOULD_LAUNCH; +exports.APP_SHOULD_SHOW = APP_SHOULD_SHOW; +exports.events = events; let splashWindow; let modulesListeners; let updateTimeout; -let updateAttempt; -let splashState; -let launchedMainWindow; -let restartRequired = false; let newUpdater; -const updateBackoff = new _Backoff.default(1000, 30000); // TODO(eiz): some of this logic should probably not live in the splash. -// -// Disabled because Rust interop stuff is going on in here. +const updateBackoff = new Backoff(1000, 30000); class TaskProgress { constructor() { @@ -96,10 +177,10 @@ class TaskProgress { recordProgress(progress, task) { this.allTasks.add(task.package_sha256); - if (progress.state !== _updater.TASK_STATE_WAITING) { + if (progress.state !== updater.TASK_STATE_WAITING) { this.inProgress.set(task.package_sha256, progress.percent); - if (progress.state === _updater.TASK_STATE_COMPLETE) { + if (progress.state === updater.TASK_STATE_COMPLETE) { this.finished.add(task.package_sha256); } } @@ -277,182 +358,4 @@ function initOldUpdater() { splashState.newVersion = newVersion; updateSplashState(UPDATE_MANUALLY); }); -} - -function initSplash(startMinimized = false) { - log('Splash', `Initing splash`); - - splashState = {}; - launchedMainWindow = false; - updateAttempt = 0; - newUpdater = (0, _updater.getUpdater)(); - - if (newUpdater == null) initOldUpdater(); - - launchSplashWindow(startMinimized); - - if (newUpdater != null) { - updateUntilCurrent(); - } else { - moduleUpdater.installPendingUpdates(); - } - - if (process.env.OPENASAR_QUICKSTART || oaConfig.quickstart) setTimeout(() => { - destroySplash(); - - if (newUpdater != null) { // Manually load desktop_core module path for faster requiring - require('../utils/u2LoadModulePath')(); - } - - launchMainWindow(); - - setTimeout(() => { - events.emit(APP_SHOULD_SHOW); - }, 100); - }, 50); -} - -function destroySplash() { - log('Splash', `Destroying splash`); - - stopUpdateTimeout(); - - if (splashWindow) { - splashWindow.setSkipTaskbar(true); // defer the window hiding for a short moment so it gets covered by the main window - - const _nukeWindow = () => { - if (splashWindow != null) { - splashWindow.hide(); - splashWindow.close(); - splashWindow = null; - } - }; - - setTimeout(_nukeWindow, 100); - } -} - -function addModulesListener(event, listener) { - if (newUpdater != null) return; - modulesListeners[event] = listener; - moduleUpdater.events.addListener(event, listener); -} - -function removeModulesListeners() { - if (newUpdater != null) return; - - for (const event of Object.keys(modulesListeners)) { - moduleUpdater.events.removeListener(event, modulesListeners[event]); - } -} - -function startUpdateTimeout() { - if (!updateTimeout) { - updateTimeout = setTimeout(() => scheduleUpdateCheck(), UPDATE_TIMEOUT_WAIT); - } -} - -function stopUpdateTimeout() { - if (updateTimeout) { - clearTimeout(updateTimeout); - updateTimeout = null; - } -} - -function updateSplashState(event) { - webContentsSend(splashWindow, 'SPLASH_UPDATE_STATE', { - status: event, - ...splashState - }); -} - -function launchSplashWindow(startMinimized) { - const windowConfig = { - width: LOADING_WINDOW_WIDTH, - height: LOADING_WINDOW_HEIGHT, - transparent: false, - frame: false, - resizable: false, - center: true, - show: false, - backgroundColor: '#2f3136', - webPreferences: { - nodeIntegration: false, - enableRemoteModule: false, - contextIsolation: true, - preload: _path.default.join(__dirname, 'preload.js') - } - }; - splashWindow = new _electron.BrowserWindow(windowConfig); // prevent users from dropping links to navigate in splash window - log('Splash', 'Created BrowserWindow'); - - if (process.platform !== 'darwin') { - // citron note: this causes a crash on quit while the window is open on osx - splashWindow.on('closed', () => { - splashWindow = null; - - if (!launchedMainWindow) { - // user has closed this window before we launched the app, so let's quit - _electron.app.quit(); - } - }); - } - - const win = splashWindow; - const wc = win.webContents; - - wc.once('dom-ready', () => { - if (oaConfig.themeSync !== false) try { // Inject themesync CSS - wc.insertCSS(JSON.parse(_fs.default.readFileSync(_path.default.join(paths.getUserData(), 'userDataCache.json'), 'utf8')).openasarSplashCSS); - } catch (e) { } - - if (oaConfig.splashText === true) try { - const buildInfo = require('../utils/buildInfo.js'); - wc.executeJavaScript(`debug.textContent = '${buildInfo.releaseChannel} ${buildInfo.version}\\nOpenAsar ${oaVersion}'`); - } catch (e) { } - - if (!startMinimized) win.once('ready-to-show', () => win.show()); - }); - - const splashUrl = _url.default.format({ - protocol: 'file', - slashes: true, - pathname: _path.default.join(__dirname, 'index.html') - }); - - win.loadURL(splashUrl); - - log('Splash', `Loading window (with url ${splashUrl})`); -} - -function launchMainWindow() { - removeModulesListeners(); - - if (!launchedMainWindow && splashWindow != null) { - launchedMainWindow = true; - events.emit(APP_SHOULD_LAUNCH); - } -} - -function scheduleUpdateCheck() { - // TODO: can we use backoff here? - updateAttempt += 1; - const retryInSeconds = Math.min(updateAttempt * 10, RETRY_CAP_SECONDS); - splashState.seconds = retryInSeconds; - setTimeout(() => moduleUpdater.checkForUpdates(), retryInSeconds * 1000); -} - -function focusWindow() { - log('Splash', `Told to focus splash window`); - - if (splashWindow != null) { - splashWindow.focus(); - } -} - -function pageReady() { - log('Splash', `Page ready called, destroying splash and marking app to show`); - - destroySplash(); - process.nextTick(() => events.emit(APP_SHOULD_SHOW)); } \ No newline at end of file diff --git a/src/splash/preload.js b/src/splash/preload.js index 672becc..b66416b 100644 --- a/src/splash/preload.js +++ b/src/splash/preload.js @@ -2,5 +2,5 @@ const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('DiscordSplash', { - onStateUpdate: callback => ipcRenderer.on('DISCORD_SPLASH_UPDATE_STATE', (_, state) => callback(state)) + onStateUpdate: callback => ipcRenderer.on('SPLASH_STATE', (_, state) => callback(state)) }); \ No newline at end of file