add.[ALL]

This commit is contained in:
|| Prof. - Xadk3!#0000 || @naryal2580 2023-05-21 16:28:12 +05:30
parent 5ac24c8cea
commit 780ad9a200
54 changed files with 3733 additions and 0 deletions

View file

@ -0,0 +1,37 @@
"use strict";
var _appSettings = require("./appSettings");
// bootstrap constants
// after startup, these constants will be merged into core module constants
// since they are used in both locations (see app/Constants.js)
const {
releaseChannel
} = require('./buildInfo');
const settings = (0, _appSettings.getSettings)();
function capitalizeFirstLetter(s) {
return s.charAt(0).toUpperCase() + s.slice(1);
}
const appNameSuffix = releaseChannel === 'stable' ? '' : capitalizeFirstLetter(releaseChannel);
const APP_COMPANY = 'Discord Inc';
const APP_DESCRIPTION = 'Discord - https://discord.com';
const APP_NAME = 'Discord' + appNameSuffix;
const APP_NAME_FOR_HUMANS = 'Discord' + (appNameSuffix !== '' ? ' ' + appNameSuffix : '');
const APP_ID_BASE = 'com.squirrel';
const APP_ID = `${APP_ID_BASE}.${APP_NAME}.${APP_NAME}`;
const APP_PROTOCOL = 'Discord';
const API_ENDPOINT = settings.get('API_ENDPOINT') || 'https://discord.com/api';
const UPDATE_ENDPOINT = settings.get('UPDATE_ENDPOINT') || API_ENDPOINT;
const NEW_UPDATE_ENDPOINT = settings.get('NEW_UPDATE_ENDPOINT') || 'https://updates.discord.com/';
const bootstrapConstants = {
APP_COMPANY,
APP_DESCRIPTION,
APP_NAME,
APP_NAME_FOR_HUMANS,
APP_ID,
APP_PROTOCOL,
API_ENDPOINT,
NEW_UPDATE_ENDPOINT,
UPDATE_ENDPOINT
};
module.exports = bootstrapConstants;

View file

@ -0,0 +1,17 @@
"use strict";
// this file is here for two reasons:
// 1. web requires ./GPUSettings file from electron app (bad!), and requires are
// relative to process.main (bootstrap's index.js)
// 2. GPUSettings has been refactored into GPUSettings, and because we want to
// be able to update GPUSettings OTA, we will have the core module provide
// us with the GPUSettings
// so tl;dr this is core module's GPUSettings, providing compat for web
exports.replace = function (GPUSettings) {
// replacing module.exports directly would have no effect, since requires are cached
// so we mutate the existing object
for (const name of Object.keys(GPUSettings)) {
exports[name] = GPUSettings[name];
}
};

View file

@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getSettings = getSettings;
exports.init = init;
var _Settings = _interopRequireDefault(require("../common/Settings"));
var paths = _interopRequireWildcard(require("../common/paths"));
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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
let settings;
function init() {
settings = new _Settings.default(paths.getUserData());
}
function getSettings() {
return settings;
}

View file

@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.focusSplash = focusSplash;
exports.update = update;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var moduleUpdater = _interopRequireWildcard(require("../common/moduleUpdater"));
var paths = _interopRequireWildcard(require("../common/paths"));
var _updater = require("../common/updater");
var _appSettings = require("./appSettings");
var autoStart = _interopRequireWildcard(require("./autoStart"));
var _buildInfo = _interopRequireDefault(require("./buildInfo"));
var _errorHandler = require("./errorHandler");
var firstRun = _interopRequireWildcard(require("./firstRun"));
var splashScreen = _interopRequireWildcard(require("./splashScreen"));
var _Constants = require("./Constants");
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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// settings
const USE_PINNED_UPDATE_MANIFEST = 'USE_PINNED_UPDATE_MANIFEST';
function update(startMinimized, doneCallback, showCallback) {
const settings = (0, _appSettings.getSettings)();
if ((0, _updater.tryInitUpdater)(_buildInfo.default, _Constants.NEW_UPDATE_ENDPOINT)) {
const updater = (0, _updater.getUpdater)();
const usePinnedUpdateManifest = settings.get(USE_PINNED_UPDATE_MANIFEST);
updater.on('host-updated', () => {
autoStart.update(() => {});
});
updater.on('unhandled-exception', _errorHandler.fatal);
updater.on(_updater.INCONSISTENT_INSTALLER_STATE_ERROR, _errorHandler.fatal);
updater.on('update-error', _errorHandler.handled);
updater.on('starting-new-host', () => {
// dont run stale launch events--the host we're updating to will run its own callbacks
splashScreen.events.removeListener(splashScreen.APP_SHOULD_LAUNCH, doneCallback);
splashScreen.events.removeListener(splashScreen.APP_SHOULD_SHOW, showCallback);
});
if (usePinnedUpdateManifest) {
const manifestPath = _path.default.join(paths.getUserData(), 'pinned_update.json');
updater.setPinnedManifestSync(JSON.parse(_fs.default.readFileSync(manifestPath)));
}
firstRun.performFirstRunTasks(updater);
} else {
moduleUpdater.init(_Constants.UPDATE_ENDPOINT, settings, _buildInfo.default);
}
splashScreen.initSplash(startMinimized);
splashScreen.events.once(splashScreen.APP_SHOULD_LAUNCH, doneCallback);
splashScreen.events.once(splashScreen.APP_SHOULD_SHOW, showCallback);
}
function focusSplash() {
splashScreen.focusWindow();
}

View file

@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.install = install;
exports.isInstalled = isInstalled;
exports.uninstall = uninstall;
exports.update = update;
function install(callback) {
return callback();
}
function update(callback) {
return callback();
}
function isInstalled(callback) {
return callback(false);
}
function uninstall(callback) {
return callback();
}

View file

@ -0,0 +1,3 @@
"use strict";
module.exports = require('./' + process.platform);

View file

