[Splash] Fix accidental push of stripped testing

main
Oj 2 years ago
parent fc4cbc7996
commit fe37f46bde

@ -1,4 +1,5 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "__esModule", {
value: true value: true
}); });
@ -6,25 +7,42 @@ exports.initSplash = initSplash;
exports.focusWindow = focusWindow; exports.focusWindow = focusWindow;
exports.pageReady = pageReady; exports.pageReady = pageReady;
exports.events = exports.APP_SHOULD_SHOW = exports.APP_SHOULD_LAUNCH = void 0; exports.events = exports.APP_SHOULD_SHOW = exports.APP_SHOULD_LAUNCH = void 0;
var _electron = require("electron"); var _electron = require("electron");
var _events = require("events"); var _events = require("events");
var _fs = _interopRequireDefault(require("fs")); var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path")); var _path = _interopRequireDefault(require("path"));
var _url = _interopRequireDefault(require("url")); var _url = _interopRequireDefault(require("url"));
var _Backoff = _interopRequireDefault(require("../utils/Backoff")); var _Backoff = _interopRequireDefault(require("../utils/Backoff"));
var moduleUpdater = _interopRequireWildcard(require("../updater/moduleUpdater")); var moduleUpdater = _interopRequireWildcard(require("../updater/moduleUpdater"));
var paths = _interopRequireWildcard(require("../paths")); var paths = _interopRequireWildcard(require("../paths"));
var _securityUtils = require("../utils/securityUtils"); var _securityUtils = require("../utils/securityUtils");
var _updater = require("../updater/updater"); var _updater = require("../updater/updater");
const ipcMain = _electron.ipcMain; const ipcMain = _electron.ipcMain;
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); } 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); }
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 _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 }; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const UPDATE_TIMEOUT_WAIT = 10000; const UPDATE_TIMEOUT_WAIT = 10000;
const RETRY_CAP_SECONDS = 60; 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 // TODO: see if we can eliminate fudge by using useContentSize BrowserWindow option
const LOADING_WINDOW_WIDTH = 300; const LOADING_WINDOW_WIDTH = 300;
const LOADING_WINDOW_HEIGHT = process.platform === 'darwin' ? 300 : 350; 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 CHECKING_FOR_UPDATES = 'checking-for-updates';
const UPDATE_CHECK_FINISHED = 'update-check-finished'; const UPDATE_CHECK_FINISHED = 'update-check-finished';
const UPDATE_FAILURE = 'update-failure'; const UPDATE_FAILURE = 'update-failure';
@ -47,15 +65,19 @@ const APP_SHOULD_SHOW = 'APP_SHOULD_SHOW';
exports.APP_SHOULD_SHOW = APP_SHOULD_SHOW; exports.APP_SHOULD_SHOW = APP_SHOULD_SHOW;
const events = new _events.EventEmitter(); const events = new _events.EventEmitter();
exports.events = events; exports.events = events;
function webContentsSend(win, event, ...args) { function webContentsSend(win, event, ...args) {
// log('Splash', `Sending to webcontents:`, event, args);
if (splashWindow != null && !splashWindow.isDestroyed() && !splashWindow.webContents.isDestroyed()) { if (splashWindow != null && !splashWindow.isDestroyed() && !splashWindow.webContents.isDestroyed()) {
try { try {
win.webContents.send(`DISCORD_${event}`, ...args); win.webContents.send(`DISCORD_${event}`, ...args);
} catch (e) { } catch (e) { // Mostly ignore, probably just destroyed
log('Splash', 'Failed to send to webcontents'); log('Splash', 'Failed to send to webcontents');
} }
} }
} }
let splashWindow; let splashWindow;
let modulesListeners; let modulesListeners;
let updateTimeout; let updateTimeout;
@ -64,30 +86,37 @@ let splashState;
let launchedMainWindow; let launchedMainWindow;
let restartRequired = false; let restartRequired = false;
let newUpdater; let newUpdater;
const updateBackoff = new _Backoff.default(1000, 30000); 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. // Disabled because Rust interop stuff is going on in here.
class TaskProgress { class TaskProgress {
constructor() { constructor() {
this.inProgress = new Map(); this.inProgress = new Map();
this.finished = new Set(); this.finished = new Set();
this.allTasks = new Set(); this.allTasks = new Set();
} }
recordProgress(progress, task) { recordProgress(progress, task) {
this.allTasks.add(task.package_sha256); 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); 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); this.finished.add(task.package_sha256);
} }
} }
} }
updateSplashState(newState) { updateSplashState(newState) {
if (this.inProgress.size > 0 && this.inProgress.size > this.finished.size) { if (this.inProgress.size > 0 && this.inProgress.size > this.finished.size) {
let totalPercent = 0; let totalPercent = 0;
for (const item of this.inProgress.values()) { for (const item of this.inProgress.values()) {
totalPercent += item; totalPercent += item;
} }
totalPercent /= this.allTasks.size; totalPercent /= this.allTasks.size;
splashState = { splashState = {
current: this.finished.size + 1, current: this.finished.size + 1,
@ -97,16 +126,21 @@ class TaskProgress {
updateSplashState(newState); updateSplashState(newState);
return true; return true;
} }
return false; return false;
} }
} }
async function updateUntilCurrent() { async function updateUntilCurrent() {
const retryOptions = { const retryOptions = {
skip_host_delta: false, skip_host_delta: false,
skip_module_delta: {} skip_module_delta: {}
}; };
while (true) { while (true) {
updateSplashState(CHECKING_FOR_UPDATES); updateSplashState(CHECKING_FOR_UPDATES);
try { try {
let installedAnything = false; let installedAnything = false;
const downloads = new TaskProgress(); const downloads = new TaskProgress();
@ -116,11 +150,14 @@ async function updateUntilCurrent() {
const downloadTask = task.HostDownload || task.ModuleDownload; const downloadTask = task.HostDownload || task.ModuleDownload;
const installTask = task.HostInstall || task.ModuleInstall; const installTask = task.HostInstall || task.ModuleInstall;
installedAnything = true; installedAnything = true;
if (downloadTask != null) { if (downloadTask != null) {
downloads.recordProgress(progress, downloadTask); downloads.recordProgress(progress, downloadTask);
} }
if (installTask != null) { if (installTask != null) {
installs.recordProgress(progress, installTask); installs.recordProgress(progress, installTask);
if (progress.state.Failed != null) { if (progress.state.Failed != null) {
if (task.HostInstall != null) { if (task.HostInstall != null) {
retryOptions.skip_host_delta = true; retryOptions.skip_host_delta = true;
@ -129,10 +166,12 @@ async function updateUntilCurrent() {
} }
} }
} }
if (!downloads.updateSplashState(DOWNLOADING_UPDATES)) { if (!downloads.updateSplashState(DOWNLOADING_UPDATES)) {
installs.updateSplashState(INSTALLING_UPDATES); installs.updateSplashState(INSTALLING_UPDATES);
} }
}); });
if (!installedAnything) { if (!installedAnything) {
await newUpdater.startCurrentVersion(); await newUpdater.startCurrentVersion();
newUpdater.setRunningInBackground(); newUpdater.setRunningInBackground();
@ -152,17 +191,20 @@ async function updateUntilCurrent() {
} }
} }
} }
const oldCheckForUpdates = () => { const oldCheckForUpdates = () => {
if (oaConfig.skipStartupUpdateChecks !== true) { if (oaConfig.skipStartupUpdateChecks !== true) {
moduleUpdater.checkForUpdates(); moduleUpdater.checkForUpdates();
} else { } else {
log('Splash', 'Skipping startup update checking (enabled)'); log('Splash', 'Skipping startup update checking (enabled)');
modulesListeners[UPDATE_CHECK_FINISHED]({ modulesListeners[UPDATE_CHECK_FINISHED]({
succeeded: true, succeeded: true,
updateCount: 0 updateCount: 0
}); });
} }
}; };
function initOldUpdater() { function initOldUpdater() {
modulesListeners = {}; modulesListeners = {};
addModulesListener(CHECKING_FOR_UPDATES, () => { addModulesListener(CHECKING_FOR_UPDATES, () => {
@ -175,6 +217,7 @@ function initOldUpdater() {
manualRequired manualRequired
}) => { }) => {
stopUpdateTimeout(); stopUpdateTimeout();
if (!succeeded) { if (!succeeded) {
scheduleUpdateCheck(); scheduleUpdateCheck();
updateSplashState(UPDATE_FAILURE); updateSplashState(UPDATE_FAILURE);
@ -210,6 +253,7 @@ function initOldUpdater() {
succeeded succeeded
}) => { }) => {
delete splashState.progress; delete splashState.progress;
if (name === 'host') { if (name === 'host') {
restartRequired = true; restartRequired = true;
} }
@ -267,44 +311,59 @@ function initOldUpdater() {
updateSplashState(UPDATE_MANUALLY); updateSplashState(UPDATE_MANUALLY);
}); });
} }
function initSplash(startMinimized = false) { function initSplash(startMinimized = false) {
log('Splash', `Initing splash`); log('Splash', `Initing splash`);
splashState = {}; splashState = {};
launchedMainWindow = false; launchedMainWindow = false;
updateAttempt = 0; updateAttempt = 0;
newUpdater = (0, _updater.getUpdater)(); newUpdater = (0, _updater.getUpdater)();
if (newUpdater == null) { if (newUpdater == null) {
initOldUpdater(); initOldUpdater();
} }
launchSplashWindow(startMinimized); launchSplashWindow(startMinimized);
log('Splash', 'Quickstart config:', process.env.OPENASAR_QUICKSTART || oaConfig.quickstart, '-', process.env.OPENASAR_QUICKSTART, oaConfig.quickstart); log('Splash', 'Quickstart config:', process.env.OPENASAR_QUICKSTART || oaConfig.quickstart, '-', process.env.OPENASAR_QUICKSTART, oaConfig.quickstart);
if (newUpdater != null) { if (newUpdater != null) {
updateUntilCurrent(); updateUntilCurrent();
} else { } else {
moduleUpdater.installPendingUpdates(); moduleUpdater.installPendingUpdates();
} }
if (process.env.OPENASAR_QUICKSTART || oaConfig.quickstart) setTimeout(() => { if (process.env.OPENASAR_QUICKSTART || oaConfig.quickstart) setTimeout(() => {
destroySplash(); destroySplash();
if (newUpdater != null) {
if (newUpdater != null) { // Manually load desktop_core module path for faster requiring
require('../utils/u2LoadModulePath')(); require('../utils/u2LoadModulePath')();
} }
/* if (newUpdater != null) { /* if (newUpdater != null) {
updateUntilCurrent(); updateUntilCurrent();
} else { } else {
moduleUpdater.installPendingUpdates(); moduleUpdater.installPendingUpdates();
moduleUpdater.setInBackground(); moduleUpdater.setInBackground();
} */ } */
launchMainWindow(); launchMainWindow();
setTimeout(() => { setTimeout(() => {
events.emit(APP_SHOULD_SHOW); events.emit(APP_SHOULD_SHOW);
}, 100); }, 100);
}, 50); }, 50);
} }
function destroySplash() { function destroySplash() {
log('Splash', `Destroying splash`); log('Splash', `Destroying splash`);
stopUpdateTimeout(); stopUpdateTimeout();
if (splashWindow) { if (splashWindow) {
splashWindow.setSkipTaskbar(true); splashWindow.setSkipTaskbar(true); // defer the window hiding for a short moment so it gets covered by the main window
const _nukeWindow = () => { const _nukeWindow = () => {
if (splashWindow != null) { if (splashWindow != null) {
splashWindow.hide(); splashWindow.hide();
@ -312,37 +371,45 @@ function destroySplash() {
splashWindow = null; splashWindow = null;
} }
}; };
setTimeout(_nukeWindow, 100); setTimeout(_nukeWindow, 100);
} }
} }
function addModulesListener(event, listener) { function addModulesListener(event, listener) {
if (newUpdater != null) return; if (newUpdater != null) return;
modulesListeners[event] = listener; modulesListeners[event] = listener;
moduleUpdater.events.addListener(event, listener); moduleUpdater.events.addListener(event, listener);
} }
function removeModulesListeners() { function removeModulesListeners() {
if (newUpdater != null) return; if (newUpdater != null) return;
for (const event of Object.keys(modulesListeners)) { for (const event of Object.keys(modulesListeners)) {
moduleUpdater.events.removeListener(event, modulesListeners[event]); moduleUpdater.events.removeListener(event, modulesListeners[event]);
} }
} }
function startUpdateTimeout() { function startUpdateTimeout() {
if (!updateTimeout) { if (!updateTimeout) {
updateTimeout = setTimeout(() => scheduleUpdateCheck(), UPDATE_TIMEOUT_WAIT); updateTimeout = setTimeout(() => scheduleUpdateCheck(), UPDATE_TIMEOUT_WAIT);
} }
} }
function stopUpdateTimeout() { function stopUpdateTimeout() {
if (updateTimeout) { if (updateTimeout) {
clearTimeout(updateTimeout); clearTimeout(updateTimeout);
updateTimeout = null; updateTimeout = null;
} }
} }
function updateSplashState(event) { function updateSplashState(event) {
webContentsSend(splashWindow, 'SPLASH_UPDATE_STATE', { webContentsSend(splashWindow, 'SPLASH_UPDATE_STATE', {
status: event, status: event,
...splashState ...splashState
}); });
} }
function launchSplashWindow(startMinimized) { function launchSplashWindow(startMinimized) {
const windowConfig = { const windowConfig = {
width: LOADING_WINDOW_WIDTH, width: LOADING_WINDOW_WIDTH,
@ -359,67 +426,90 @@ function launchSplashWindow(startMinimized) {
preload: _path.default.join(__dirname, 'preload.js') preload: _path.default.join(__dirname, 'preload.js')
} }
}; };
splashWindow = new _electron.BrowserWindow(windowConfig); splashWindow = new _electron.BrowserWindow(windowConfig); // prevent users from dropping links to navigate in splash window
log('Splash', 'Created BrowserWindow'); log('Splash', 'Created BrowserWindow');
splashWindow.webContents.on('will-navigate', e => e.preventDefault()); splashWindow.webContents.on('will-navigate', e => e.preventDefault());
splashWindow.webContents.on('new-window', (e, windowURL) => { splashWindow.webContents.on('new-window', (e, windowURL) => {
e.preventDefault(); e.preventDefault();
(0, _securityUtils.saferShellOpenExternal)(windowURL); (0, _securityUtils.saferShellOpenExternal)(windowURL); // exit, but delay half a second because openExternal is about to fire
// some events to things that are freed by app.quit.
setTimeout(_electron.app.quit, 500); setTimeout(_electron.app.quit, 500);
}); });
if (process.platform !== 'darwin') { if (process.platform !== 'darwin') {
// citron note: this causes a crash on quit while the window is open on osx
splashWindow.on('closed', () => { splashWindow.on('closed', () => {
splashWindow = null; splashWindow = null;
if (!launchedMainWindow) { if (!launchedMainWindow) {
// user has closed this window before we launched the app, so let's quit
_electron.app.quit(); _electron.app.quit();
} }
}); });
} }
ipcMain.on('DISCORD_SPLASH_SCREEN_READY', () => { ipcMain.on('DISCORD_SPLASH_SCREEN_READY', () => {
log('Splash', 'Window declared ready, showing and starting update process'); log('Splash', 'Window declared ready, showing and starting update process');
if (oaConfig.themeSync !== false) try {
if (oaConfig.themeSync !== false) try { // Inject themesync CSS
splashWindow.webContents.insertCSS(JSON.parse(_fs.default.readFileSync(_path.default.join(paths.getUserData(), 'userDataCache.json'), 'utf8')).openasarSplashCSS); splashWindow.webContents.insertCSS(JSON.parse(_fs.default.readFileSync(_path.default.join(paths.getUserData(), 'userDataCache.json'), 'utf8')).openasarSplashCSS);
} catch (e) { } } catch (e) { }
if (oaConfig.splashText === true) try { if (oaConfig.splashText === true) try {
const buildInfo = require('../utils/buildInfo.js'); const buildInfo = require('../utils/buildInfo.js');
splashWindow.webContents.executeJavaScript(`debug.textContent = '${buildInfo.releaseChannel} ${buildInfo.version}\\nOpenAsar ${oaVersion}'`); splashWindow.webContents.executeJavaScript(`debug.textContent = '${buildInfo.releaseChannel} ${buildInfo.version}\\nOpenAsar ${oaVersion}'`);
} catch (e) { } } catch (e) { }
if (splashWindow && !startMinimized) { if (splashWindow && !startMinimized) {
splashWindow.show(); splashWindow.show();
} }
}); });
ipcMain.on('DISCORD_SPLASH_SCREEN_QUIT', () => { ipcMain.on('DISCORD_SPLASH_SCREEN_QUIT', () => {
_electron.app.quit(); _electron.app.quit();
}); });
const splashUrl = _url.default.format({ const splashUrl = _url.default.format({
protocol: 'file', protocol: 'file',
slashes: true, slashes: true,
pathname: _path.default.join(__dirname, 'index.html') pathname: _path.default.join(__dirname, 'index.html')
}); });
splashWindow.loadURL(splashUrl); splashWindow.loadURL(splashUrl);
log('Splash', `Loading window (with url ${splashUrl})`); log('Splash', `Loading window (with url ${splashUrl})`);
} }
function launchMainWindow() { function launchMainWindow() {
removeModulesListeners(); removeModulesListeners();
if (!launchedMainWindow && splashWindow != null) { if (!launchedMainWindow && splashWindow != null) {
launchedMainWindow = true; launchedMainWindow = true;
events.emit(APP_SHOULD_LAUNCH); events.emit(APP_SHOULD_LAUNCH);
} }
} }
function scheduleUpdateCheck() { function scheduleUpdateCheck() {
// TODO: can we use backoff here?
updateAttempt += 1; updateAttempt += 1;
const retryInSeconds = Math.min(updateAttempt * 10, RETRY_CAP_SECONDS); const retryInSeconds = Math.min(updateAttempt * 10, RETRY_CAP_SECONDS);
splashState.seconds = retryInSeconds; splashState.seconds = retryInSeconds;
setTimeout(() => moduleUpdater.checkForUpdates(), retryInSeconds * 1000); setTimeout(() => moduleUpdater.checkForUpdates(), retryInSeconds * 1000);
} }
function focusWindow() { function focusWindow() {
log('Splash', `Told to focus splash window`); log('Splash', `Told to focus splash window`);
if (splashWindow != null) { if (splashWindow != null) {
splashWindow.focus(); splashWindow.focus();
} }
} }
function pageReady() { function pageReady() {
log('Splash', `Page ready called, destroying splash and marking app to show`); log('Splash', `Page ready called, destroying splash and marking app to show`);
destroySplash(); destroySplash();
process.nextTick(() => events.emit(APP_SHOULD_SHOW)); process.nextTick(() => events.emit(APP_SHOULD_SHOW));
} }

@ -1,8 +1,13 @@
const { contextBridge, ipcRenderer } = require('electron'); const { contextBridge, ipcRenderer } = require('electron');
const { saferShellOpenExternal } = require('../utils/securityUtils'); const { saferShellOpenExternal } = require('../utils/securityUtils');
contextBridge.exposeInMainWorld('DiscordSplash', { contextBridge.exposeInMainWorld('DiscordSplash', {
signalReady: () => ipcRenderer.send('DISCORD_SPLASH_SCREEN_READY'), signalReady: () => ipcRenderer.send('DISCORD_SPLASH_SCREEN_READY'),
onStateUpdate: callback => ipcRenderer.on('DISCORD_SPLASH_UPDATE_STATE', (_, state) => callback(state)), onStateUpdate: callback => ipcRenderer.on('DISCORD_SPLASH_UPDATE_STATE', (_, state) => callback(state)),
openUrl: saferShellOpenExternal, openUrl: saferShellOpenExternal,
quitDiscord: () => ipcRenderer.send('DISCORD_SPLASH_SCREEN_QUIT') quitDiscord: () => ipcRenderer.send('DISCORD_SPLASH_SCREEN_QUIT')
}); });
Loading…
Cancel
Save