@ -0,0 +1,71 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.install = install;
exports.isInstalled = isInstalled;
exports.uninstall = uninstall;
exports.update = update;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _electron = require("electron");
var _buildInfo = _interopRequireDefault(require("../buildInfo"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// TODO: We should use Constant's APP_NAME, but only once
// we set up backwards compat with this.
const appName = _path.default.basename(process.execPath, '.exe');
const exePath = _electron.app.getPath('exe');
const exeDir = _path.default.dirname(exePath);
const iconPath = _path.default.join(exeDir, 'discord.png');
const autostartDir = _path.default.join(_electron.app.getPath('appData'), 'autostart');
const electronAppName = _electron.app.name ? _electron.app.name : _electron.app.getName();
const autostartFileName = _path.default.join(autostartDir, electronAppName + '-' + _buildInfo.default.releaseChannel + '.desktop');
const desktopFile = `[Desktop Entry]
Type=Application
Exec=${exePath}
Hidden=false
NoDisplay=false
Name=${appName}
Icon=${iconPath}
Comment=Text and voice chat for gamers.
X-GNOME-Autostart-enabled=true
`;
function ensureDir() {
try {
_fs.default.mkdirSync(autostartDir);
return true;
} catch (e) {
// catch for when it already exists.
}
return false;
}
function install(callback) {
// TODO: This could fail. We should read its return value
ensureDir();
try {
return _fs.default.writeFile(autostartFileName, desktopFile, callback);
} catch (e) {
// I guess we don't autostart then
return callback();
}
}
function update(callback) {
// TODO: We might need to implement this later on
return callback();
}
function isInstalled(callback) {
try {
_fs.default.stat(autostartFileName, (err, stats) => {
if (err) {
return callback(false);
}
return callback(stats.isFile());
});
} catch (e) {
return callback(false);
}
}
function uninstall(callback) {
return _fs.default.unlink(autostartFileName, callback);
}

View file

@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.install = install;
exports.isInstalled = isInstalled;
exports.uninstall = uninstall;
exports.update = update;
var _path = _interopRequireDefault(require("path"));
var windowsUtils = _interopRequireWildcard(require("../windowsUtils"));
var _appSettings = require("../appSettings");
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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const settings = (0, _appSettings.getSettings)();
// TODO: We should use Constant's APP_NAME, but only once
// we set up backwards compat with this.
const appName = _path.default.basename(process.execPath, '.exe');
const fullExeName = _path.default.basename(process.execPath);
const updatePath = _path.default.join(_path.default.dirname(process.execPath), '..', 'Update.exe');
function install(callback) {
const startMinimized = settings.get('START_MINIMIZED', false);
let execPath = `"${updatePath}" --processStart ${fullExeName}`;
if (startMinimized) {
execPath = `${execPath} --process-start-args --start-minimized`;
}
const queue = [['HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run', '/v', appName, '/d', execPath]];
windowsUtils.addToRegistry(queue, callback);
}
function update(callback) {
isInstalled(installed => {
if (installed) {
install(callback);
} else {
callback();
}
});
}
function isInstalled(callback) {
const queryValue = ['HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run', '/v', appName];
queryValue.unshift('query');
windowsUtils.spawnReg(queryValue, (error, stdout) => {
const doesOldKeyExist = stdout.indexOf(appName) >= 0;
callback(doesOldKeyExist);
});
}
function uninstall(callback) {
const queryValue = ['HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run', '/v', appName, '/f'];
queryValue.unshift('delete');
windowsUtils.spawnReg(queryValue, (error, stdout) => {
callback();
});
}

View file

@ -0,0 +1,167 @@
"use strict";
// bootstrap, or what runs before the rest of desktop does
// responsible for handling updates and updating modules before continuing startup
if (process.platform === 'linux') {
// Some people are reporting audio problems on Linux that are fixed by setting
// an environment variable PULSE_LATENCY_MSEC=30 -- the "real" fix is to see
// what conditions require this and set this then (also to set it directly in
// our webrtc setup code rather than here) but this should fix the bug for now.
if (process.env.PULSE_LATENCY_MSEC === undefined) {
process.env.PULSE_LATENCY_MSEC = 30;
}
}
const {
app,
Menu
} = require('electron');
const sentry = require('@sentry/node');
const buildInfo = require('./buildInfo');
app.setVersion(buildInfo.version);
// expose releaseChannel to a global, since it's used by splash screen
global.releaseChannel = buildInfo.releaseChannel;
const errorHandler = require('./errorHandler');
errorHandler.init();
const crashReporterSetup = require('../common/crashReporterSetup');
crashReporterSetup.init(buildInfo, sentry);
const paths = require('../common/paths');
paths.init(buildInfo);
global.moduleDataPath = paths.getModuleDataPath();
const appSettings = require('./appSettings');
appSettings.init();
const Constants = require('./Constants');
const GPUSettings = require('./GPUSettings');
function setupHardwareAcceleration() {
const settings = appSettings.getSettings();
// TODO: this is a copy of gpuSettings.getEnableHardwareAcceleration
if (!settings.get('enableHardwareAcceleration', true)) {
app.disableHardwareAcceleration();
}
}
setupHardwareAcceleration();
// [adill] work around chrome 66 disabling autoplay by default
app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required');
// WinRetrieveSuggestionsOnlyOnDemand: Work around electron 13 bug w/ async spellchecking on Windows.
// HardwareMediaKeyHandling,MediaSessionService: Prevent Discord from registering as a media service.
app.commandLine.appendSwitch('disable-features', 'WinRetrieveSuggestionsOnlyOnDemand,HardwareMediaKeyHandling,MediaSessionService');
function hasArgvFlag(flag) {
return (process.argv || []).slice(1).includes(flag);
}
console.log(`${Constants.APP_NAME} ${app.getVersion()}`);
let pendingAppQuit = false;
if (process.platform === 'win32') {
// this tells Windows (in particular Windows 10) which icon to associate your app with, important for correctly
// pinning app to task bar.
app.setAppUserModelId(Constants.APP_ID);
const {
handleStartupEvent
} = require('./squirrelUpdate');
// TODO: Isn't using argv[1] fragile?
const squirrelCommand = process.argv[1];
// TODO: Is protocol case sensitive?
if (handleStartupEvent(Constants.APP_PROTOCOL, app, squirrelCommand)) {
pendingAppQuit = true;
}
}
const appUpdater = require('./appUpdater');
const moduleUpdater = require('../common/moduleUpdater');
const updater = require('../common/updater');
const splashScreen = require('./splashScreen');
const autoStart = require('./autoStart');
const requireNative = require('./requireNative');
let coreModule;
const allowMultipleInstances = hasArgvFlag('--multi-instance');
const isFirstInstance = allowMultipleInstances ? true : app.requestSingleInstanceLock();
function extractUrlFromArgs(args) {
const urlArgIndex = args.indexOf('--url');
if (urlArgIndex < 0) {
return null;
}
const passThroughArgsIndex = args.indexOf('--');
if (passThroughArgsIndex < 0 || passThroughArgsIndex < urlArgIndex) {
return null;
}
const url = args[passThroughArgsIndex + 1];
if (url == null) {
return null;
}
return url;
}
let initialUrl = extractUrlFromArgs(process.argv);
if (!allowMultipleInstances) {
app.on('second-instance', (_event, args, _workingDirectory) => {
if (args != null && args.indexOf('--squirrel-uninstall') > -1) {
app.quit();
return;
}
const url = extractUrlFromArgs(args);
if (coreModule) {
// url can be null, as a user opening the executable again will focus the app from background
coreModule.handleOpenUrl(url);
} else if (url != null) {
initialUrl = url;
}
if (!coreModule) {
appUpdater.focusSplash();
}
});
}
app.on('will-finish-launching', () => {
// on macos protocol links are handled entirely through this event
app.on('open-url', (event, url) => {
event.preventDefault();
if (coreModule) {
coreModule.handleOpenUrl(url);
} else {
initialUrl = url;
}
});
});
function startUpdate() {
console.log('Starting updater.');
const startMinimized = hasArgvFlag('--start-minimized');
appUpdater.update(startMinimized, () => {
try {
coreModule = requireNative('discord_desktop_core');
coreModule.startup({
paths,
splashScreen,
moduleUpdater,
autoStart,
buildInfo,
appSettings,
Constants,
GPUSettings,
updater,
crashReporterSetup
});
if (initialUrl != null) {
coreModule.handleOpenUrl(initialUrl);
initialUrl = null;
}
} catch (err) {
return errorHandler.fatal(err);
}
}, () => {
coreModule.setMainWindowVisible(!startMinimized);
});
}
function startApp() {
console.log('Starting app.');
paths.cleanOldVersions(buildInfo);
const startupMenu = require('./startupMenu');
Menu.setApplicationMenu(startupMenu);
startUpdate();
}
if (pendingAppQuit) {
console.log('Startup prevented.');
} else if (!isFirstInstance && !allowMultipleInstances) {
console.log('Quitting secondary instance.');
app.quit();
} else {
app.whenReady().then(() => startApp());
}

View file

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _path = _interopRequireDefault(require("path"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const buildInfo = require(_path.default.join(process.resourcesPath, 'build_info.json'));
var _default = buildInfo;
exports.default = _default;
module.exports = exports.default;

View file

@ -0,0 +1,14 @@
[
"Upsorbing the Contents",
"Additive Parsing the Load",
"Commence Monosaturated Goodening",
"Kick Off the Multi-Core Widening",
"Bastening the Game Turkey",
"Abstracting the Rummage Disc",
"Undecerealenizing the Process",
"Postrefragmenting the Widget Layer",
"Satisfying the Constraints",
"Abnoramalzing Some of the Matrices",
"Optimizing the People",
"Proclaigerizing the Network"
]

View file

@ -0,0 +1,85 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fatal = fatal;
exports.handled = handled;
exports.init = init;
var Sentry = _interopRequireWildcard(require("@sentry/node"));
var _electron = require("electron");
var _process = _interopRequireDefault(require("process"));
var _crashReporterSetup = require("../common/crashReporterSetup");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
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; }
const HANDLED_ERROR_INTERVAL = 3;
const HANDLED_ERROR_LIMIT = 10;
let handledErrorCounter = 0;
let totalHandledErrors = 0;
const consoleOutputOnly = _process.default.env.DISCORD_TEST != null;
function isErrorSafeToSuppress(error) {
return /attempting to call a function in a renderer window/i.test(error.message);
}
function captureJSException(error) {
Sentry.captureException(error, scope => {
scope.clear();
scope.setTag('nativeBuildNumber', _crashReporterSetup.metadata.nativeBuildNumber);
scope.setUser(_crashReporterSetup.metadata.sentry.user);
scope.setExtras({
environment: _crashReporterSetup.metadata.sentry.environment,
release: _crashReporterSetup.metadata.sentry.release,
nativeBuildNumber: _crashReporterSetup.metadata.nativeBuildNumber
});
return scope;
});
}
function init() {
_process.default.on('uncaughtException', error => {
const stack = error.stack ? error.stack : String(error);
const message = `Uncaught exception:\n ${stack}`;
console.warn(message);
captureJSException(error);
if (!isErrorSafeToSuppress(error)) {
if (consoleOutputOnly) {
console.error(`${message} error: ${error}`);
_process.default.exit(-1);
}
_electron.dialog.showErrorBox('A JavaScript error occurred in the main process', message);
}
});
}
// show a similar error message to the error handler, except exit out the app
// after the error message has been closed
function fatal(err) {
const options = {
type: 'error',
message: 'A fatal Javascript error occured',
detail: err && err.stack ? err.stack : String(err)
};
if (consoleOutputOnly) {
console.error(`fatal: ${err}\n${err === null || err === void 0 ? void 0 : err.stack}`);
_process.default.exit(-1);
}
const callback = _ => _electron.app.quit();
const electronMajor = parseInt(_process.default.versions.electron.split('.')[0]);
if (electronMajor >= 6) {
_electron.dialog.showMessageBox(null, options).then(callback);
} else {
_electron.dialog.showMessageBox(options, callback);
}
captureJSException(err);
}
// capture a handled error for telemetry purposes, e.g. finding update loops.
function handled(err) {
if (global.releaseChannel !== 'ptb' && global.releaseChannel !== 'canary' && global.releaseChannel !== 'development') {
return;
}
if (totalHandledErrors < HANDLED_ERROR_LIMIT && handledErrorCounter++ % HANDLED_ERROR_INTERVAL == 0) {
console.warn('Reporting non-fatal error', err);
captureJSException(err);
totalHandledErrors++;
}
}

View file

@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.performFirstRunTasks = performFirstRunTasks;
function performFirstRunTasks(_updater) {
//
}

View file

@ -0,0 +1,3 @@
"use strict";
module.exports = require('./' + process.platform);

View file

@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.performFirstRunTasks = performFirstRunTasks;
function performFirstRunTasks(_updater) {
//
}

View file

@ -0,0 +1,75 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.performFirstRunTasks = performFirstRunTasks;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var paths = _interopRequireWildcard(require("../../common/paths"));
var _errorHandler = require("../errorHandler");
var _squirrelUpdate = require("../squirrelUpdate");
var _Constants = require("../Constants");
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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const appFolder = _path.default.resolve(process.execPath, '..');
const rootFolder = _path.default.resolve(appFolder, '..');
const exeName = _path.default.basename(process.execPath);
const updateExe = _path.default.join(rootFolder, 'Update.exe');
function copyIconToRoot() {
const icoSrc = _path.default.join(appFolder, 'app.ico');
const icoDest = _path.default.join(rootFolder, 'app.ico');
try {
const ico = _fs.default.readFileSync(icoSrc);
_fs.default.writeFileSync(icoDest, ico);
return icoDest;
} catch (e) {
return icoSrc;
}
}
function updateShortcuts(updater) {
const shortcutFileName = `${_Constants.APP_NAME_FOR_HUMANS}.lnk`;
const shortcutPaths = [_path.default.join(updater.getKnownFolder('desktop'), shortcutFileName), _path.default.join(updater.getKnownFolder('programs'), _Constants.APP_COMPANY, shortcutFileName)];
const iconPath = copyIconToRoot();
for (const shortcutPath of shortcutPaths) {
if (!_fs.default.existsSync(shortcutPath)) {
// If the user deleted the shortcut, don't recreate it.
continue;
}
updater.createShortcut({
/* eslint-disable camelcase */
target_path: updateExe,
shortcut_path: shortcutPath,
arguments: `--processStart ${exeName}`,
icon_path: iconPath,
icon_index: 0,
description: _Constants.APP_DESCRIPTION,
app_user_model_id: _Constants.APP_ID,
working_directory: appFolder
/* eslint-enable camelcase */
});
}
}
function performFirstRunTasks(updater) {
const firstRunCompletePath = _path.default.join(paths.getUserDataVersioned(), '.first-run');
if (!_fs.default.existsSync(firstRunCompletePath)) {
let updatedShortcuts = false;
try {
updateShortcuts(updater);
updatedShortcuts = true;
} catch (e) {
(0, _errorHandler.handled)(e);
}
(0, _squirrelUpdate.installProtocol)(_Constants.APP_PROTOCOL, () => {
try {
if (updatedShortcuts) {
_fs.default.writeFileSync(firstRunCompletePath, 'true');
}
} catch (e) {
(0, _errorHandler.handled)(e);
}
});
}
}

View file

@ -0,0 +1,164 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _electron = require("electron");
var _events = require("events");
var _request = _interopRequireDefault(require("./request"));
var squirrelUpdate = _interopRequireWildcard(require("./squirrelUpdate"));
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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable no-console */
function versionParse(verString) {
return verString.split('.').map(i => parseInt(i));
}
function versionNewer(verA, verB) {
let i = 0;
while (true) {
const a = verA[i];
const b = verB[i];
i++;
if (a === undefined) {
return false;
} else {
if (b === undefined || a > b) {
return true;
}
if (a < b) {
return false;
}
}
}
}
class AutoUpdaterWin32 extends _events.EventEmitter {
constructor() {
super();
this.updateUrl = null;
this.updateVersion = null;
}
setFeedURL(updateUrl) {
this.updateUrl = updateUrl;
}
quitAndInstall() {
if (squirrelUpdate.updateExistsSync()) {
squirrelUpdate.restart(_electron.app, this.updateVersion ?? _electron.app.getVersion());
} else {
/* eslint-disable-next-line */
require('auto-updater').quitAndInstall();
}
}
downloadAndInstallUpdate(callback) {
squirrelUpdate.spawnUpdateInstall(this.updateUrl, progress => {
this.emit('update-progress', progress);
}).catch(err => callback(err)).then(() => callback());
}
checkForUpdates() {
if (this.updateUrl == null) {
throw new Error('Update URL is not set');
}
this.emit('checking-for-update');
if (!squirrelUpdate.updateExistsSync()) {
this.emit('update-not-available');
return;
}
squirrelUpdate.spawnUpdate(['--check', this.updateUrl], (error, stdout) => {
if (error != null) {
this.emit('error', error);
return;
}
try {
// Last line of the output is JSON details about the releases
const json = stdout.trim().split('\n').pop();
const releasesFound = JSON.parse(json).releasesToApply;
if (releasesFound == null || releasesFound.length === 0) {
this.emit('update-not-available');
return;
}
const update = releasesFound.pop();
this.emit('update-available');
this.downloadAndInstallUpdate(error => {
if (error != null) {
this.emit('error', error);
return;
}
this.updateVersion = update.version;
this.emit('update-downloaded', {}, update.release, update.version, new Date(), this.updateUrl, this.quitAndInstall.bind(this));
});
} catch (error) {
error.stdout = stdout;
this.emit('error', error);
}
});
}
}
// todo
class AutoUpdaterLinux extends _events.EventEmitter {
constructor() {
super();
this.updateUrl = null;
}
setFeedURL(url) {
this.updateUrl = url;
}
quitAndInstall() {
// Just restart. The splash screen will hit the update manually state and
// prompt the user to download the new package.
_electron.app.relaunch();
_electron.app.quit();
}
async checkForUpdates() {
const currVersion = versionParse(_electron.app.getVersion());
this.emit('checking-for-update');
try {
const response = await _request.default.get(this.updateUrl);
if (response.statusCode === 204) {
// you are up to date
this.emit('update-not-available');
return;
}
let latestVerStr = '';
let latestVersion = [];
try {
const latestMetadata = JSON.parse(response.body);
latestVerStr = latestMetadata.name;
latestVersion = versionParse(latestVerStr);
} catch (_) {}
if (versionNewer(latestVersion, currVersion)) {
console.log('[Updates] You are out of date!');
// you need to update
this.emit('update-manually', latestVerStr);
} else {
console.log('[Updates] You are living in the future!');
this.emit('update-not-available');
}
} catch (err) {
console.error('[Updates] Error fetching ' + this.updateUrl + ': ' + err.message);
this.emit('error', err);
}
}
}
let autoUpdater;
// TODO
// events: checking-for-update, update-available, update-not-available, update-manually, update-downloaded, error
// also, checkForUpdates, setFeedURL, quitAndInstall
// also, see electron.autoUpdater, and its API
switch (process.platform) {
case 'darwin':
autoUpdater = require('electron').autoUpdater;
break;
case 'win32':
autoUpdater = new AutoUpdaterWin32();
break;
case 'linux':
autoUpdater = new AutoUpdaterLinux();
break;
}
var _default = autoUpdater;
exports.default = _default;
module.exports = exports.default;

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View file

@ -0,0 +1,39 @@
"use strict";
const buildInfo = require('./buildInfo');
const paths = require('../common/paths');
paths.init(buildInfo);
const moduleUpdater = require('../common/moduleUpdater');
const updater = require('../common/updater');
const requireNative = require('./requireNative');
function getAppMode() {
if (process.argv && process.argv.includes('--overlay-host')) {
return 'overlay-host';
}
return 'app';
}
const mode = getAppMode();
if (mode === 'app') {
require('./bootstrap');
} else if (mode === 'overlay-host') {
// Initialize the update system just enough to find installed native modules.
const appSettings = require('./appSettings');
appSettings.init();
const {
NEW_UPDATE_ENDPOINT
} = require('./Constants');
if (buildInfo.newUpdater) {
if (!updater.tryInitUpdater(buildInfo, NEW_UPDATE_ENDPOINT)) {
throw new Error('Failed to initialize modules in overlay host.');
}
// Load the module search path but if there's a pending host update, don't
// restart into it.
updater.getUpdater().startCurrentVersionSync({
allowObsoleteHost: true
});
} else {
moduleUpdater.initPathsOnly(buildInfo);
}
requireNative('discord_overlay2/standalone_host.js');
}

View file

@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
// used in devtools to hook in additional dev tools
// require('electron').remote.require('./installDevTools')()
function installDevTools() {
console.log(`Installing Devtron`);
const devtron = require('devtron');
devtron.uninstall();
devtron.install();
console.log(`Installed Devtron`);
}
var _default = installDevTools;
exports.default = _default;
module.exports = exports.default;

View file

@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _electron = require("electron");
var _default = {
on: (event, callback) => _electron.ipcMain.on(`DISCORD_${event}`, callback),
removeListener: (event, callback) => _electron.ipcMain.removeListener(`DISCORD_${event}`, callback)
};
exports.default = _default;
module.exports = exports.default;

View file

@ -0,0 +1,162 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _electron = require("electron");
var _querystring = _interopRequireDefault(require("querystring"));
var _request = _interopRequireDefault(require("request"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const DEFAULT_REQUEST_TIMEOUT = 30000;
function makeHTTPResponse({
method,
url,
headers,
statusCode,
statusMessage
}, body) {
return {
method,
url,
headers,
statusCode,
statusMessage,
body
};
}
function makeHTTPStatusError(response) {
const err = new Error(`HTTP Error: Status Code ${response.statusCode}`);
err.response = response;
return err;
}
function handleHTTPResponse(resolve, reject, response, stream) {
const totalBytes = parseInt(response.headers['content-length'] || 1, 10);
let receivedBytes = 0;
const chunks = [];
// don't stream response if it's a failure
if (response.statusCode >= 300) {
stream = null;
}
response.on('data', chunk => {
if (stream != null) {
receivedBytes += chunk.length;
stream.write(chunk);
stream.emit('progress', {
totalBytes,
receivedBytes
});
return;
}
chunks.push(chunk);
});
response.on('end', () => {
if (stream != null) {
stream.on('finish', () => resolve(makeHTTPResponse(response, null)));
stream.end();
return;
}
const res = makeHTTPResponse(response, Buffer.concat(chunks));
if (res.statusCode >= 300) {
reject(makeHTTPStatusError(res));
return;
}
resolve(res);
});
}
function nodeRequest({
method,
url,
headers,
qs,
timeout,
body,
stream
}) {
return new Promise((resolve, reject) => {
const req = (0, _request.default)({
method,
url,
qs,
headers,
followAllRedirects: true,
encoding: null,
timeout: timeout != null ? timeout : DEFAULT_REQUEST_TIMEOUT,
body
});
req.on('response', response => handleHTTPResponse(resolve, reject, response, stream));
req.on('error', err => reject(err));
});
}
async function electronRequest({
method,
url,
headers,
qs,
timeout,
body,
stream
}) {
await _electron.app.whenReady();
const {
net,
session
} = require('electron');
const req = net.request({
method,
url: `${url}${qs != null ? `?${_querystring.default.stringify(qs)}` : ''}`,
redirect: 'follow',
session: session.defaultSession
});
if (headers != null) {
for (const headerKey of Object.keys(headers)) {
req.setHeader(headerKey, headers[headerKey]);
}
}
if (body != null) {
req.write(body, 'utf-8');
}
return new Promise((resolve, reject) => {
const reqTimeout = setTimeout(() => {
req.abort();
reject(new Error(`network timeout: ${url}`));
}, timeout != null ? timeout : DEFAULT_REQUEST_TIMEOUT);
req.on('login', (authInfo, callback) => callback());
req.on('response', response => {
clearTimeout(reqTimeout);
handleHTTPResponse(resolve, reject, response, stream);
});
req.on('error', err => {
clearTimeout(reqTimeout);
reject(err);
});
req.end();
});
}
async function requestWithMethod(method, options) {
if (typeof options === 'string') {
options = {
url: options
};
}
options = {
...options,
method
};
try {
return await electronRequest(options);
} catch (err) {
console.log(`Error downloading with electron net: ${err.message}`);
console.log('Falling back to node net library..');
}
return nodeRequest(options);
}
// only supports get for now, since retrying is non-idempotent and
// we'd want to grovel the errors to make sure it's safe to retry
var _default = {
get: requestWithMethod.bind(null, 'GET')
};
exports.default = _default;
module.exports = exports.default;

View file

@ -0,0 +1,5 @@
"use strict";
// require(), with paths specialized for requiring only native modules.
module.paths = [];
module.exports = require;

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Discord Updater</title>
</head>
<body>
<div id="splash-mount"></div>
<script src="index.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,6 @@
{
"width": "300px",
"height": "300px",
"inDuration": 700,
"outDuration": 333
}

View file

@ -0,0 +1,421 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.events = exports.APP_SHOULD_SHOW = exports.APP_SHOULD_LAUNCH = void 0;
exports.focusWindow = focusWindow;
exports.initSplash = initSplash;
exports.pageReady = pageReady;
var _electron = require("electron");
var _events = require("events");
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _url = _interopRequireDefault(require("url"));
var _Backoff = _interopRequireDefault(require("../common/Backoff"));
var moduleUpdater = _interopRequireWildcard(require("../common/moduleUpdater"));
var paths = _interopRequireWildcard(require("../common/paths"));
var _securityUtils = require("../common/securityUtils");
var _updater = require("../common/updater");
var _ipcMain = _interopRequireDefault(require("./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 _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 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
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';
const UPDATE_FAILURE = 'update-failure';
const LAUNCHING = 'launching';
const DOWNLOADING_MODULE = 'downloading-module';
const DOWNLOADING_UPDATES = 'downloading-updates';
const DOWNLOADING_MODULES_FINISHED = 'downloading-modules-finished';
const DOWNLOADING_MODULE_PROGRESS = 'downloading-module-progress';
const DOWNLOADED_MODULE = 'downloaded-module';
const NO_PENDING_UPDATES = 'no-pending-updates';
const INSTALLING_MODULE = 'installing-module';
const INSTALLING_UPDATES = 'installing-updates';
const INSTALLED_MODULE = 'installed-module';
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) {
if (win != null && win.webContents != null) {
win.webContents.send(`DISCORD_${event}`, ...args);
}
}
let splashWindow;
let modulesListeners;
let updateTimeout;
let updateAttempt;
let splashState;
let launchedMainWindow;
let quoteCachePath;
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.
/* eslint-disable camelcase */
class TaskProgress {
constructor() {
this.inProgress = new Map();
this.finished = new Set();
this.allTasks = new Set();
}
recordProgress(progress, task) {
this.allTasks.add(task.package_sha256);
if (progress.state !== _updater.TASK_STATE_WAITING) {
this.inProgress.set(task.package_sha256, progress.percent);
if (progress.state === _updater.TASK_STATE_COMPLETE) {
this.finished.add(task.package_sha256);
}
}
}
updateSplashState(newState) {
if (this.inProgress.size > 0 && this.inProgress.size > this.finished.size) {
let totalPercent = 0;
for (const item of this.inProgress.values()) {
totalPercent += item;
}
totalPercent /= this.allTasks.size;
splashState = {
current: this.finished.size + 1,
total: this.allTasks.size,
progress: totalPercent
};
updateSplashState(newState);
return true;
}
return false;
}
}
async function updateUntilCurrent() {
const retryOptions = {
skip_host_delta: false,
skip_module_delta: {}
};
while (true) {
updateSplashState(CHECKING_FOR_UPDATES);
try {
let installedAnything = false;
const downloads = new TaskProgress();
const installs = new TaskProgress();
await newUpdater.updateToLatestWithOptions(retryOptions, progress => {
const task = progress.task;
const downloadTask = task.HostDownload || task.ModuleDownload;
const installTask = task.HostInstall || task.ModuleInstall;
installedAnything = true;
if (downloadTask != null) {
downloads.recordProgress(progress, downloadTask);
}
if (installTask != null) {
installs.recordProgress(progress, installTask);
if (progress.state.Failed != null) {
if (task.HostInstall != null) {
retryOptions.skip_host_delta = true;
} else if (task.ModuleInstall != null) {
retryOptions.skip_module_delta[installTask.version.module.name] = true;
}
}
}
if (!downloads.updateSplashState(DOWNLOADING_UPDATES)) {
installs.updateSplashState(INSTALLING_UPDATES);
}
});
if (!installedAnything) {
await newUpdater.startCurrentVersion();
newUpdater.setRunningInBackground();
newUpdater.collectGarbage();
launchMainWindow();
updateBackoff.succeed();
updateSplashState(LAUNCHING);
return;
}
} catch (e) {
console.error('Update failed', e);
await new Promise(resolve => {
const delayMs = updateBackoff.fail(resolve);
splashState.seconds = Math.round(delayMs / 1000);
updateSplashState(UPDATE_FAILURE);
});
}
}
}
/* eslint-enable camelcase */
function initOldUpdater() {
modulesListeners = {};
addModulesListener(CHECKING_FOR_UPDATES, () => {
startUpdateTimeout();
updateSplashState(CHECKING_FOR_UPDATES);
});
addModulesListener(UPDATE_CHECK_FINISHED, ({
succeeded,
updateCount,
manualRequired
}) => {
stopUpdateTimeout();
if (!succeeded) {
scheduleUpdateCheck();
updateSplashState(UPDATE_FAILURE);
} else if (updateCount === 0) {
moduleUpdater.setInBackground();
launchMainWindow();
updateSplashState(LAUNCHING);
}
});
addModulesListener(DOWNLOADING_MODULE, ({
name,
current,
total
}) => {
stopUpdateTimeout();
splashState = {
current,
total
};
updateSplashState(DOWNLOADING_UPDATES);
});
addModulesListener(DOWNLOADING_MODULE_PROGRESS, ({
name,
progress
}) => {
splashState.progress = progress;
updateSplashState(DOWNLOADING_UPDATES);
});
addModulesListener(DOWNLOADED_MODULE, ({
name,
current,
total,
succeeded
}) => {
delete splashState.progress;
if (name === 'host') {
restartRequired = true;
}
});
addModulesListener(DOWNLOADING_MODULES_FINISHED, ({
succeeded,
failed
}) => {
if (failed > 0) {
scheduleUpdateCheck();
updateSplashState(UPDATE_FAILURE);
} else {
process.nextTick(() => {
if (restartRequired) {
moduleUpdater.quitAndInstallUpdates();
} else {
moduleUpdater.installPendingUpdates();
}
});
}
});
addModulesListener(NO_PENDING_UPDATES, () => moduleUpdater.checkForUpdates());
addModulesListener(INSTALLING_MODULE, ({
name,
current,
total
}) => {
splashState = {
current,
total
};
updateSplashState(INSTALLING_UPDATES);
});
addModulesListener(INSTALLED_MODULE, ({
name,
current,
total,
succeeded
}) => delete splashState.progress);
addModulesListener(INSTALLING_MODULE_PROGRESS, ({
name,
progress
}) => {
splashState.progress = progress;
updateSplashState(INSTALLING_UPDATES);
});
addModulesListener(INSTALLING_MODULES_FINISHED, ({
succeeded,
failed
}) => moduleUpdater.checkForUpdates());
addModulesListener(UPDATE_MANUALLY, ({
newVersion
}) => {
splashState.newVersion = newVersion;
updateSplashState(UPDATE_MANUALLY);
});
}
function initSplash(startMinimized = false) {
splashState = {};
launchedMainWindow = false;
updateAttempt = 0;
newUpdater = (0, _updater.getUpdater)();
if (newUpdater == null) {
initOldUpdater();
}
launchSplashWindow(startMinimized);
quoteCachePath = _path.default.join(paths.getUserData(), 'quotes.json');
_ipcMain.default.on('UPDATED_QUOTES', (_event, quotes) => cacheLatestQuotes(quotes));
}
function destroySplash() {
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) {
if (splashWindow != null && !splashWindow.isDestroyed() && !splashWindow.webContents.isDestroyed()) {
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,
webPreferences: {
nodeIntegration: false,
sandbox: false,
enableRemoteModule: false,
contextIsolation: true,
preload: _path.default.join(__dirname, 'splashScreenPreload.js')
}
};
splashWindow = new _electron.BrowserWindow(windowConfig);
// prevent users from dropping links to navigate in splash window
splashWindow.webContents.on('will-navigate', e => e.preventDefault());
splashWindow.webContents.on('new-window', (e, windowURL) => {
e.preventDefault();
(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);
});
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();
}
});
}
_ipcMain.default.on('SPLASH_SCREEN_READY', () => {
const cachedQuote = chooseCachedQuote();
if (cachedQuote) {
webContentsSend(splashWindow, 'SPLASH_SCREEN_QUOTE', cachedQuote);
}
if (splashWindow && !startMinimized) {
splashWindow.show();
}
if (newUpdater != null) {
updateUntilCurrent();
} else {
moduleUpdater.installPendingUpdates();
}
});
_ipcMain.default.on('SPLASH_SCREEN_QUIT', () => {
_electron.app.quit();
});
const splashUrl = _url.default.format({
protocol: 'file',
slashes: true,
pathname: _path.default.join(__dirname, 'splash', 'index.html')
});
splashWindow.loadURL(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() {
if (splashWindow != null) {
splashWindow.focus();
}
}
function pageReady() {
destroySplash();
process.nextTick(() => events.emit(APP_SHOULD_SHOW));
}
function cacheLatestQuotes(quotes) {
_fs.default.writeFile(quoteCachePath, JSON.stringify(quotes), e => {
if (e) {
console.warn('Failed updating quote cache with error: ', e);
}
});
}
function chooseCachedQuote() {
let cachedQuote = null;
try {
const cachedQuotes = JSON.parse(_fs.default.readFileSync(quoteCachePath));
cachedQuote = cachedQuotes[Math.floor(Math.random() * cachedQuotes.length)];
} catch (_err) {}
return cachedQuote;
}

View file

@ -0,0 +1,33 @@
"use strict";
const {
app,
contextBridge,
ipcRenderer
} = require('electron');
const {
saferShellOpenExternal
} = require('../common/securityUtils');
contextBridge.exposeInMainWorld('DiscordSplash', {
getReleaseChannel: () => {
const buildInfo = require('./buildInfo');
return buildInfo.releaseChannel;
},
signalReady: () => {
ipcRenderer.send('DISCORD_SPLASH_SCREEN_READY');
},
onStateUpdate: callback => {
ipcRenderer.on('DISCORD_SPLASH_UPDATE_STATE', (_, state) => {
callback(state);
});
},
onQuoteUpdate: callback => {
ipcRenderer.on('DISCORD_SPLASH_SCREEN_QUOTE', (_, quote) => {
callback(quote);
});
},
openUrl: saferShellOpenExternal,
quitDiscord: () => {
ipcRenderer.send('DISCORD_SPLASH_SCREEN_QUIT');
}
});

View file

@ -0,0 +1,189 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.handleStartupEvent = handleStartupEvent;
exports.installProtocol = installProtocol;
exports.restart = restart;
exports.spawnUpdate = spawnUpdate;
exports.spawnUpdateInstall = spawnUpdateInstall;
exports.updateExistsSync = updateExistsSync;
var _child_process = _interopRequireDefault(require("child_process"));
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var autoStart = _interopRequireWildcard(require("./autoStart"));
var windowsUtils = _interopRequireWildcard(require("./windowsUtils"));
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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// citron note: this assumes the execPath is in the format Discord/someVersion/Discord.exe
const appFolder = _path.default.resolve(process.execPath, '..');
const rootFolder = _path.default.resolve(appFolder, '..');
const exeName = _path.default.basename(process.execPath);
const updateExe = _path.default.join(rootFolder, 'Update.exe');
// Specialized spawn function specifically used for spawning the updater in
// update mode. Calls back with progress percentages.
// Returns Promise.
function spawnUpdateInstall(updateUrl, progressCallback) {
return new Promise((resolve, reject) => {
const proc = _child_process.default.spawn(updateExe, ['--update', updateUrl]);
proc.on('error', reject);
proc.on('exit', code => {
if (code !== 0) {
return reject(new Error(`Update failed with exit code ${code}`));
}
return resolve();
});
let lastProgress = -1;
function parseProgress() {
const lines = stdout.split(/\r?\n/);
if (lines.length === 1) return;
// return the last (possibly incomplete) line to stdout for parsing again
stdout = lines.pop();
let currentProgress;
for (const line of lines) {
if (!/^\d\d?$/.test(line)) continue;
const progress = Number(line);
// make sure that this number is steadily increasing
if (lastProgress > progress) continue;
currentProgress = progress;
}
if (currentProgress == null) return;
lastProgress = currentProgress;
progressCallback(Math.min(currentProgress, 100));
}
let stdout = '';
proc.stdout.on('data', chunk => {
stdout += String(chunk);
parseProgress();
});
});
}
// Spawn the Update.exe with the given arguments and invoke the callback when
// the command completes.
function spawnUpdate(args, callback) {
windowsUtils.spawn(updateExe, args, callback);
}
// Create a desktop and start menu shortcut by using the command line API
// provided by Squirrel's Update.exe
function createShortcuts(callback, updateOnly) {
// move icon out to a more stable location, to keep shortcuts from breaking as much
const icoSrc = _path.default.join(appFolder, 'app.ico');
const icoDest = _path.default.join(rootFolder, 'app.ico');
let icoForTarget = icoDest;
try {
const ico = _fs.default.readFileSync(icoSrc);
_fs.default.writeFileSync(icoDest, ico);
} catch (e) {
// if we can't write there for some reason, just use the source.
icoForTarget = icoSrc;
}
const createShortcutArgs = ['--createShortcut', exeName, '--setupIcon', icoForTarget];
if (updateOnly) {
createShortcutArgs.push('--updateOnly');
}
spawnUpdate(createShortcutArgs, callback);
}
// Add a protocol registration for this application.
function installProtocol(protocol, callback) {
const queue = [['HKCU\\Software\\Classes\\' + protocol, '/ve', '/d', `URL:${protocol} Protocol`], ['HKCU\\Software\\Classes\\' + protocol, '/v', 'URL Protocol'], ['HKCU\\Software\\Classes\\' + protocol + '\\DefaultIcon', '/ve', '/d', '"' + process.execPath + '",-1'], ['HKCU\\Software\\Classes\\' + protocol + '\\shell\\open\\command', '/ve', '/d', `"${process.execPath}" --url -- "%1"`]];
windowsUtils.addToRegistry(queue, callback);
}
function terminate(app) {
app.quit();
process.exit(0);
}
// Remove the desktop and start menu shortcuts by using the command line API
// provided by Squirrel's Update.exe
function removeShortcuts(callback) {
spawnUpdate(['--removeShortcut', exeName], callback);
}
// Update the desktop and start menu shortcuts by using the command line API
// provided by Squirrel's Update.exe
function updateShortcuts(callback) {
createShortcuts(callback, true);
}
// Purge the protocol for this applicationstart.
function uninstallProtocol(protocol, callback) {
windowsUtils.spawnReg(['delete', 'HKCU\\Software\\Classes\\' + protocol, '/f'], callback);
}
function maybeInstallNewUpdaterSeedDb() {
const installerDbSrc = _path.default.join(appFolder, 'installer.db');
const installerDbDest = _path.default.join(rootFolder, 'installer.db');
if (_fs.default.existsSync(installerDbSrc)) {
_fs.default.renameSync(installerDbSrc, installerDbDest);
}
}
// Handle squirrel events denoted by --squirrel-* command line arguments.
// returns `true` if regular startup should be prevented
function handleStartupEvent(protocol, app, squirrelCommand) {
switch (squirrelCommand) {
case '--squirrel-install':
createShortcuts(() => {
autoStart.install(() => {
installProtocol(protocol, () => {
terminate(app);
});
});
}, false);
return true;
case '--squirrel-updated':
updateShortcuts(() => {
autoStart.update(() => {
installProtocol(protocol, () => {
terminate(app);
});
});
});
return true;
case '--squirrel-uninstall':
removeShortcuts(() => {
autoStart.uninstall(() => {
uninstallProtocol(protocol, () => {
terminate(app);
});
});
});
return true;
case '--squirrel-obsolete':
terminate(app);
return true;
case '--squirrel-firstrun':
// Squirrel doesn't have a way to include app-level files. We get around
// this for new updater hosts, which rely on a seeded manifest, by
// bubbling the db up from the versioned-app directory if it exists.
//
// Additionally, we run this in --squirrel-firstrun, not
// --squirrel-install, because the latter is unreliable with unicode
// paths. yay!
maybeInstallNewUpdaterSeedDb();
return false;
default:
return false;
}
}
// Are we using Squirrel for updates?
function updateExistsSync() {
return _fs.default.existsSync(updateExe);
}
// Restart app as the new version
function restart(app, newVersion) {
app.once('will-quit', () => {
const execPath = _path.default.resolve(rootFolder, `app-${newVersion}/${exeName}`);
_child_process.default.spawn(execPath, [], {
detached: true
});
});
app.quit();
}

View file

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _electron = require("electron");
var _default = [{
label: 'Discord',
submenu: [{
label: 'Quit',
click: () => _electron.app.quit(),
accelerator: 'Command+Q'
}]
}];
exports.default = _default;
module.exports = exports.default;

View file

@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _electron = require("electron");
const menu = require('./' + process.platform);
var _default = _electron.Menu.buildFromTemplate(menu);
exports.default = _default;
module.exports = exports.default;

View file

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _electron = require("electron");
var _default = [{
label: '&File',
submenu: [{
label: '&Exit',
click: () => _electron.app.quit(),
accelerator: 'Control+Q'
}]
}];
exports.default = _default;
module.exports = exports.default;

View file

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _electron = require("electron");
var _default = [{
label: '&File',
submenu: [{
label: '&Exit',
click: () => _electron.app.quit(),
accelerator: 'Alt+F4'
}]
}];
exports.default = _default;
module.exports = exports.default;

Binary file not shown.

View file

@ -0,0 +1,76 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.addToRegistry = addToRegistry;
exports.spawn = spawn;
exports.spawnReg = spawnReg;
var _child_process = _interopRequireDefault(require("child_process"));
var _path = _interopRequireDefault(require("path"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const regExe = process.env.SystemRoot ? _path.default.join(process.env.SystemRoot, 'System32', 'reg.exe') : 'reg.exe';
// Spawn a command and invoke the callback when it completes with an error
// and the output from standard out.
function spawn(command, args, callback) {
let stdout = '';
let spawnedProcess;
try {
// TODO: contrary to below, it should not throw any error
spawnedProcess = _child_process.default.spawn(command, args);
} catch (err) {
// Spawn can throw an error
process.nextTick(() => {
if (callback != null) {
callback(err, stdout);
}
});
return;
}
// TODO: we need to specify the encoding for the data if we're going to concat it as a string
spawnedProcess.stdout.on('data', data => {
stdout += data;
});
let err = null;
// TODO: close event might not get called, we should
// callback on error https://nodejs.org/api/child_process.html#child_process_event_error
spawnedProcess.on('error', err => {
// TODO: there should always be an error
if (err != null) {
err = err;
}
});
// TODO: don't listen to close, but listen to exit instead
spawnedProcess.on('close', (code, signal) => {
if (err === null && code !== 0) {
err = new Error('Command failed: ' + (signal || code));
}
if (err != null) {
err.code = err.code || code;
err.stdout = err.stdout || stdout;
}
if (callback != null) {
callback(err, stdout);
}
});
}
// Spawn reg.exe and callback when it completes
function spawnReg(args, callback) {
return spawn(regExe, args, callback);
}
// TODO: since we're doing this one by one, we could have a more graceful way of processing the queue
// rather than mutating the array
function addToRegistry(queue, callback) {
if (queue.length === 0) {
return callback && callback();
}
const args = queue.shift();
args.unshift('add');
args.push('/f');
return spawnReg(args, () => addToRegistry(queue, callback));
}