Compare commits
143 Commits
Author | SHA1 | Date |
---|---|---|
|| Prof. - Xadk3!#0000 || @naryal2580 | 5791d70e0d | |
|| Prof. - Xadk3!#0000 || @naryal2580 | f95fef17d2 | |
|| Prof. - Xadk3!#0000 || @naryal2580 | 074436668f | |
|| Prof. - Xadk3! | b390a93306 | |
|| Prof. - Xadk3! | cc1ed1f005 | |
|| Prof. - Xadk3! | b0078534d6 | |
|| Prof. - Xadk3! | b725e71d82 | |
Ducko | 20b5fa3165 | |
Ducko | 8cf5233e94 | |
Ducko | d8035e14b7 | |
Ducko | 6705ee9933 | |
Ducko | 120d1a5b16 | |
Ducko | be9f15dc45 | |
Ducko | 0d81eadaf0 | |
Ducko | 9052a5cb78 | |
Ducko | 28e8ed4a60 | |
Ducko | ac0ad4d48a | |
Ducko | cc0cae97f9 | |
Ducko | 3a52bd2ac7 | |
Ducko | a1be7204df | |
Ducko | be076a2fe4 | |
Ducko | 3279282c96 | |
alsoGAMER | 40b27dd1b8 | |
Ducko | c2cd5449bd | |
Ducko | c9a4662008 | |
Ducko | 6b6cabecf0 | |
Ducko | 0b1d4685cb | |
Ducko | edb6a5b4fe | |
Ducko | 78b49c092c | |
Ian Manske | 9582d79109 | |
Ducko | bb6165c1ad | |
Ducko | ad9b161744 | |
Ducko | d1f9fe0024 | |
Ducko | e1bd891f74 | |
CanadaHonk | ec5082860e | |
Ducko | f2da613f2b | |
Ducko | 7a04cb57df | |
Kyiro | c72f1a3fc0 | |
Ducko | 78204759a3 | |
Ducko | 1f0ac0f27e | |
Ducko | a6bd6654c9 | |
Ducko | d16475714d | |
Ducko | 3314bc9c28 | |
Ducko | 5c68a2a78f | |
Ducko | d63646ccfe | |
Ducko | 3291e197af | |
Ducko | 3e027d59f2 | |
Ducko | 3278a3f97e | |
Ducko | 5d2bd94945 | |
Ducko | a021777ede | |
Ducko | f425859c93 | |
Ducko | 045f9db914 | |
Ducko | 73fcc84e25 | |
CanadaHonk | e087078400 | |
Julian Pettersen | 4606f93e52 | |
CanadaHonk | ed2d0045ff | |
CanadaHonk | 6f7505fb91 | |
Ducko | c6f2f5eb78 | |
Ducko | e3cfc8dcdc | |
Ducko | 936ee08616 | |
Ducko | 967229fea8 | |
Ducko | 0018c52257 | |
Ducko | c3b020f0f1 | |
Ducko | b089e48bd7 | |
Ducko | 3585c7a1db | |
Ducko | 605c1b89dc | |
Ducko | cca324c536 | |
Kat | 127236b433 | |
Ducko | 6748897e46 | |
Ducko | 716dbce22b | |
Ducko | c9c3b5ecff | |
Ducko | 7688667bac | |
Ducko | ed731b6153 | |
Ducko | 029123e0ac | |
Ducko | ec4c8921ae | |
Ducko | 535214b25a | |
Ducko | 4a4c6e2e3a | |
Ducko | fe66b3133d | |
Ducko | d16402e064 | |
Ducko | 64a1b325fb | |
Ducko | 95fb31ffd6 | |
Ducko | 72a9b09eae | |
Ducko | f7325d6e35 | |
Ducko | 234545f1ce | |
Ducko | 91a752c6e6 | |
Ducko | 43ec96e073 | |
Ducko | a5f2630725 | |
Ducko | 70482376ad | |
Ducko | b8d8d81405 | |
Ducko | e7761a6b43 | |
Ducko | 88b45998a5 | |
Ducko | 2e4b8e2bc9 | |
Ducko | 9ed1b0b01b | |
Ducko | 71ce4fe018 | |
Ducko | d5d55b54ca | |
Ducko | d2a4b13284 | |
Ducko | ed73901be0 | |
Ducko | ab34f5386a | |
Ducko | 91b46c56cf | |
Ducko | 2ccabfda58 | |
Ducko | 52a3fa5e86 | |
Ducko | 979044bb16 | |
Ducko | e256e8fea1 | |
Ducko | f4c097e086 | |
Ducko | e9a794565a | |
Ducko | e4990cd3ad | |
Ducko | 25ff7efdc0 | |
Ducko | e5747f4ab7 | |
Ducko | 159aad3a66 | |
Ducko | 2735539b2c | |
Ducko | 933377e49d | |
Ducko | b51d358492 | |
Ducko | b8f6784911 | |
Ducko | 407add2ad6 | |
Ducko | 3286a441ba | |
Ducko | 864df199ac | |
Ducko | 06b35cbc1d | |
Ducko | 6ae3c0f284 | |
Ducko | f0f2d08f2c | |
Ducko | 513d004ce5 | |
Ducko | e56ce23966 | |
Ducko | 1827f4a783 | |
Ducko | 72842faf85 | |
Ducko | 86b3f0992e | |
Ducko | f34d8b8a76 | |
Ducko | d063ad1f2c | |
Ducko | f09208979a | |
Ducko | fd6274bb95 | |
Ducko | 99f146ea86 | |
Ducko | 25b84f4837 | |
Ducko | f599d1bd1d | |
Ducko | e06e1abda8 | |
Ducko | c20233e008 | |
Ducko | 3df9df98da | |
Ducko | e7a3a61a73 | |
Ducko | c3d6eced6c | |
Ducko | fde1aac7d4 | |
Ducko | 98cad6fcc3 | |
Ducko | 042e495b7b | |
Ducko | d3fe05b22e | |
Ducko | ac009a179e | |
Ducko | bce146927d | |
Ducko | 904f51fb28 |
|
@ -6,7 +6,6 @@ on:
|
|||
paths:
|
||||
- 'src/**'
|
||||
- 'scripts/**'
|
||||
- 'poly/**'
|
||||
- '.github/workflows/**'
|
||||
|
||||
jobs:
|
||||
|
@ -25,7 +24,6 @@ jobs:
|
|||
- name: Pack base asar
|
||||
run: |
|
||||
npm i -g asar
|
||||
bash scripts/injectPolyfills.sh
|
||||
sed -i -e "s/nightly/nightly-$(git rev-parse HEAD | cut -c 1-7)/" src/index.js
|
||||
node scripts/strip.js
|
||||
npx asar pack src app.asar
|
||||
|
@ -151,8 +149,9 @@ jobs:
|
|||
git push origin --delete nightly || true
|
||||
git tag nightly
|
||||
git push origin nightly
|
||||
curl -L -o old.asar "https://github.com/GooseMod/OpenAsar/releases/download/nightly/app.asar"
|
||||
gh release delete ${{ env.VERSION }} -y || true
|
||||
gh release create ${{ env.VERSION }} -t "Nightly" -n "$(git rev-parse HEAD | cut -c 1-7) | $(git log -1 --pretty=%B)" ${{ env.FILES }}
|
||||
gh release create ${{ env.VERSION }} -t "Nightly" -n "$(bash scripts/nightlyNotes.sh)" ${{ env.FILES }}
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
VERSION: 'nightly'
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
# People who can (and typically have) contributed to this repository.
|
||||
#
|
||||
# This script is generated by contributors.sh
|
||||
#
|
||||
|
||||
alsoGAMER <35269770+alsoGAMER@users.noreply.github.com>
|
||||
CanadaHonk <19228318+CanadaHonk@users.noreply.github.com>
|
||||
CanadaHonk <oj@oojmed.com>
|
||||
Ian Manske <IanManske@pm.me>
|
||||
Julian Pettersen <darlion2301@hotmail.com>
|
||||
Kat <61893437+TransKat@users.noreply.github.com>
|
||||
Kyiro <54126666+Kyiro@users.noreply.github.com>
|
||||
Oj <oj@oojmed.com>
|
||||
|| Prof. - Xadk3!#0000 || @naryal2580 <naryal2580@proton.me>
|
||||
|| Prof. - Xadk3! <naryal2580@gmail.com>
|
||||
|| Prof. - Xadk3! <root@nick.cf>
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash -e
|
||||
|
||||
file="$(git rev-parse --show-toplevel)/CONTRIBUTORS"
|
||||
|
||||
cat <<EOF > "$file"
|
||||
# People who can (and typically have) contributed to this repository.
|
||||
#
|
||||
# This script is generated by $(basename "$0")
|
||||
#
|
||||
|
||||
EOF
|
||||
|
||||
git log --format='%aN <%aE>' | sort -uf >> "$file"
|
|
@ -0,0 +1,54 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
// before we can set up (and export) our constants, we first need to grab bootstrap's constants
|
||||
// so we can merge them in with our constants
|
||||
function init(bootstrapConstants) {
|
||||
const APP_NAME = bootstrapConstants.APP_NAME;
|
||||
const API_ENDPOINT = bootstrapConstants.API_ENDPOINT;
|
||||
const NEW_UPDATE_ENDPOINT = bootstrapConstants.NEW_UPDATE_ENDPOINT;
|
||||
const UPDATE_ENDPOINT = bootstrapConstants.UPDATE_ENDPOINT;
|
||||
const APP_ID = bootstrapConstants.APP_ID;
|
||||
const DEFAULT_MAIN_WINDOW_ID = 0;
|
||||
const MAIN_APP_DIRNAME = __dirname;
|
||||
const UpdaterEvents = {
|
||||
UPDATE_NOT_AVAILABLE: 'UPDATE_NOT_AVAILABLE',
|
||||
CHECKING_FOR_UPDATES: 'CHECKING_FOR_UPDATES',
|
||||
UPDATE_ERROR: 'UPDATE_ERROR',
|
||||
UPDATE_MANUALLY: 'UPDATE_MANUALLY',
|
||||
UPDATE_AVAILABLE: 'UPDATE_AVAILABLE',
|
||||
MODULE_INSTALL_PROGRESS: 'MODULE_INSTALL_PROGRESS',
|
||||
UPDATE_DOWNLOADED: 'UPDATE_DOWNLOADED',
|
||||
MODULE_INSTALLED: 'MODULE_INSTALLED',
|
||||
CHECK_FOR_UPDATES: 'CHECK_FOR_UPDATES',
|
||||
QUIT_AND_INSTALL: 'QUIT_AND_INSTALL',
|
||||
MODULE_INSTALL: 'MODULE_INSTALL',
|
||||
MODULE_QUERY: 'MODULE_QUERY',
|
||||
UPDATER_HISTORY_QUERY_AND_TRUNCATE: 'UPDATER_HISTORY_QUERY_AND_TRUNCATE',
|
||||
UPDATER_HISTORY_RESPONSE: 'UPDATER_HISTORY_RESPONSE'
|
||||
};
|
||||
const MenuEvents = {
|
||||
OPEN_HELP: 'menu:open-help',
|
||||
OPEN_SETTINGS: 'menu:open-settings',
|
||||
CHECK_FOR_UPDATES: 'menu:check-for-updates'
|
||||
};
|
||||
const exported = {
|
||||
APP_NAME,
|
||||
DEFAULT_MAIN_WINDOW_ID,
|
||||
MAIN_APP_DIRNAME,
|
||||
APP_ID,
|
||||
API_ENDPOINT,
|
||||
NEW_UPDATE_ENDPOINT,
|
||||
UPDATE_ENDPOINT,
|
||||
UpdaterEvents,
|
||||
MenuEvents
|
||||
};
|
||||
for (const [k, v] of Object.entries(exported)) {
|
||||
module.exports[k] = v;
|
||||
}
|
||||
}
|
||||
module.exports = {
|
||||
init
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.getEnableHardwareAcceleration = getEnableHardwareAcceleration;
|
||||
exports.setEnableHardwareAcceleration = setEnableHardwareAcceleration;
|
||||
var _electron = require("electron");
|
||||
var _appSettings = require("./bootstrapModules/appSettings");
|
||||
const settings = _appSettings.appSettings.getSettings();
|
||||
function getEnableHardwareAcceleration() {
|
||||
// TODO: This should probably a constant
|
||||
return settings.get('enableHardwareAcceleration', true);
|
||||
}
|
||||
function setEnableHardwareAcceleration(enableHardwareAcceleration) {
|
||||
settings.set('enableHardwareAcceleration', enableHardwareAcceleration);
|
||||
settings.save();
|
||||
_electron.app.relaunch();
|
||||
_electron.app.exit(0);
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.hasInit = void 0;
|
||||
exports.init = init;
|
||||
var _electron = require("electron");
|
||||
var _utils = require("./utils");
|
||||
var _mainScreen = require("./mainScreen");
|
||||
var _ipcMain = _interopRequireDefault(require("./ipcMain"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
let hasInit = false;
|
||||
exports.hasInit = hasInit;
|
||||
let lastIndex;
|
||||
let appIcons;
|
||||
|
||||
/**
|
||||
* Used on Windows to set the taskbar icon
|
||||
*/
|
||||
function init() {
|
||||
// Only init on win32 platforms
|
||||
if (process.platform !== 'win32') return;
|
||||
if (hasInit) {
|
||||
console.warn('appBadge: Has already init! Cancelling init.');
|
||||
return;
|
||||
}
|
||||
exports.hasInit = hasInit = true;
|
||||
lastIndex = null;
|
||||
appIcons = [];
|
||||
const resourcePath = `app/images/badges`;
|
||||
for (let i = 1; i <= 11; i++) {
|
||||
appIcons.push((0, _utils.exposeModuleResource)(resourcePath, `badge-${i}.ico`));
|
||||
}
|
||||
_ipcMain.default.on('APP_BADGE_SET', (_event, count) => setAppBadge(count));
|
||||
}
|
||||
function setAppBadge(count) {
|
||||
const win = _electron.BrowserWindow.fromId((0, _mainScreen.getMainWindowId)());
|
||||
const {
|
||||
index,
|
||||
description
|
||||
} = getOverlayIconData(count);
|
||||
|
||||
// Prevent setting a new icon when the icon is the same
|
||||
if (lastIndex !== index) {
|
||||
if (index == null) {
|
||||
win.setOverlayIcon(null, description);
|
||||
} else {
|
||||
win.setOverlayIcon(appIcons[index], description);
|
||||
}
|
||||
lastIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* -1 is bullet
|
||||
* 0 is nothing
|
||||
* 1-9 is a number badge
|
||||
* 10+ is `9+`
|
||||
*/
|
||||
function getOverlayIconData(count) {
|
||||
// Unread message badge
|
||||
if (count === -1) {
|
||||
return {
|
||||
index: 10,
|
||||
// this.appIcons.length - 1
|
||||
description: `Unread messages`
|
||||
};
|
||||
}
|
||||
|
||||
// Clear overlay icon
|
||||
if (count === 0) {
|
||||
return {
|
||||
index: null,
|
||||
// null is used to clear the overlay icon
|
||||
description: 'No Notifications'
|
||||
};
|
||||
}
|
||||
|
||||
// Notification badge
|
||||
const index = Math.max(1, Math.min(count, 10)) - 1; // arrays are 0 based
|
||||
return {
|
||||
index,
|
||||
description: `${index} notifications`
|
||||
};
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.hasInit = void 0;
|
||||
exports.init = init;
|
||||
var _autoStart = require("./bootstrapModules/autoStart");
|
||||
var _appSettings = require("./bootstrapModules/appSettings");
|
||||
var _ipcMain = _interopRequireDefault(require("./ipcMain"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
const settings = _appSettings.appSettings.getSettings();
|
||||
const NOOP = () => {};
|
||||
let hasInit = false;
|
||||
exports.hasInit = hasInit;
|
||||
function init() {
|
||||
if (hasInit) {
|
||||
console.warn('appConfig: Has already init! Cancelling init.');
|
||||
return;
|
||||
}
|
||||
exports.hasInit = hasInit = true;
|
||||
_ipcMain.default.on('TOGGLE_MINIMIZE_TO_TRAY', (_event, value) => setMinimizeOnClose(value));
|
||||
_ipcMain.default.on('TOGGLE_OPEN_ON_STARTUP', (_event, value) => toggleRunOnStartup(value));
|
||||
_ipcMain.default.on('TOGGLE_START_MINIMIZED', (_event, value) => toggleStartMinimized(value));
|
||||
_ipcMain.default.on('UPDATE_OPEN_ON_STARTUP', _event => updateOpenOnStartup());
|
||||
}
|
||||
function setMinimizeOnClose(minimizeToTray) {
|
||||
settings.set('MINIMIZE_TO_TRAY', minimizeToTray);
|
||||
}
|
||||
function toggleRunOnStartup(openOnStartup) {
|
||||
settings.set('OPEN_ON_STARTUP', openOnStartup);
|
||||
if (openOnStartup) {
|
||||
_autoStart.autoStart.install(NOOP);
|
||||
} else {
|
||||
_autoStart.autoStart.uninstall(NOOP);
|
||||
}
|
||||
}
|
||||
function toggleStartMinimized(startMinimized) {
|
||||
settings.set('START_MINIMIZED', startMinimized);
|
||||
_autoStart.autoStart.isInstalled(installed => {
|
||||
// Only update the registry for this toggle if the app was already set to autorun
|
||||
if (installed) {
|
||||
_autoStart.autoStart.install(NOOP);
|
||||
}
|
||||
});
|
||||
}
|
||||
function updateOpenOnStartup() {
|
||||
_autoStart.autoStart.update(NOOP);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.getFeatures = getFeatures;
|
||||
exports.init = init;
|
||||
var _FeatureFlags = _interopRequireDefault(require("../common/FeatureFlags"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
let features;
|
||||
function init() {
|
||||
features = new _FeatureFlags.default();
|
||||
}
|
||||
function getFeatures() {
|
||||
return features;
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _electron = require("electron");
|
||||
var _securityUtils = require("../../common/securityUtils");
|
||||
var Constants = _interopRequireWildcard(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; }
|
||||
const {
|
||||
MenuEvents
|
||||
} = Constants;
|
||||
const SEPARATOR = {
|
||||
type: 'separator'
|
||||
};
|
||||
function getWindow() {
|
||||
let window = _electron.BrowserWindow.getFocusedWindow();
|
||||
if (!window) {
|
||||
const windowList = _electron.BrowserWindow.getAllWindows();
|
||||
if (windowList && windowList[0]) {
|
||||
window = windowList[0];
|
||||
window.show();
|
||||
window.focus();
|
||||
}
|
||||
}
|
||||
return window;
|
||||
}
|
||||
var _default = enableDevtools => [{
|
||||
label: 'Discord',
|
||||
submenu: [{
|
||||
label: 'About Discord',
|
||||
selector: 'orderFrontStandardAboutPanel:'
|
||||
}, {
|
||||
label: 'Check for Updates...',
|
||||
click: () => _electron.app.emit(MenuEvents.CHECK_FOR_UPDATES)
|
||||
}, {
|
||||
label: 'Acknowledgements',
|
||||
click: () => (0, _securityUtils.saferShellOpenExternal)('https://discord.com/acknowledgements')
|
||||
}, SEPARATOR, {
|
||||
label: 'Preferences',
|
||||
click: () => _electron.app.emit(MenuEvents.OPEN_SETTINGS),
|
||||
accelerator: 'Command+,'
|
||||
}, SEPARATOR, {
|
||||
label: 'Services',
|
||||
submenu: []
|
||||
}, SEPARATOR, {
|
||||
label: 'Hide Discord',
|
||||
selector: 'hide:',
|
||||
accelerator: 'Command+H'
|
||||
}, {
|
||||
label: 'Hide Others',
|
||||
selector: 'hideOtherApplications:',
|
||||
accelerator: 'Command+Alt+H'
|
||||
}, {
|
||||
label: 'Show All',
|
||||
selector: 'unhideAllApplications:'
|
||||
}, SEPARATOR, {
|
||||
label: 'Quit',
|
||||
click: () => _electron.app.quit(),
|
||||
accelerator: 'Command+Q'
|
||||
}]
|
||||
}, {
|
||||
label: 'Edit',
|
||||
submenu: [{
|
||||
role: 'undo',
|
||||
accelerator: 'Command+Z'
|
||||
}, {
|
||||
role: 'redo',
|
||||
accelerator: 'Shift+Command+Z'
|
||||
}, SEPARATOR, {
|
||||
role: 'cut',
|
||||
accelerator: 'Command+X'
|
||||
}, {
|
||||
role: 'copy',
|
||||
accelerator: 'Command+C'
|
||||
}, {
|
||||
role: 'paste',
|
||||
accelerator: 'Command+V'
|
||||
}, {
|
||||
role: 'selectAll',
|
||||
accelerator: 'Command+A'
|
||||
}]
|
||||
}, {
|
||||
label: 'View',
|
||||
submenu: [{
|
||||
label: 'Reload',
|
||||
click: () => {
|
||||
const window = getWindow();
|
||||
if (window) {
|
||||
window.webContents.reloadIgnoringCache();
|
||||
}
|
||||
},
|
||||
accelerator: 'Command+R'
|
||||
}, {
|
||||
label: 'Toggle Full Screen',
|
||||
click: () => {
|
||||
const window = getWindow();
|
||||
if (window) {
|
||||
window.setFullScreen(!window.isFullScreen());
|
||||
}
|
||||
},
|
||||
accelerator: 'Command+Control+F'
|
||||
}, ...(enableDevtools ? [SEPARATOR, {
|
||||
label: 'Developer',
|
||||
submenu: [{
|
||||
label: 'Toggle Developer Tools',
|
||||
click: () => {
|
||||
const window = getWindow();
|
||||
if (window) {
|
||||
window.toggleDevTools();
|
||||
}
|
||||
},
|
||||
accelerator: 'Alt+Command+I'
|
||||
}]
|
||||
}] : [])]
|
||||
}, {
|
||||
label: 'Window',
|
||||
submenu: [{
|
||||
label: 'Minimize',
|
||||
selector: 'performMiniaturize:',
|
||||
accelerator: 'Command+M'
|
||||
}, {
|
||||
label: 'Zoom',
|
||||
selector: 'performZoom:'
|
||||
}, {
|
||||
label: 'Close',
|
||||
accelerator: 'Command+W',
|
||||
click: (_, window) => {
|
||||
// Main window
|
||||
if (window == null || window.windowKey == null) {
|
||||
_electron.Menu.sendActionToFirstResponder('hide:');
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
}, SEPARATOR, {
|
||||
label: 'Bring All to Front',
|
||||
selector: 'arrangeInFront:'
|
||||
}]
|
||||
}, {
|
||||
label: 'Help',
|
||||
submenu: [{
|
||||
label: 'Discord Help',
|
||||
click: () => _electron.app.emit(MenuEvents.OPEN_HELP)
|
||||
}]
|
||||
}];
|
||||
exports.default = _default;
|
||||
module.exports = exports.default;
|
|
@ -0,0 +1,11 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _electron = require("electron");
|
||||
const createMenu = require('./' + process.platform);
|
||||
var _default = enableDevtools => _electron.Menu.buildFromTemplate(createMenu(enableDevtools));
|
||||
exports.default = _default;
|
||||
module.exports = exports.default;
|
|
@ -0,0 +1,78 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _electron = require("electron");
|
||||
var Constants = _interopRequireWildcard(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; }
|
||||
const {
|
||||
MenuEvents
|
||||
} = Constants;
|
||||
const SEPARATOR = {
|
||||
type: 'separator'
|
||||
};
|
||||
var _default = enableDevtools => [{
|
||||
label: '&File',
|
||||
submenu: [{
|
||||
label: '&Options',
|
||||
click: () => _electron.app.emit(MenuEvents.OPEN_SETTINGS),
|
||||
accelerator: 'Control+,'
|
||||
}, SEPARATOR, {
|
||||
label: 'E&xit',
|
||||
click: () => _electron.app.quit(),
|
||||
accelerator: 'Control+Q'
|
||||
}]
|
||||
}, {
|
||||
label: '&Edit',
|
||||
submenu: [{
|
||||
role: 'undo',
|
||||
accelerator: 'Control+Z'
|
||||
}, {
|
||||
role: 'redo',
|
||||
accelerator: 'Shift+Control+Z'
|
||||
}, SEPARATOR, {
|
||||
role: 'cut',
|
||||
accelerator: 'Control+X'
|
||||
}, {
|
||||
role: 'copy',
|
||||
accelerator: 'Control+C'
|
||||
}, {
|
||||
role: 'paste',
|
||||
accelerator: 'Control+V'
|
||||
}, {
|
||||
role: 'selectAll',
|
||||
accelerator: 'Control+A'
|
||||
}]
|
||||
}, {
|
||||
label: '&View',
|
||||
submenu: [{
|
||||
label: '&Reload',
|
||||
click: () => _electron.BrowserWindow.getFocusedWindow().webContents.reloadIgnoringCache(),
|
||||
accelerator: 'Control+R'
|
||||
}, {
|
||||
label: 'Toggle &Full Screen',
|
||||
click: () => _electron.BrowserWindow.getFocusedWindow().setFullScreen(!_electron.BrowserWindow.getFocusedWindow().isFullScreen()),
|
||||
accelerator: 'Control+Shift+F'
|
||||
}, ...(enableDevtools ? [SEPARATOR, {
|
||||
label: '&Developer',
|
||||
submenu: [{
|
||||
label: 'Toggle Developer &Tools',
|
||||
click: () => _electron.BrowserWindow.getFocusedWindow().toggleDevTools(),
|
||||
accelerator: 'Control+Shift+I'
|
||||
}]
|
||||
}] : [])]
|
||||
}, {
|
||||
label: '&Help',
|
||||
submenu: [{
|
||||
label: 'Check for Updates',
|
||||
click: () => _electron.app.emit(MenuEvents.CHECK_FOR_UPDATES)
|
||||
}, SEPARATOR, {
|
||||
label: 'Discord Help',
|
||||
click: () => _electron.app.emit(MenuEvents.OPEN_HELP)
|
||||
}]
|
||||
}];
|
||||
exports.default = _default;
|
||||
module.exports = exports.default;
|
|
@ -0,0 +1,57 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _electron = require("electron");
|
||||
var Constants = _interopRequireWildcard(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; }
|
||||
const {
|
||||
MenuEvents
|
||||
} = Constants;
|
||||
const SEPARATOR = {
|
||||
type: 'separator'
|
||||
};
|
||||
var _default = enableDevtools => [{
|
||||
label: '&File',
|
||||
submenu: [{
|
||||
label: '&Options',
|
||||
click: () => _electron.app.emit(MenuEvents.OPEN_SETTINGS),
|
||||
accelerator: 'Ctrl+,'
|
||||
}, SEPARATOR, {
|
||||
label: '&Exit',
|
||||
click: () => _electron.app.quit(),
|
||||
accelerator: 'Alt+F4'
|
||||
}]
|
||||
}, {
|
||||
label: '&View',
|
||||
submenu: [{
|
||||
label: '&Reload',
|
||||
click: () => _electron.BrowserWindow.getFocusedWindow().webContents.reloadIgnoringCache(),
|
||||
accelerator: 'Control+R'
|
||||
}, {
|
||||
label: 'Toggle &Full Screen',
|
||||
click: () => _electron.BrowserWindow.getFocusedWindow().setFullScreen(!_electron.BrowserWindow.getFocusedWindow().isFullScreen()),
|
||||
accelerator: 'Control+Shift+F'
|
||||
}, ...(enableDevtools ? [SEPARATOR, {
|
||||
label: '&Developer',
|
||||
submenu: [{
|
||||
label: 'Toggle Developer &Tools',
|
||||
click: () => _electron.BrowserWindow.getFocusedWindow().toggleDevTools(),
|
||||
accelerator: 'Control+Shift+I'
|
||||
}]
|
||||
}] : [])]
|
||||
}, {
|
||||
label: '&Help',
|
||||
submenu: [{
|
||||
label: 'Check for Updates',
|
||||
click: () => _electron.app.emit(MenuEvents.CHECK_FOR_UPDATES)
|
||||
}, SEPARATOR, {
|
||||
label: 'Discord Help',
|
||||
click: () => _electron.app.emit(MenuEvents.OPEN_HELP)
|
||||
}]
|
||||
}];
|
||||
exports.default = _default;
|
||||
module.exports = exports.default;
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "appSettings", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _bootstrapModules.appSettings;
|
||||
}
|
||||
});
|
||||
var _bootstrapModules = require("./bootstrapModules");
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "autoStart", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _bootstrapModules.autoStart;
|
||||
}
|
||||
});
|
||||
var _bootstrapModules = require("./bootstrapModules");
|
|
@ -0,0 +1,52 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.crashReporterSetup = exports.buildInfo = exports.autoStart = exports.appSettings = exports.GPUSettings = exports.Constants = void 0;
|
||||
exports.init = init;
|
||||
exports.updater = exports.splashScreen = exports.requireNative = exports.paths = exports.moduleUpdater = void 0;
|
||||
let hasInit = false;
|
||||
|
||||
// NOTE: We may want to instead of initializing these to null, instead initialize them to their normal files.
|
||||
// This way each one (see `crashReporterSetup`) would not need to do their own self-detection of loading when
|
||||
// inside the overlay (or any future relevant code).
|
||||
let paths = null;
|
||||
exports.paths = paths;
|
||||
let splashScreen = null;
|
||||
exports.splashScreen = splashScreen;
|
||||
let autoStart = null;
|
||||
exports.autoStart = autoStart;
|
||||
let requireNative = null;
|
||||
exports.requireNative = requireNative;
|
||||
let appSettings = null;
|
||||
exports.appSettings = appSettings;
|
||||
let Constants = null;
|
||||
exports.Constants = Constants;
|
||||
let GPUSettings = null;
|
||||
exports.GPUSettings = GPUSettings;
|
||||
let buildInfo = null;
|
||||
exports.buildInfo = buildInfo;
|
||||
let moduleUpdater = null;
|
||||
exports.moduleUpdater = moduleUpdater;
|
||||
let updater = null;
|
||||
exports.updater = updater;
|
||||
let crashReporterSetup = null;
|
||||
exports.crashReporterSetup = crashReporterSetup;
|
||||
function init(bootstrapModules) {
|
||||
if (hasInit) {
|
||||
throw new Error(`bootstrapModules has already init`);
|
||||
}
|
||||
exports.paths = paths = bootstrapModules.paths;
|
||||
exports.splashScreen = splashScreen = bootstrapModules.splashScreen;
|
||||
exports.autoStart = autoStart = bootstrapModules.autoStart;
|
||||
exports.requireNative = requireNative = bootstrapModules.requireNative;
|
||||
exports.appSettings = appSettings = bootstrapModules.appSettings;
|
||||
exports.Constants = Constants = bootstrapModules.Constants;
|
||||
exports.GPUSettings = GPUSettings = bootstrapModules.GPUSettings;
|
||||
exports.buildInfo = buildInfo = bootstrapModules.buildInfo;
|
||||
exports.moduleUpdater = moduleUpdater = bootstrapModules.moduleUpdater;
|
||||
exports.updater = updater = bootstrapModules.updater;
|
||||
exports.crashReporterSetup = crashReporterSetup = bootstrapModules.crashReporterSetup;
|
||||
hasInit = true;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "buildInfo", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _bootstrapModules.buildInfo;
|
||||
}
|
||||
});
|
||||
var _bootstrapModules = require("./bootstrapModules");
|
|
@ -0,0 +1,10 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.crashReporterSetup = void 0;
|
||||
var _bootstrapModules = require("./bootstrapModules");
|
||||
// Note: bootstrapCrashReporterSetup will not be set in the overlay.
|
||||
const crashReporterSetup = _bootstrapModules.crashReporterSetup ?? require('../../common/crashReporterSetup');
|
||||
exports.crashReporterSetup = crashReporterSetup;
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "moduleUpdater", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _bootstrapModules.moduleUpdater;
|
||||
}
|
||||
});
|
||||
var _bootstrapModules = require("./bootstrapModules");
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "paths", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _bootstrapModules.paths;
|
||||
}
|
||||
});
|
||||
var _bootstrapModules = require("./bootstrapModules");
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "splashScreen", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _bootstrapModules.splashScreen;
|
||||
}
|
||||
});
|
||||
var _bootstrapModules = require("./bootstrapModules");
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "updater", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _bootstrapModules.updater;
|
||||
}
|
||||
});
|
||||
var _bootstrapModules = require("./bootstrapModules");
|
|
@ -0,0 +1,8 @@
|
|||
"use strict";
|
||||
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.ACCESSIBILITY_GET_ENABLED, _ => {
|
||||
return Promise.resolve(_electron.default.app.accessibilitySupportEnabled);
|
||||
});
|
|
@ -0,0 +1,96 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.injectBuildInfo = injectBuildInfo;
|
||||
exports.injectModuleUpdater = injectModuleUpdater;
|
||||
exports.injectUpdater = injectUpdater;
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/* eslint-disable require-await */
|
||||
|
||||
let injectedBuildInfo = null;
|
||||
let injectedModuleUpdater = null;
|
||||
let injectedUpdater = null;
|
||||
function injectBuildInfo(buildInfo) {
|
||||
injectedBuildInfo = buildInfo;
|
||||
}
|
||||
function injectModuleUpdater(moduleUpdater) {
|
||||
injectedModuleUpdater = moduleUpdater;
|
||||
}
|
||||
function injectUpdater(updater) {
|
||||
injectedUpdater = updater;
|
||||
}
|
||||
_DiscordIPC.DiscordIPC.main.on(_DiscordIPC.IPCEvents.APP_GET_RELEASE_CHANNEL_SYNC, event => {
|
||||
event.returnValue = injectedBuildInfo.releaseChannel;
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.on(_DiscordIPC.IPCEvents.APP_GET_HOST_VERSION_SYNC, event => {
|
||||
event.returnValue = _electron.default.app.getVersion();
|
||||
});
|
||||
async function newUpdaterGetModuleVersions(updater) {
|
||||
// eslint-disable-next-line camelcase
|
||||
return (await updater.queryCurrentVersions()).current_modules;
|
||||
}
|
||||
function newUpdaterGetBuildNumber(updater) {
|
||||
const version = updater.queryCurrentVersionsSync();
|
||||
// eslint-disable-next-line camelcase
|
||||
if (version.running_update != null) {
|
||||
return version.running_update.metadata_version;
|
||||
}
|
||||
return version.last_successful_update.metadata_version;
|
||||
}
|
||||
_DiscordIPC.DiscordIPC.main.on(_DiscordIPC.IPCEvents.APP_GET_BUILD_NUMBER, event => {
|
||||
var _injectedUpdater;
|
||||
const newUpdater = (_injectedUpdater = injectedUpdater) === null || _injectedUpdater === void 0 ? void 0 : _injectedUpdater.getUpdater();
|
||||
if (newUpdater != null) {
|
||||
event.returnValue = newUpdaterGetBuildNumber(newUpdater);
|
||||
return;
|
||||
}
|
||||
event.returnValue = null;
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_GET_MODULE_VERSIONS, async _ => {
|
||||
var _injectedUpdater2;
|
||||
const newUpdater = (_injectedUpdater2 = injectedUpdater) === null || _injectedUpdater2 === void 0 ? void 0 : _injectedUpdater2.getUpdater();
|
||||
if (newUpdater != null) {
|
||||
return newUpdaterGetModuleVersions(newUpdater);
|
||||
}
|
||||
const versions = {};
|
||||
const installed = injectedModuleUpdater != null ? injectedModuleUpdater.getInstalled() : {};
|
||||
for (const name of Object.keys(installed)) {
|
||||
versions[name] = installed[name].installedVersion;
|
||||
}
|
||||
return versions;
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_GET_PATH, async (_, path) => {
|
||||
// TODO: Fix argument in AsyncIPCEventMap.
|
||||
return _electron.default.app.getPath(path);
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_SET_BADGE_COUNT, async (_, count) => {
|
||||
_electron.default.app.setBadgeCount(count);
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_DOCK_SET_BADGE, async (_, badge) => {
|
||||
if (_electron.default.app.dock != null) {
|
||||
_electron.default.app.dock.setBadge(badge);
|
||||
}
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_DOCK_BOUNCE, async (_, type) => {
|
||||
if (_electron.default.app.dock != null) {
|
||||
return _electron.default.app.dock.bounce(type);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_DOCK_CANCEL_BOUNCE, async (_, id) => {
|
||||
if (_electron.default.app.dock != null) {
|
||||
_electron.default.app.dock.cancelBounce(id);
|
||||
}
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_RELAUNCH, async _ => {
|
||||
_electron.default.app.relaunch();
|
||||
_electron.default.app.exit(0);
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.APP_GET_DEFAULT_DOUBLE_CLICK_ACTION, async _ => {
|
||||
return _electron.default.systemPreferences.getUserDefault('AppleActionOnDoubleClick', 'string');
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
"use strict";
|
||||
|
||||
// @ts-nocheck
|
||||
/* eslint-disable */
|
||||
const electron = require('electron');
|
||||
const {
|
||||
CLIPBOARD_COPY,
|
||||
CLIPBOARD_CUT,
|
||||
CLIPBOARD_PASTE
|
||||
} = require('../common/constants').IPCEvents;
|
||||
electron.ipcMain.handle(CLIPBOARD_COPY, async _ => {
|
||||
electron.webContents.getFocusedWebContents().copy();
|
||||
});
|
||||
electron.ipcMain.handle(CLIPBOARD_CUT, async _ => {
|
||||
electron.webContents.getFocusedWebContents().cut();
|
||||
});
|
||||
electron.ipcMain.handle(CLIPBOARD_PASTE, async _ => {
|
||||
electron.webContents.getFocusedWebContents().paste();
|
||||
});
|
|
@ -0,0 +1,134 @@
|
|||
"use strict";
|
||||
|
||||
var _buffer = _interopRequireDefault(require("buffer"));
|
||||
var _promises = _interopRequireDefault(require("fs/promises"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
var _fileutils = require("../common/fileutils");
|
||||
var _utils = require("../common/utils");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const MAX_LENGTH = _buffer.default.constants.MAX_LENGTH;
|
||||
const DISCORD_HEADER_NAME = 'dscl';
|
||||
const INVALID_FILE_ERROR = 'Invalid file';
|
||||
class InvalidFileError extends Error {}
|
||||
function verifyIsMP4(buffer) {
|
||||
if (getBoxHeaderName(buffer, 0) !== 'ftyp') {
|
||||
throw new InvalidFileError(INVALID_FILE_ERROR);
|
||||
}
|
||||
}
|
||||
function verifyHasMP4Extension(filename) {
|
||||
if (_path.default.parse(filename).ext !== '.mp4') {
|
||||
throw new InvalidFileError(INVALID_FILE_ERROR);
|
||||
}
|
||||
}
|
||||
function getBoxSize(buffer, startIndex) {
|
||||
return buffer.readUInt32BE(startIndex);
|
||||
}
|
||||
function getBoxHeaderName(buffer, startIndex) {
|
||||
return buffer.toString('ascii', startIndex + 4, startIndex + 8);
|
||||
}
|
||||
function verifyValidClip(buffer) {
|
||||
let currIndex = 0;
|
||||
while (currIndex < buffer.byteLength) {
|
||||
const boxHeaderName = getBoxHeaderName(buffer, currIndex);
|
||||
if (boxHeaderName === DISCORD_HEADER_NAME) {
|
||||
return;
|
||||
}
|
||||
const boxSize = getBoxSize(buffer, currIndex);
|
||||
//box size must be at least 8 to account for header, so return false for malformed file
|
||||
if (boxSize < 8) {
|
||||
throw new InvalidFileError(INVALID_FILE_ERROR);
|
||||
}
|
||||
currIndex += boxSize;
|
||||
}
|
||||
throw new InvalidFileError(INVALID_FILE_ERROR);
|
||||
}
|
||||
async function loadClip(filename) {
|
||||
try {
|
||||
verifyHasMP4Extension(filename);
|
||||
const result = await (0, _fileutils.readFulfilledFiles)([filename], MAX_LENGTH, true);
|
||||
const buffer = result[0].data;
|
||||
verifyIsMP4(buffer);
|
||||
verifyValidClip(buffer);
|
||||
return result[0];
|
||||
} catch (e) {
|
||||
if (e instanceof InvalidFileError) {
|
||||
console.log(`Invalid clips file: ${e}`);
|
||||
} else {
|
||||
console.error(`Invalid clips file: ${e}`);
|
||||
}
|
||||
throw new Error(INVALID_FILE_ERROR);
|
||||
}
|
||||
}
|
||||
async function getClipMetadata(filename, dirPath) {
|
||||
try {
|
||||
verifyHasMP4Extension(filename);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
const filepath = _path.default.join(dirPath, filename);
|
||||
const handle = await _promises.default.open(filepath, 'r');
|
||||
const stats = await handle.stat();
|
||||
let currIndex = 0;
|
||||
const mp4HeaderBuffer = Buffer.alloc(8);
|
||||
try {
|
||||
await handle.read({
|
||||
buffer: mp4HeaderBuffer,
|
||||
position: 0
|
||||
});
|
||||
verifyIsMP4(mp4HeaderBuffer);
|
||||
currIndex += getBoxSize(mp4HeaderBuffer, currIndex);
|
||||
while (currIndex < stats.size) {
|
||||
await handle.read({
|
||||
buffer: mp4HeaderBuffer,
|
||||
position: currIndex
|
||||
});
|
||||
const boxSize = getBoxSize(mp4HeaderBuffer, 0);
|
||||
if (boxSize < 8) {
|
||||
return null;
|
||||
}
|
||||
const header = getBoxHeaderName(mp4HeaderBuffer, 0);
|
||||
if (header === DISCORD_HEADER_NAME) {
|
||||
const metadataBuffer = Buffer.alloc(boxSize - 8);
|
||||
await handle.read({
|
||||
buffer: metadataBuffer,
|
||||
position: currIndex + 8
|
||||
});
|
||||
const metadata = JSON.parse(metadataBuffer.toString('utf-8'));
|
||||
return {
|
||||
filepath: filepath,
|
||||
metadata: metadata
|
||||
};
|
||||
}
|
||||
currIndex += boxSize;
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
console.log(`error: ${e}`);
|
||||
return null;
|
||||
} finally {
|
||||
await handle.close();
|
||||
}
|
||||
}
|
||||
async function deleteClip(path) {
|
||||
try {
|
||||
await loadClip(path);
|
||||
await (0, _fileutils.deleteFile)(path);
|
||||
} catch (e) {
|
||||
console.log(`Invalid clips file to delete: ${e}`);
|
||||
throw new Error(INVALID_FILE_ERROR);
|
||||
}
|
||||
}
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.LOAD_CLIP, (_, path) => {
|
||||
return loadClip(path);
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.LOAD_CLIPS_DIRECTORY, async (_, dirPath) => {
|
||||
const filenames = await (0, _fileutils.getFilesnamesFromDirectory)(dirPath);
|
||||
const filteredFiles = (await Promise.all(filenames.map(filename => getClipMetadata(filename, dirPath)))).filter(_utils.isNotNullish);
|
||||
return filteredFiles;
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.DELETE_CLIP, (_, path) => {
|
||||
return deleteClip(path);
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
"use strict";
|
||||
|
||||
// @ts-nocheck
|
||||
/* eslint-disable */
|
||||
const electron = require('electron');
|
||||
const {
|
||||
CONSTANTS_GET
|
||||
} = require('../common/constants').IPCEvents;
|
||||
const {
|
||||
APP_NAME,
|
||||
APP_ID,
|
||||
API_ENDPOINT,
|
||||
UPDATE_ENDPOINT
|
||||
} = require('../../Constants');
|
||||
const exposedConstants = {
|
||||
APP_NAME,
|
||||
APP_ID,
|
||||
API_ENDPOINT,
|
||||
UPDATE_ENDPOINT
|
||||
};
|
||||
electron.ipcMain.handle(CONSTANTS_GET, async (_, name) => {
|
||||
if (!exposedConstants.hasOwnProperty(name)) {
|
||||
return undefined;
|
||||
}
|
||||
return exposedConstants[name];
|
||||
});
|
|
@ -0,0 +1,25 @@
|
|||
"use strict";
|
||||
|
||||
var _assert = _interopRequireDefault(require("assert"));
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _lodash = _interopRequireDefault(require("lodash"));
|
||||
var _crashReporterUtils = require("../../../common/crashReporterUtils");
|
||||
var _crashReporterSetup = require("../../bootstrapModules/crashReporterSetup");
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.CRASH_REPORTER_UPDATE_METADATA, (_, additionalMetadata) => {
|
||||
const metadata = _crashReporterSetup.crashReporterSetup.metadata;
|
||||
(0, _assert.default)(metadata != null, 'Metadata imported improperly.');
|
||||
const finalMetadata = _lodash.default.defaultsDeep(metadata, additionalMetadata ?? {});
|
||||
(0, _crashReporterUtils.reconcileCrashReporterMetadata)(_electron.default.crashReporter, finalMetadata);
|
||||
return Promise.resolve({
|
||||
metadata: finalMetadata
|
||||
});
|
||||
});
|
||||
|
||||
// Internal test for unhandled JS exception
|
||||
_electron.default.ipcMain.handle(_DiscordIPC.IPCEvents.UNHANDLED_JS_EXCEPTION, _ => {
|
||||
setTimeout(() => {
|
||||
throw new Error('UNHANDLED_EXCEPTION ' + process.type);
|
||||
}, 50);
|
||||
});
|
|
@ -0,0 +1,8 @@
|
|||
"use strict";
|
||||
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.DESKTOP_CAPTURER_GET_SOURCES, (_, opts) => {
|
||||
return _electron.default.desktopCapturer.getSources(opts);
|
||||
});
|
|
@ -0,0 +1,25 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.injectFeaturesBackend = injectFeaturesBackend;
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
let injectedFeatures = null;
|
||||
function getFeatures() {
|
||||
return injectedFeatures != null ? injectedFeatures : {
|
||||
getSupported: () => {
|
||||
return [];
|
||||
},
|
||||
supports: () => {
|
||||
return false;
|
||||
},
|
||||
declareSupported: () => {}
|
||||
};
|
||||
}
|
||||
function injectFeaturesBackend(features) {
|
||||
injectedFeatures = features;
|
||||
}
|
||||
_DiscordIPC.DiscordIPC.main.on(_DiscordIPC.IPCEvents.FEATURES_GET_BROWSER_FEATURES, event => {
|
||||
event.returnValue = getFeatures().getSupported();
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
"use strict";
|
||||
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/* eslint-disable require-await */
|
||||
|
||||
function getModulePath() {
|
||||
// The smoketest's need to be able to:
|
||||
// 1) store multiple running instances data separately,
|
||||
// 2) have it in a known location so it can be used as a build artifact.
|
||||
if (process.env.DISCORD_USER_DATA_DIR != null) {
|
||||
return process.env.DISCORD_USER_DATA_DIR;
|
||||
}
|
||||
return global.moduleDataPath ?? global.modulePath;
|
||||
}
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.FILE_MANAGER_GET_MODULE_PATH, async _ => {
|
||||
return getModulePath();
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.FILE_MANAGER_SHOW_SAVE_DIALOG, async (_, dialogOptions) => {
|
||||
return await _electron.default.dialog.showSaveDialog(dialogOptions);
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.FILE_MANAGER_SHOW_OPEN_DIALOG, async (_, dialogOptions) => {
|
||||
return await _electron.default.dialog.showOpenDialog(dialogOptions);
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.FILE_MANAGER_SHOW_ITEM_IN_FOLDER, async (_, path) => {
|
||||
_electron.default.shell.showItemInFolder(path);
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.on(_DiscordIPC.IPCEvents.FILE_MANAGER_GET_MODULE_DATA_PATH_SYNC, event => {
|
||||
// This is kind of a lie... we offer no promise that moduleDataPath or modulePath are set.
|
||||
event.returnValue = getModulePath();
|
||||
});
|
|
@ -0,0 +1,89 @@
|
|||
"use strict";
|
||||
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var _url = require("url");
|
||||
var _processUtils = require("../../../common/processUtils");
|
||||
var _mainScreen = require("../../mainScreen");
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/* eslint-disable no-console */
|
||||
|
||||
let interactiveWindow = null;
|
||||
// let transparentWindow: electron.BrowserWindow | null = null;
|
||||
|
||||
// We need to be restrictive about what url's are accepted.
|
||||
function isValidUrl(url) {
|
||||
try {
|
||||
const parsedUrl = new _url.URL(url);
|
||||
if (parsedUrl.origin !== _mainScreen.WEBAPP_ENDPOINT) {
|
||||
console.error(`isValidUrl: "${parsedUrl.origin}" !== "${_mainScreen.WEBAPP_ENDPOINT}" (${url})`);
|
||||
return false;
|
||||
}
|
||||
if (parsedUrl.pathname !== '/overlay') {
|
||||
console.error(`isValidUrl: Invalid pathname "${parsedUrl.pathname}" (${url})`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(`isValidUrl: Error "${e}" (${url})`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.GLOBAL_OVERLAY_OPEN, (_, url) => {
|
||||
if (!_processUtils.IS_WIN) {
|
||||
console.log('GLOBAL_OVERLAY_OPEN: Windows only.');
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// TODO: Check if the url has changed...?
|
||||
if (interactiveWindow != null) {
|
||||
console.log('GLOBAL_OVERLAY_OPEN: Window already open.');
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (!isValidUrl(url)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// The title is randomized to prevent multiple instances from having conflicting titles.
|
||||
// We may want a global lock on there being a single global overlay tho.
|
||||
// TODO: The titlebar is blanked out by the javascript code, which is fine'ish for now because the mixture
|
||||
// of window class and window title are unique for the time being.
|
||||
const windowOptions = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
transparent: true,
|
||||
title: 'Discord_Overlay3' + Math.round(Math.random() * 1e9).toString(16),
|
||||
// TODO: For some reason, it does not workout if the window starts hidden. Perhaps it's not loading and the native
|
||||
// code isn't firing?
|
||||
// show: false, // It's shown when initialized by the native code.
|
||||
frame: false,
|
||||
// Sets WS_EX_NOACTIVATE, which keeps it out of the taskbar prior to our initialization running.
|
||||
// Disabled for the time being as it appears to make opening dev tools impossible.
|
||||
// focusable: true,
|
||||
webPreferences: {
|
||||
preload: _path.default.join(__dirname, '..', '..', 'mainScreenPreload.js'),
|
||||
nodeIntegration: false,
|
||||
sandbox: false,
|
||||
contextIsolation: true
|
||||
}
|
||||
};
|
||||
try {
|
||||
interactiveWindow = new _electron.default.BrowserWindow(windowOptions);
|
||||
interactiveWindow.once('closed', () => {
|
||||
// Untested code path.
|
||||
interactiveWindow = null;
|
||||
console.log('GLOBAL_OVERLAY_OPEN: closed');
|
||||
});
|
||||
|
||||
// Enable when finally working on the non-interactive layer.
|
||||
// transparentWindow = new electron.BrowserWindow(windowOptions);
|
||||
|
||||
interactiveWindow.loadURL(url + '#global_overlay');
|
||||
} catch (e) {
|
||||
console.log(`GLOBAL_OVERLAY_OPEN: Error "${e.text}"\n${e.stack}`);
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
|
@ -0,0 +1,25 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.injectGpuSettingsBackend = injectGpuSettingsBackend;
|
||||
// @ts-nocheck
|
||||
/* eslint-disable */
|
||||
const electron = require('electron');
|
||||
const {
|
||||
GPU_SETTINGS_SET_ENABLE_HWACCEL,
|
||||
GPU_SETTINGS_GET_ENABLE_HWACCEL_SYNC
|
||||
} = require('../common/constants').IPCEvents;
|
||||
let injectedGpuSettings = null;
|
||||
function injectGpuSettingsBackend(gpuSettings) {
|
||||
injectedGpuSettings = gpuSettings;
|
||||
}
|
||||
electron.ipcMain.handle(GPU_SETTINGS_SET_ENABLE_HWACCEL, async (_, enable) => {
|
||||
if (injectedGpuSettings) {
|
||||
injectedGpuSettings.setEnableHardwareAcceleration(enable);
|
||||
}
|
||||
});
|
||||
electron.ipcMain.on(GPU_SETTINGS_GET_ENABLE_HWACCEL_SYNC, event => {
|
||||
event.returnValue = injectedGpuSettings != null ? injectedGpuSettings.getEnableHardwareAcceleration() : false;
|
||||
});
|
|
@ -0,0 +1,97 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.injectModuleUpdater = injectModuleUpdater;
|
||||
exports.injectUpdater = injectUpdater;
|
||||
const childProcess = require('child_process');
|
||||
const electron = require('electron');
|
||||
const {
|
||||
once
|
||||
} = require('events');
|
||||
const path = require('path');
|
||||
const process = require('process');
|
||||
const {
|
||||
getGlobalPaths
|
||||
} = require('../../../common/nodeGlobalPaths');
|
||||
const {
|
||||
NATIVE_MODULES_GET_PATHS,
|
||||
NATIVE_MODULES_INSTALL,
|
||||
NATIVE_MODULES_FINISH_UPDATER_BOOTSTRAP,
|
||||
NATIVE_MODULES_GET_HAS_NEW_UPDATER
|
||||
} = require('../common/constants').IPCEvents;
|
||||
let injectedModuleUpdater = null;
|
||||
let injectedUpdater = null;
|
||||
function injectModuleUpdater(moduleUpdater) {
|
||||
injectedModuleUpdater = moduleUpdater;
|
||||
}
|
||||
function injectUpdater(updater) {
|
||||
injectedUpdater = updater;
|
||||
}
|
||||
electron.ipcMain.on(NATIVE_MODULES_GET_PATHS, event => {
|
||||
event.returnValue = {
|
||||
mainAppDirname: global.mainAppDirname,
|
||||
browserModulePaths: getGlobalPaths()
|
||||
};
|
||||
});
|
||||
async function newUpdaterInstall(updater, moduleName) {
|
||||
try {
|
||||
await updater.installModule(moduleName);
|
||||
await updater.commitModules();
|
||||
} catch (e) {
|
||||
throw new Error(`Failed to install ${moduleName}: ${e}`);
|
||||
}
|
||||
}
|
||||
electron.ipcMain.handle(NATIVE_MODULES_INSTALL, async (_, moduleName) => {
|
||||
var _injectedUpdater;
|
||||
const newUpdater = (_injectedUpdater = injectedUpdater) === null || _injectedUpdater === void 0 ? void 0 : _injectedUpdater.getUpdater();
|
||||
if (newUpdater != null) {
|
||||
return newUpdaterInstall(newUpdater, moduleName);
|
||||
}
|
||||
const updater = injectedModuleUpdater;
|
||||
if (!updater) {
|
||||
throw new Error('Module updater is not available!');
|
||||
}
|
||||
const waitForInstall = new Promise((resolve, reject) => {
|
||||
const installedHandler = installedModuleEvent => {
|
||||
if (installedModuleEvent.name === moduleName) {
|
||||
updater.events.removeListener(updater.INSTALLED_MODULE, installedHandler);
|
||||
if (installedModuleEvent.succeeded) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error(`Failed to install ${moduleName}`));
|
||||
}
|
||||
}
|
||||
};
|
||||
updater.events.on(updater.INSTALLED_MODULE, installedHandler);
|
||||
});
|
||||
updater.install(moduleName, false);
|
||||
await waitForInstall;
|
||||
});
|
||||
electron.ipcMain.on(NATIVE_MODULES_GET_HAS_NEW_UPDATER, event => {
|
||||
var _injectedUpdater2;
|
||||
event.returnValue = ((_injectedUpdater2 = injectedUpdater) === null || _injectedUpdater2 === void 0 ? void 0 : _injectedUpdater2.getUpdater()) != null;
|
||||
});
|
||||
|
||||
// This endpoint is a bit special in the sense that it's exposed from
|
||||
// discord_updater_bootstrap instead of discord_desktop_core. The reason for
|
||||
// this is so that a malicious app can't pass in an arbitrary version number to
|
||||
// launch.
|
||||
electron.ipcMain.on(NATIVE_MODULES_FINISH_UPDATER_BOOTSTRAP, async (_, [major, minor, revision]) => {
|
||||
// TODO(eiz): This code is currently duplicated between the updater and here
|
||||
// due to bootstrapping reasons. I'd like to not have it be that way.
|
||||
if (typeof major !== 'number' || typeof minor !== 'number' || typeof revision !== 'number') {
|
||||
throw new Error('You tried.');
|
||||
}
|
||||
const hostVersionStr = `${major}.${minor}.${revision}`;
|
||||
const hostExePath = path.join(path.dirname(process.execPath), '..', `app-${hostVersionStr}`, path.basename(process.execPath));
|
||||
electron.app.once('will-quit', () => {
|
||||
childProcess.spawn(hostExePath, [], {
|
||||
detached: true,
|
||||
stdio: 'inherit'
|
||||
});
|
||||
});
|
||||
console.log(`Restarting from ${path.resolve(process.execPath)} to ${path.resolve(hostExePath)}`);
|
||||
electron.app.quit();
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const {
|
||||
POWER_MONITOR_RESUME,
|
||||
POWER_MONITOR_SUSPEND,
|
||||
POWER_MONITOR_LOCK_SCREEN,
|
||||
POWER_MONITOR_UNLOCK_SCREEN,
|
||||
POWER_MONITOR_GET_SYSTEM_IDLE_TIME
|
||||
} = require('../common/constants').IPCEvents;
|
||||
electron.ipcMain.handle(POWER_MONITOR_GET_SYSTEM_IDLE_TIME, async _ => {
|
||||
return electron.powerMonitor.getSystemIdleTime() * 1000;
|
||||
});
|
||||
function sendToAllWindows(channel) {
|
||||
electron.BrowserWindow.getAllWindows().forEach(win => {
|
||||
const contents = win.webContents;
|
||||
if (contents != null) {
|
||||
contents.send(channel);
|
||||
}
|
||||
});
|
||||
}
|
||||
electron.powerMonitor.on('resume', () => {
|
||||
sendToAllWindows(POWER_MONITOR_RESUME);
|
||||
});
|
||||
electron.powerMonitor.on('suspend', () => {
|
||||
sendToAllWindows(POWER_MONITOR_SUSPEND);
|
||||
});
|
||||
electron.powerMonitor.on('lock-screen', () => {
|
||||
sendToAllWindows(POWER_MONITOR_LOCK_SCREEN);
|
||||
});
|
||||
electron.powerMonitor.on('unlock-screen', () => {
|
||||
sendToAllWindows(POWER_MONITOR_UNLOCK_SCREEN);
|
||||
});
|
|
@ -0,0 +1,25 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const {
|
||||
POWER_SAVE_BLOCKER_BLOCK_DISPLAY_SLEEP,
|
||||
POWER_SAVE_BLOCKER_UNBLOCK_DISPLAY_SLEEP,
|
||||
POWER_SAVE_BLOCKER_CLEANUP_DISPLAY_SLEEP
|
||||
} = require('../common/constants').IPCEvents;
|
||||
const powerSaveBlockerIds = new Set();
|
||||
electron.ipcMain.handle(POWER_SAVE_BLOCKER_BLOCK_DISPLAY_SLEEP, async _ => {
|
||||
const newId = electron.powerSaveBlocker.start('prevent-display-sleep');
|
||||
powerSaveBlockerIds.add(newId);
|
||||
return newId;
|
||||
});
|
||||
electron.ipcMain.handle(POWER_SAVE_BLOCKER_UNBLOCK_DISPLAY_SLEEP, async (_, id) => {
|
||||
electron.powerSaveBlocker.stop(id);
|
||||
powerSaveBlockerIds.delete(id);
|
||||
});
|
||||
electron.ipcMain.handle(POWER_SAVE_BLOCKER_CLEANUP_DISPLAY_SLEEP, async _ => {
|
||||
// cleanup all previous sleeps
|
||||
for (const id of powerSaveBlockerIds) {
|
||||
electron.powerSaveBlocker.stop(id);
|
||||
}
|
||||
powerSaveBlockerIds.clear();
|
||||
});
|
|
@ -0,0 +1,80 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.processUtilsSettings = void 0;
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _os = _interopRequireDefault(require("os"));
|
||||
var _process = _interopRequireDefault(require("process"));
|
||||
var _systeminformation = _interopRequireDefault(require("systeminformation"));
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
// Since crashes normally happen inside of the renderer process, we can store crash information inside of the
|
||||
// browser/main process, and report it back after the next startup.
|
||||
// lastRunsStoredInformation is set from currentStoredInformation, and currentStoredInformation is cleared on startup.
|
||||
const processUtilsSettings = {
|
||||
rendererCrashReason: null,
|
||||
rendererCrashExitCode: null,
|
||||
lastRunsStoredInformation: {},
|
||||
currentStoredInformation: {}
|
||||
};
|
||||
exports.processUtilsSettings = processUtilsSettings;
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_CPU_USAGE, _ => {
|
||||
let totalProcessorUsagePercent = 0.0;
|
||||
for (const processMetric of _electron.default.app.getAppMetrics()) {
|
||||
totalProcessorUsagePercent += processMetric.cpu.percentCPUUsage;
|
||||
}
|
||||
return Promise.resolve(totalProcessorUsagePercent);
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_LAST_CRASH, _ => {
|
||||
return Promise.resolve({
|
||||
..._electron.default.crashReporter.getLastCrashReport(),
|
||||
rendererCrashReason: processUtilsSettings.rendererCrashReason,
|
||||
rendererCrashExitCode: processUtilsSettings.rendererCrashExitCode,
|
||||
storedInformation: processUtilsSettings.lastRunsStoredInformation
|
||||
});
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_MEMORY_INFO, _ => {
|
||||
return _process.default.getProcessMemoryInfo();
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_SYSTEM_INFO, async _ => {
|
||||
const gpuInfo = await _systeminformation.default.graphics();
|
||||
return {
|
||||
cpus: _os.default.cpus().map(cpu => ({
|
||||
model: cpu.model,
|
||||
speed: cpu.speed
|
||||
})),
|
||||
gpus: gpuInfo.controllers.map(({
|
||||
model,
|
||||
vendor,
|
||||
vram
|
||||
}) => ({
|
||||
model,
|
||||
vendor,
|
||||
memory: vram ?? -1
|
||||
})),
|
||||
total_memory: _os.default.totalmem()
|
||||
};
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_FLUSH_DNS_CACHE, _ => {
|
||||
const defaultSession = _electron.default.session.defaultSession;
|
||||
if (defaultSession != null && defaultSession.clearHostResolverCache != null) {
|
||||
defaultSession.clearHostResolverCache();
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_FLUSH_COOKIES, _ => {
|
||||
return _electron.default.session.defaultSession.cookies.flushStore();
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_FLUSH_STORAGE_DATA, _ => {
|
||||
_electron.default.session.defaultSession.flushStorageData();
|
||||
return Promise.resolve();
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.on(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_MAIN_ARGV_SYNC, event => {
|
||||
event.returnValue = _process.default.argv;
|
||||
});
|
||||
_DiscordIPC.DiscordIPC.main.handle(_DiscordIPC.IPCEvents.PROCESS_UTILS_SET_CRASH_INFORMATION, (_, crashInformation, state) => {
|
||||
processUtilsSettings.currentStoredInformation[crashInformation] = state;
|
||||
return Promise.resolve();
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const {
|
||||
SAFE_STORAGE_IS_ENCRYPTION_AVAILABLE,
|
||||
SAFE_STORAGE_ENCRYPT_STRING,
|
||||
SAFE_STORAGE_DECRYPT_STRING
|
||||
} = require('../common/constants').IPCEvents;
|
||||
electron.ipcMain.on(SAFE_STORAGE_IS_ENCRYPTION_AVAILABLE, event => {
|
||||
event.returnValue = electron.safeStorage != null && electron.safeStorage.isEncryptionAvailable();
|
||||
});
|
||||
electron.ipcMain.on(SAFE_STORAGE_ENCRYPT_STRING, (event, plainText) => {
|
||||
if (plainText) {
|
||||
event.returnValue = electron.safeStorage.encryptString(plainText).toString('base64');
|
||||
} else {
|
||||
event.returnValue = null;
|
||||
}
|
||||
});
|
||||
electron.ipcMain.on(SAFE_STORAGE_DECRYPT_STRING, (event, encrypted) => {
|
||||
if (encrypted) {
|
||||
try {
|
||||
event.returnValue = electron.safeStorage.decryptString(Buffer.from(encrypted, 'base64'));
|
||||
} catch {
|
||||
event.returnValue = null;
|
||||
}
|
||||
} else {
|
||||
event.returnValue = null;
|
||||
}
|
||||
});
|
|
@ -0,0 +1,36 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.injectSettingsBackend = injectSettingsBackend;
|
||||
const electron = require('electron');
|
||||
const {
|
||||
SETTINGS_GET,
|
||||
SETTINGS_SET,
|
||||
SETTINGS_GET_SYNC
|
||||
} = require('../common/constants').IPCEvents;
|
||||
let injectedSettings = null;
|
||||
function getSettings() {
|
||||
return injectedSettings != null ? injectedSettings : {
|
||||
get: () => {},
|
||||
set: () => {},
|
||||
save: () => {}
|
||||
};
|
||||
}
|
||||
function injectSettingsBackend(settings) {
|
||||
injectedSettings = settings;
|
||||
}
|
||||
electron.ipcMain.handle(SETTINGS_GET, (_, name, defaultValue) => {
|
||||
const settings = getSettings();
|
||||
return settings.get(name, defaultValue);
|
||||
});
|
||||
electron.ipcMain.handle(SETTINGS_SET, (_, name, value) => {
|
||||
const settings = getSettings();
|
||||
settings.set(name, value);
|
||||
settings.save();
|
||||
});
|
||||
electron.ipcMain.on(SETTINGS_GET_SYNC, (event, name, defaultValue) => {
|
||||
const settings = getSettings();
|
||||
event.returnValue = settings.get(name, defaultValue);
|
||||
});
|
|
@ -0,0 +1,39 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const {
|
||||
SPELLCHECK_REPLACE_MISSPELLING,
|
||||
SPELLCHECK_GET_AVAILABLE_DICTIONARIES,
|
||||
SPELLCHECK_SET_LOCALE,
|
||||
SPELLCHECK_SET_LEARNED_WORDS
|
||||
} = require('../common/constants').IPCEvents;
|
||||
let _learnedWords = new Set();
|
||||
let _hasLoadedLearnedWords = false;
|
||||
electron.ipcMain.handle(SPELLCHECK_REPLACE_MISSPELLING, async (event, correction) => {
|
||||
event.sender.replaceMisspelling(correction);
|
||||
});
|
||||
electron.ipcMain.handle(SPELLCHECK_GET_AVAILABLE_DICTIONARIES, async _ => {
|
||||
return electron.session.defaultSession.availableSpellCheckerLanguages;
|
||||
});
|
||||
electron.ipcMain.handle(SPELLCHECK_SET_LOCALE, async (_, locale) => {
|
||||
electron.session.defaultSession.setSpellCheckerLanguages([locale]);
|
||||
});
|
||||
electron.ipcMain.handle(SPELLCHECK_SET_LEARNED_WORDS, async (_, newLearnedWords) => {
|
||||
const session = electron.session.defaultSession;
|
||||
if (!_hasLoadedLearnedWords) {
|
||||
const dictionaryContents = await session.listWordsInSpellCheckerDictionary();
|
||||
_learnedWords = new Set(dictionaryContents);
|
||||
_hasLoadedLearnedWords = true;
|
||||
}
|
||||
_learnedWords.forEach(word => {
|
||||
if (!newLearnedWords.has(word)) {
|
||||
session.removeWordFromSpellCheckerDictionary(word);
|
||||
}
|
||||
});
|
||||
newLearnedWords.forEach(word => {
|
||||
if (!_learnedWords.has(word)) {
|
||||
session.addWordToSpellCheckerDictionary(word);
|
||||
}
|
||||
});
|
||||
_learnedWords = new Set(newLearnedWords);
|
||||
});
|
|
@ -0,0 +1,54 @@
|
|||
"use strict";
|
||||
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var _appFeatures = require("../../appFeatures");
|
||||
var _paths = require("../../bootstrapModules/paths");
|
||||
var _constants = require("../common/constants");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
const {
|
||||
USER_DATA_CACHE_SAVE,
|
||||
USER_DATA_CACHE_GET,
|
||||
USER_DATA_CACHE_DELETE
|
||||
} = _constants.IPCEvents;
|
||||
const features = (0, _appFeatures.getFeatures)();
|
||||
function getCachePath() {
|
||||
return _path.default.join(_paths.paths.getUserData(), 'userDataCache.json');
|
||||
}
|
||||
function getMigratedPath() {
|
||||
return _path.default.join(_paths.paths.getUserData(), 'domainMigrated');
|
||||
}
|
||||
function cacheUserData(userData) {
|
||||
_fs.default.writeFile(getCachePath(), userData, e => {
|
||||
if (e) {
|
||||
console.warn('Failed updating user data cache with error: ', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
function getCachedUserData() {
|
||||
try {
|
||||
return JSON.parse(_fs.default.readFileSync(getCachePath()));
|
||||
} catch (_err) {}
|
||||
return null;
|
||||
}
|
||||
function deleteCachedUserData() {
|
||||
try {
|
||||
_fs.default.unlinkSync(getCachePath());
|
||||
_fs.default.writeFile(getMigratedPath(), '', e => {
|
||||
if (e) {
|
||||
console.warn('Failed to create domainMigrated file with error: ', e);
|
||||
}
|
||||
});
|
||||
} catch (_err) {}
|
||||
}
|
||||
_electron.default.ipcMain.handle(USER_DATA_CACHE_GET, () => {
|
||||
return getCachedUserData();
|
||||
});
|
||||
_electron.default.ipcMain.on(USER_DATA_CACHE_SAVE, (_event, userData) => {
|
||||
cacheUserData(userData);
|
||||
});
|
||||
_electron.default.ipcMain.on(USER_DATA_CACHE_DELETE, _event => {
|
||||
deleteCachedUserData();
|
||||
});
|
||||
features.declareSupported('user_data_cache');
|
|
@ -0,0 +1,97 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.injectGetWindow = injectGetWindow;
|
||||
const electron = require('electron');
|
||||
const process = require('process');
|
||||
const {
|
||||
WINDOW_BLUR,
|
||||
WINDOW_CLOSE,
|
||||
WINDOW_FOCUS,
|
||||
WINDOW_MAXIMIZE,
|
||||
WINDOW_MINIMIZE,
|
||||
WINDOW_RESTORE,
|
||||
WINDOW_FLASH_FRAME,
|
||||
WINDOW_TOGGLE_FULLSCREEN,
|
||||
WINDOW_SET_BACKGROUND_THROTTLING,
|
||||
WINDOW_SET_PROGRESS_BAR,
|
||||
WINDOW_IS_ALWAYS_ON_TOP,
|
||||
WINDOW_SET_ALWAYS_ON_TOP
|
||||
} = require('../common/constants').IPCEvents;
|
||||
let injectedGetWindow = _key => {
|
||||
return null;
|
||||
};
|
||||
function injectGetWindow(getWindow) {
|
||||
injectedGetWindow = getWindow;
|
||||
}
|
||||
electron.ipcMain.handle(WINDOW_FLASH_FRAME, async (_, flag) => {
|
||||
const currentWindow = injectedGetWindow();
|
||||
if (currentWindow == null || currentWindow.flashFrame == null) return;
|
||||
currentWindow.flashFrame(!currentWindow.isFocused() && flag);
|
||||
});
|
||||
electron.ipcMain.handle(WINDOW_MINIMIZE, async (_, key) => {
|
||||
const win = injectedGetWindow(key);
|
||||
if (win == null) return;
|
||||
win.minimize();
|
||||
});
|
||||
electron.ipcMain.handle(WINDOW_RESTORE, async (_, key) => {
|
||||
const win = injectedGetWindow(key);
|
||||
if (win == null) return;
|
||||
win.restore();
|
||||
});
|
||||
electron.ipcMain.handle(WINDOW_MAXIMIZE, async (_, key) => {
|
||||
const win = injectedGetWindow(key);
|
||||
if (win == null) return;
|
||||
if (win.isMaximized()) {
|
||||
win.unmaximize();
|
||||
} else {
|
||||
win.maximize();
|
||||
}
|
||||
});
|
||||
electron.ipcMain.handle(WINDOW_FOCUS, async (_, key) => {
|
||||
const win = injectedGetWindow(key);
|
||||
if (win == null) return;
|
||||
win.show();
|
||||
win.setSkipTaskbar(false);
|
||||
});
|
||||
electron.ipcMain.handle(WINDOW_SET_ALWAYS_ON_TOP, async (_, key, enabled) => {
|
||||
const win = injectedGetWindow(key);
|
||||
if (win == null) return;
|
||||
win.setAlwaysOnTop(enabled);
|
||||
});
|
||||
electron.ipcMain.handle(WINDOW_IS_ALWAYS_ON_TOP, async (_, key) => {
|
||||
const win = injectedGetWindow(key);
|
||||
if (win == null) return false;
|
||||
return win.isAlwaysOnTop();
|
||||
});
|
||||
electron.ipcMain.handle(WINDOW_BLUR, async (_, key) => {
|
||||
const win = injectedGetWindow(key);
|
||||
if (win != null && !win.isDestroyed()) {
|
||||
win.blur();
|
||||
}
|
||||
});
|
||||
electron.ipcMain.handle(WINDOW_SET_PROGRESS_BAR, async (_, key, progress) => {
|
||||
const win = injectedGetWindow(key);
|
||||
if (win == null) return;
|
||||
win.setProgressBar(progress);
|
||||
});
|
||||
electron.ipcMain.handle(WINDOW_TOGGLE_FULLSCREEN, async (_, key) => {
|
||||
const currentWindow = injectedGetWindow(key);
|
||||
currentWindow.setFullScreen(!currentWindow.isFullScreen());
|
||||
});
|
||||
electron.ipcMain.handle(WINDOW_CLOSE, async (_, key) => {
|
||||
if (key == null && process.platform === 'darwin') {
|
||||
electron.Menu.sendActionToFirstResponder('hide:');
|
||||
} else {
|
||||
const win = injectedGetWindow(key);
|
||||
if (win == null) return;
|
||||
win.close();
|
||||
}
|
||||
});
|
||||
electron.ipcMain.handle(WINDOW_SET_BACKGROUND_THROTTLING, async (_, enabled) => {
|
||||
const win = injectedGetWindow();
|
||||
if (win == null) return;
|
||||
win.webContents.setBackgroundThrottling(enabled);
|
||||
});
|
|
@ -0,0 +1,62 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.DiscordIPC = void 0;
|
||||
Object.defineProperty(exports, "IPCEvents", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _constants.IPCEvents;
|
||||
}
|
||||
});
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _constants = require("./constants");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/* eslint-disable prefer-spread */
|
||||
|
||||
// Save people from needing two imports.
|
||||
|
||||
class DiscordMainIPC {
|
||||
/**
|
||||
* For handling sync events.
|
||||
*/
|
||||
|
||||
static on(channel, listener) {
|
||||
_electron.default.ipcMain.on(channel, (...args) => {
|
||||
return listener.apply(this, args);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* For handling async events.
|
||||
*/
|
||||
|
||||
static handle(channel, listener) {
|
||||
return _electron.default.ipcMain.handle(channel, (...args) => {
|
||||
return listener.apply(this, args);
|
||||
});
|
||||
}
|
||||
}
|
||||
class DiscordRendererIPC {
|
||||
/**
|
||||
* For sending sync events.
|
||||
*/
|
||||
|
||||
static sendSync(...args) {
|
||||
return _electron.default.ipcRenderer.sendSync.apply(_electron.default.ipcRenderer, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* For sending async events.
|
||||
*/
|
||||
|
||||
static invoke(...args) {
|
||||
return _electron.default.ipcRenderer.invoke.apply(_electron.default.ipcRenderer, args);
|
||||
}
|
||||
}
|
||||
const DiscordIPC = {
|
||||
main: DiscordMainIPC,
|
||||
renderer: DiscordRendererIPC
|
||||
};
|
||||
exports.DiscordIPC = DiscordIPC;
|
|
@ -0,0 +1,116 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.IPCEvents = void 0;
|
||||
exports.getDiscordIPCEvent = getDiscordIPCEvent;
|
||||
const discordPrefixRegex = /^DISCORD_/;
|
||||
function getDiscordIPCEvent(ev) {
|
||||
return discordPrefixRegex.test(ev) ? ev : `DISCORD_${ev}`;
|
||||
}
|
||||
|
||||
// Namespace all event names with DISCORD_
|
||||
let IPCEvents;
|
||||
exports.IPCEvents = IPCEvents;
|
||||
(function (IPCEvents) {
|
||||
IPCEvents["ACCESSIBILITY_GET_ENABLED"] = "DISCORD_ACCESSIBILITY_GET_ENABLED";
|
||||
IPCEvents["APP_BADGE_SET"] = "DISCORD_APP_BADGE_SET";
|
||||
IPCEvents["APP_GET_RELEASE_CHANNEL_SYNC"] = "DISCORD_APP_GET_RELEASE_CHANNEL_SYNC";
|
||||
IPCEvents["APP_GET_HOST_VERSION_SYNC"] = "DISCORD_APP_GET_HOST_VERSION_SYNC";
|
||||
IPCEvents["APP_GET_BUILD_NUMBER"] = "DISCORD_APP_GET_BUILD_NUMBER";
|
||||
IPCEvents["APP_GET_MODULE_VERSIONS"] = "DISCORD_APP_GET_MODULE_VERSIONS";
|
||||
IPCEvents["APP_GET_PATH"] = "DISCORD_APP_GET_PATH";
|
||||
IPCEvents["APP_SET_BADGE_COUNT"] = "DISCORD_APP_SET_BADGE_COUNT";
|
||||
IPCEvents["APP_DOCK_SET_BADGE"] = "DISCORD_APP_DOCK_SET_BADGE";
|
||||
IPCEvents["APP_DOCK_BOUNCE"] = "DISCORD_APP_DOCK_BOUNCE";
|
||||
IPCEvents["APP_DOCK_CANCEL_BOUNCE"] = "DISCORD_APP_DOCK_CANCEL_BOUNCE";
|
||||
IPCEvents["APP_RELAUNCH"] = "DISCORD_APP_RELAUNCH";
|
||||
IPCEvents["APP_GET_DEFAULT_DOUBLE_CLICK_ACTION"] = "DISCORD_APP_GET_DEFAULT_DOUBLE_CLICK_ACTION";
|
||||
IPCEvents["CLIPBOARD_COPY"] = "DISCORD_CLIPBOARD_COPY";
|
||||
IPCEvents["CLIPBOARD_CUT"] = "DISCORD_CLIPBOARD_CUT";
|
||||
IPCEvents["CLIPBOARD_PASTE"] = "DISCORD_CLIPBOARD_PASTE";
|
||||
IPCEvents["LOAD_CLIP"] = "DISCORD_LOAD_CLIP";
|
||||
IPCEvents["LOAD_CLIPS_DIRECTORY"] = "DISCORD_LOAD_CLIPS_DIRECTORY";
|
||||
IPCEvents["DELETE_CLIP"] = "DISCORD_DELETE_CLIP";
|
||||
IPCEvents["CHECK_FOR_UPDATES"] = "DISCORD_CHECK_FOR_UPDATES";
|
||||
IPCEvents["DESKTOP_CAPTURER_GET_SOURCES"] = "DISCORD_DESKTOP_CAPTURER_GET_SOURCES";
|
||||
IPCEvents["CONSTANTS_GET"] = "DISCORD_CONSTANTS_GET";
|
||||
IPCEvents["CRASH_REPORTER_UPDATE_METADATA"] = "DISCORD_CRASH_REPORTER_UPDATE_METADATA";
|
||||
IPCEvents["FEATURES_GET_BROWSER_FEATURES"] = "DISCORD_FEATURES_GET_BROWSER_FEATURES";
|
||||
IPCEvents["FILE_MANAGER_GET_MODULE_PATH"] = "DISCORD_FILE_MANAGER_GET_MODULE_PATH";
|
||||
IPCEvents["FILE_MANAGER_GET_MODULE_DATA_PATH_SYNC"] = "DISCORD_FILE_MANAGER_GET_MODULE_DATA_PATH_SYNC";
|
||||
IPCEvents["FILE_MANAGER_SHOW_SAVE_DIALOG"] = "DISCORD_FILE_MANAGER_SHOW_SAVE_DIALOG";
|
||||
IPCEvents["FILE_MANAGER_SHOW_OPEN_DIALOG"] = "DISCORD_FILE_MANAGER_SHOW_OPEN_DIALOG";
|
||||
IPCEvents["FILE_MANAGER_SHOW_ITEM_IN_FOLDER"] = "DISCORD_FILE_MANAGER_SHOW_ITEM_IN_FOLDER";
|
||||
IPCEvents["GPU_SETTINGS_SET_ENABLE_HWACCEL"] = "DISCORD_GPU_SETTINGS_SET_ENABLE_HWACCEL";
|
||||
IPCEvents["GPU_SETTINGS_GET_ENABLE_HWACCEL_SYNC"] = "DISCORD_GPU_SETTINGS_GET_ENABLE_HWACCEL_SYNC";
|
||||
IPCEvents["NATIVE_MODULES_GET_PATHS"] = "DISCORD_NATIVE_MODULES_GET_PATHS";
|
||||
IPCEvents["NATIVE_MODULES_INSTALL"] = "DISCORD_NATIVE_MODULES_INSTALL";
|
||||
IPCEvents["NATIVE_MODULES_FINISH_UPDATER_BOOTSTRAP"] = "DISCORD_NATIVE_MODULES_FINISH_UPDATER_BOOTSTRAP";
|
||||
IPCEvents["NATIVE_MODULES_GET_HAS_NEW_UPDATER"] = "DISCORD_NATIVE_MODULES_GET_HAS_NEW_UPDATER";
|
||||
IPCEvents["NOTIFICATION_CLOSE"] = "DISCORD_NOTIFICATION_CLOSE";
|
||||
IPCEvents["NOTIFICATION_SHOW"] = "DISCORD_NOTIFICATION_SHOW";
|
||||
IPCEvents["NOTIFICATIONS_CLEAR"] = "DISCORD_NOTIFICATIONS_CLEAR";
|
||||
IPCEvents["OPEN_EXTERNAL_URL"] = "DISCORD_OPEN_EXTERNAL_URL";
|
||||
IPCEvents["GLOBAL_OVERLAY_OPEN"] = "DISCORD_GLOBAL_OVERLAY_OPEN";
|
||||
IPCEvents["POWER_MONITOR_RESUME"] = "DISCORD_POWER_MONITOR_RESUME";
|
||||
IPCEvents["POWER_MONITOR_SUSPEND"] = "DISCORD_POWER_MONITOR_SUSPEND";
|
||||
IPCEvents["POWER_MONITOR_LOCK_SCREEN"] = "DISCORD_POWER_MONITOR_LOCK_SCREEN";
|
||||
IPCEvents["POWER_MONITOR_UNLOCK_SCREEN"] = "DISCORD_POWER_MONITOR_UNLOCK_SCREEN";
|
||||
IPCEvents["POWER_MONITOR_GET_SYSTEM_IDLE_TIME"] = "DISCORD_POWER_MONITOR_GET_SYSTEM_IDLE_TIME";
|
||||
IPCEvents["POWER_SAVE_BLOCKER_BLOCK_DISPLAY_SLEEP"] = "DISCORD_POWER_SAVE_BLOCKER_BLOCK_DISPLAY_SLEEP";
|
||||
IPCEvents["POWER_SAVE_BLOCKER_UNBLOCK_DISPLAY_SLEEP"] = "DISCORD_POWER_SAVE_BLOCKER_UNBLOCK_DISPLAY_SLEEP";
|
||||
IPCEvents["POWER_SAVE_BLOCKER_CLEANUP_DISPLAY_SLEEP"] = "DISCORD_POWER_SAVE_BLOCKER_CLEANUP_DISPLAY_SLEEP";
|
||||
IPCEvents["PROCESS_UTILS_GET_CPU_USAGE"] = "DISCORD_PROCESS_UTILS_GET_CPU_USAGE";
|
||||
IPCEvents["PROCESS_UTILS_GET_MEMORY_INFO"] = "DISCORD_PROCESS_UTILS_GET_MEMORY_INFO";
|
||||
IPCEvents["PROCESS_UTILS_FLUSH_DNS_CACHE"] = "DISCORD_PROCESS_UTILS_FLUSH_DNS_CACHE";
|
||||
IPCEvents["PROCESS_UTILS_FLUSH_COOKIES"] = "DISCORD_PROCESS_UTILS_FLUSH_COOKIES";
|
||||
IPCEvents["PROCESS_UTILS_FLUSH_STORAGE_DATA"] = "DISCORD_PROCESS_UTILS_FLUSH_STORAGE_DATA";
|
||||
IPCEvents["PROCESS_UTILS_GET_MAIN_ARGV_SYNC"] = "DISCORD_PROCESS_UTILS_GET_MAIN_ARGV_SYNC";
|
||||
IPCEvents["PROCESS_UTILS_GET_LAST_CRASH"] = "DISCORD_PROCESS_UTILS_GET_LAST_CRASH";
|
||||
IPCEvents["PROCESS_UTILS_SET_CRASH_INFORMATION"] = "DISCORD_PROCESS_UTILS_SET_CRASH_INFORMATION";
|
||||
IPCEvents["PROCESS_UTILS_GET_SYSTEM_INFO"] = "DISCORD_PROCESS_UTILS_GET_SYSTEM_INFO";
|
||||
IPCEvents["QUIT_AND_INSTALL"] = "DISCORD_QUIT_AND_INSTALL";
|
||||
IPCEvents["SAFE_STORAGE_DECRYPT_STRING"] = "DISCORD_SAFE_STORAGE_DECRYPT_STRING";
|
||||
IPCEvents["SAFE_STORAGE_ENCRYPT_STRING"] = "DISCORD_SAFE_STORAGE_ENCRYPT_STRING";
|
||||
IPCEvents["SAFE_STORAGE_IS_ENCRYPTION_AVAILABLE"] = "DISCORD_SAFE_STORAGE_IS_ENCRYPTION_AVAILABLE";
|
||||
IPCEvents["SETTINGS_GET"] = "DISCORD_SETTINGS_GET";
|
||||
IPCEvents["SETTINGS_SET"] = "DISCORD_SETTINGS_SET";
|
||||
IPCEvents["SETTINGS_GET_SYNC"] = "DISCORD_SETTINGS_GET_SYNC";
|
||||
IPCEvents["SETTINGS_UPDATE_BACKGROUND_COLOR"] = "DISCORD_SETTINGS_UPDATE_BACKGROUND_COLOR";
|
||||
IPCEvents["SPELLCHECK_RESULT"] = "DISCORD_SPELLCHECK_RESULT";
|
||||
IPCEvents["SPELLCHECK_REPLACE_MISSPELLING"] = "DISCORD_SPELLCHECK_REPLACE_MISSPELLING";
|
||||
IPCEvents["SPELLCHECK_GET_AVAILABLE_DICTIONARIES"] = "DISCORD_SPELLCHECK_GET_AVAILABLE_DICTIONARIES";
|
||||
IPCEvents["SPELLCHECK_SET_LOCALE"] = "DISCORD_SPELLCHECK_SET_LOCALE";
|
||||
IPCEvents["SPELLCHECK_SET_LEARNED_WORDS"] = "DISCORD_SPELLCHECK_SET_LEARNED_WORDS";
|
||||
IPCEvents["SYSTEM_TRAY_SET_ICON"] = "DISCORD_SYSTEM_TRAY_SET_ICON";
|
||||
IPCEvents["SYSTEM_TRAY_SET_APPLICATIONS"] = "DISCORD_SYSTEM_TRAY_SET_APPLICATIONS";
|
||||
IPCEvents["THUMBAR_BUTTONS_UPDATE"] = "DISCORD_THUMBAR_BUTTONS_UPDATE";
|
||||
IPCEvents["THUMBAR_BUTTONS_CLICKED"] = "DISCORD_THUMBAR_BUTTONS_CLICKED";
|
||||
IPCEvents["TOGGLE_MINIMIZE_TO_TRAY"] = "DISCORD_TOGGLE_MINIMIZE_TO_TRAY";
|
||||
IPCEvents["TOGGLE_OPEN_ON_STARTUP"] = "DISCORD_TOGGLE_OPEN_ON_STARTUP";
|
||||
IPCEvents["TOGGLE_START_MINIMIZED"] = "DISCORD_TOGGLE_START_MINIMIZED";
|
||||
IPCEvents["UPDATE_OPEN_ON_STARTUP"] = "DISCORD_UPDATE_OPEN_ON_STARTUP";
|
||||
IPCEvents["UNHANDLED_JS_EXCEPTION"] = "DISCORD_UNHANDLED_JS_EXCEPTION";
|
||||
IPCEvents["UPDATER_HISTORY_QUERY_AND_TRUNCATE"] = "DISCORD_UPDATER_HISTORY_QUERY_AND_TRUNCATE";
|
||||
IPCEvents["UPDATED_QUOTES"] = "DISCORD_UPDATED_QUOTES";
|
||||
IPCEvents["USER_DATA_CACHE_DELETE"] = "DISCORD_USER_DATA_CACHE_DELETE";
|
||||
IPCEvents["USER_DATA_CACHE_GET"] = "DISCORD_USER_DATA_CACHE_GET";
|
||||
IPCEvents["USER_DATA_CACHE_SAVE"] = "DISCORD_USER_DATA_CACHE_SAVE";
|
||||
IPCEvents["WINDOW_BLUR"] = "DISCORD_WINDOW_BLUR";
|
||||
IPCEvents["WINDOW_CLOSE"] = "DISCORD_WINDOW_CLOSE";
|
||||
IPCEvents["WINDOW_FOCUS"] = "DISCORD_WINDOW_FOCUS";
|
||||
IPCEvents["WINDOW_MAXIMIZE"] = "DISCORD_WINDOW_MAXIMIZE";
|
||||
IPCEvents["WINDOW_MINIMIZE"] = "DISCORD_WINDOW_MINIMIZE";
|
||||
IPCEvents["WINDOW_RESTORE"] = "DISCORD_WINDOW_RESTORE";
|
||||
IPCEvents["WINDOW_FLASH_FRAME"] = "DISCORD_WINDOW_FLASH_FRAME";
|
||||
IPCEvents["WINDOW_TOGGLE_FULLSCREEN"] = "DISCORD_WINDOW_TOGGLE_FULLSCREEN";
|
||||
IPCEvents["WINDOW_SET_BACKGROUND_THROTTLING"] = "DISCORD_WINDOW_SET_BACKGROUND_THROTTLING";
|
||||
IPCEvents["WINDOW_SET_PROGRESS_BAR"] = "DISCORD_WINDOW_SET_PROGRESS_BAR";
|
||||
IPCEvents["WINDOW_IS_ALWAYS_ON_TOP"] = "DISCORD_WINDOW_IS_ALWAYS_ON_TOP";
|
||||
IPCEvents["WINDOW_SET_ALWAYS_ON_TOP"] = "DISCORD_WINDOW_SET_ALWAYS_ON_TOP";
|
||||
IPCEvents["WINDOW_DEVTOOLS_OPENED"] = "DISCORD_WINDOW_DEVTOOLS_OPENED";
|
||||
IPCEvents["WINDOW_DEVTOOLS_CLOSED"] = "DISCORD_WINDOW_DEVTOOLS_CLOSED";
|
||||
IPCEvents["GET_MOUSE_COORDINATES"] = "DISCORD_GET_MOUSE_COORDINATES";
|
||||
})(IPCEvents || (exports.IPCEvents = IPCEvents = {}));
|
|
@ -0,0 +1,105 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "basename", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _path.basename;
|
||||
}
|
||||
});
|
||||
exports.deleteFile = deleteFile;
|
||||
Object.defineProperty(exports, "dirname", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _path.dirname;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "extname", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _path.extname;
|
||||
}
|
||||
});
|
||||
exports.getFilesnamesFromDirectory = getFilesnamesFromDirectory;
|
||||
Object.defineProperty(exports, "join", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _path.join;
|
||||
}
|
||||
});
|
||||
exports.readFiles = readFiles;
|
||||
exports.readFulfilledFiles = readFulfilledFiles;
|
||||
var _buffer = _interopRequireDefault(require("buffer"));
|
||||
var _originalFs = _interopRequireDefault(require("original-fs"));
|
||||
var _path = _interopRequireWildcard(require("path"));
|
||||
var _util = _interopRequireDefault(require("util"));
|
||||
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 */
|
||||
|
||||
// eslint-disable-line import/no-unresolved
|
||||
|
||||
// Reason for original-fs being import/no-unresolved: https://github.com/discord/discord/pull/74159#discussion_r893733771
|
||||
|
||||
const MAX_LENGTH = _buffer.default.constants.MAX_LENGTH;
|
||||
const promiseFs = {
|
||||
readdir: _util.default.promisify(_originalFs.default.readdir),
|
||||
open: _util.default.promisify(_originalFs.default.open),
|
||||
fstat: _util.default.promisify(_originalFs.default.fstat),
|
||||
stat: _util.default.promisify(_originalFs.default.stat),
|
||||
unlink: _util.default.promisify(_originalFs.default.unlink),
|
||||
read: _util.default.promisify(_originalFs.default.read),
|
||||
close: _util.default.promisify(_originalFs.default.close)
|
||||
};
|
||||
|
||||
// Perform `readFiles` but only return `fulfilled` results.
|
||||
// If [orException] is set, exception if any of the results were rejected.
|
||||
async function readFulfilledFiles(filenames, maxSize, orException) {
|
||||
const files = await readFiles(filenames, maxSize);
|
||||
if (orException) {
|
||||
files.forEach(result => {
|
||||
if (result.status === 'rejected') {
|
||||
throw result.reason;
|
||||
}
|
||||
});
|
||||
}
|
||||
return files.filter(result => result.status === 'fulfilled').map(result => result.value);
|
||||
}
|
||||
function readFiles(filenames, maxSize) {
|
||||
maxSize = Math.min(maxSize, MAX_LENGTH);
|
||||
return Promise.allSettled(filenames.map(async filename => {
|
||||
const handle = await promiseFs.open(filename, 'r');
|
||||
try {
|
||||
const stats = await promiseFs.fstat(handle);
|
||||
if (maxSize != null && stats.size > maxSize) {
|
||||
// Used to help determine why openFiles failed.
|
||||
// Cannot use an error here because context bridge will remove the code field.
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw {
|
||||
code: 'ETOOLARGE',
|
||||
message: 'upload too large',
|
||||
filesize: stats.size,
|
||||
maxSize
|
||||
};
|
||||
}
|
||||
const buffer = Buffer.alloc(stats.size);
|
||||
const data = await promiseFs.read(handle, buffer, 0, stats.size, 0);
|
||||
return {
|
||||
data: data.buffer.slice(0, data.bytesRead),
|
||||
filename: _path.default.basename(filename)
|
||||
};
|
||||
} finally {
|
||||
promiseFs.close(handle); // No reason to await?
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
function getFilesnamesFromDirectory(path) {
|
||||
return promiseFs.readdir(path);
|
||||
}
|
||||
function deleteFile(filename) {
|
||||
return promiseFs.unlink(filename);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.getCrashFiles = getCrashFiles;
|
||||
exports.getPath = getPath;
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _originalFs = _interopRequireDefault(require("original-fs"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var _util = _interopRequireDefault(require("util"));
|
||||
var _processUtils = require("../../../common/processUtils");
|
||||
var _constants = require("../common/constants");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
const allowedAppPaths = new Set(['home', 'appData', 'desktop', 'documents', 'downloads', 'crashDumps']);
|
||||
const readdir = _util.default.promisify(_fs.default.readdir);
|
||||
async function getPath(path) {
|
||||
if (!allowedAppPaths.has(path)) {
|
||||
throw new Error(`${path} is not an allowed app path`);
|
||||
}
|
||||
return _electron.default.ipcRenderer.invoke(_constants.IPCEvents.APP_GET_PATH, path);
|
||||
}
|
||||
function getTimes(filenames) {
|
||||
return Promise.allSettled(filenames.map(filename => new Promise((resolve, reject) => {
|
||||
_originalFs.default.stat(filename, (err, stats) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
if (!stats.isFile()) {
|
||||
return reject(new Error('Not a file'));
|
||||
}
|
||||
return resolve({
|
||||
filename,
|
||||
mtime: stats.mtime
|
||||
});
|
||||
});
|
||||
})));
|
||||
}
|
||||
async function orderedFiles(folder) {
|
||||
try {
|
||||
const filenames = await readdir(folder);
|
||||
const times = await getTimes(filenames.map(filename => _path.default.join(folder, filename)));
|
||||
return times.filter(result => result.status === 'fulfilled').map(result => result.value).sort((a, b) => b.mtime.getTime() - a.mtime.getTime()).map(a => a.filename);
|
||||
} catch (err) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
async function getCrashFiles() {
|
||||
const crashBaseFolder = await getPath('crashDumps');
|
||||
const crashFolder = _processUtils.IS_WIN ? _path.default.join(crashBaseFolder, 'reports') : _path.default.join(crashBaseFolder, 'completed');
|
||||
return orderedFiles(crashFolder);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.isNotNullish = isNotNullish;
|
||||
/**
|
||||
* This function is primarly useful to type-erase the `null | undefined` in
|
||||
* filter statements, allowing you to write more ergonomic code down-the-line.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* values.filter(isNotNullish).map(v => v.toFoo());
|
||||
*/
|
||||
function isNotNullish(value) {
|
||||
return value != null;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
"use strict";
|
||||
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
function isAccessibilitySupportEnabled() {
|
||||
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.ACCESSIBILITY_GET_ENABLED);
|
||||
}
|
||||
module.exports = {
|
||||
isAccessibilitySupportEnabled
|
||||
};
|
|
@ -0,0 +1,90 @@
|
|||
"use strict";
|
||||
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
var _paths = require("../common/paths");
|
||||
var _crashReporter = require("./crashReporter");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
const releaseChannel = _DiscordIPC.DiscordIPC.renderer.sendSync(_DiscordIPC.IPCEvents.APP_GET_RELEASE_CHANNEL_SYNC);
|
||||
const hostVersion = _DiscordIPC.DiscordIPC.renderer.sendSync(_DiscordIPC.IPCEvents.APP_GET_HOST_VERSION_SYNC);
|
||||
const buildNumber = _DiscordIPC.DiscordIPC.renderer.sendSync(_DiscordIPC.IPCEvents.APP_GET_BUILD_NUMBER);
|
||||
(0, _crashReporter.updateCrashReporter)({
|
||||
nativeBuildNumber: (buildNumber === null || buildNumber === void 0 ? void 0 : buildNumber.toString()) ?? 'null'
|
||||
});
|
||||
let moduleVersions = {};
|
||||
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_GET_MODULE_VERSIONS).then(versions => {
|
||||
moduleVersions = versions;
|
||||
});
|
||||
|
||||
// TODO: Fix this .on to be part of our typing.
|
||||
_electron.default.ipcRenderer.on('DISCORD_MODULE_INSTALLED', async _ => {
|
||||
moduleVersions = await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_GET_MODULE_VERSIONS);
|
||||
});
|
||||
function getReleaseChannel() {
|
||||
return releaseChannel;
|
||||
}
|
||||
function getVersion() {
|
||||
return hostVersion;
|
||||
}
|
||||
function getBuildNumber() {
|
||||
return buildNumber;
|
||||
}
|
||||
function getModuleVersions() {
|
||||
return moduleVersions;
|
||||
}
|
||||
function setBadgeCount(count) {
|
||||
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_SET_BADGE_COUNT, count);
|
||||
return Promise.resolve();
|
||||
}
|
||||
function dockSetBadge(badge) {
|
||||
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_DOCK_SET_BADGE, badge);
|
||||
return Promise.resolve();
|
||||
}
|
||||
function dockBounce(type) {
|
||||
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_DOCK_BOUNCE, type);
|
||||
return Promise.resolve();
|
||||
}
|
||||
function dockCancelBounce(id) {
|
||||
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_DOCK_CANCEL_BOUNCE, id);
|
||||
return Promise.resolve();
|
||||
}
|
||||
function relaunch() {
|
||||
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_RELAUNCH);
|
||||
return Promise.resolve();
|
||||
}
|
||||
function getDefaultDoubleClickAction() {
|
||||
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.APP_GET_DEFAULT_DOUBLE_CLICK_ACTION);
|
||||
}
|
||||
function registerUserInteractionHandler(elementId, eventType, callback) {
|
||||
const element = document.getElementById(elementId);
|
||||
if (element == null) {
|
||||
throw new Error(`Element with id '${elementId}' was not found`);
|
||||
}
|
||||
function handleUserInteraction(ev) {
|
||||
if (!ev.isTrusted) {
|
||||
return;
|
||||
}
|
||||
callback(ev);
|
||||
}
|
||||
element.addEventListener(eventType, handleUserInteraction);
|
||||
return () => {
|
||||
element.removeEventListener(eventType, handleUserInteraction);
|
||||
};
|
||||
}
|
||||
module.exports = {
|
||||
getReleaseChannel,
|
||||
getVersion,
|
||||
getModuleVersions,
|
||||
getBuildNumber,
|
||||
getPath: _paths.getPath,
|
||||
// used via DiscordNative.remoteApp.getPath
|
||||
setBadgeCount,
|
||||
dock: {
|
||||
setBadge: dockSetBadge,
|
||||
bounce: dockBounce,
|
||||
cancelBounce: dockCancelBounce
|
||||
},
|
||||
relaunch,
|
||||
getDefaultDoubleClickAction,
|
||||
registerUserInteractionHandler
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
"use strict";
|
||||
|
||||
// @ts-nocheck
|
||||
/* eslint-disable */
|
||||
const electron = require('electron');
|
||||
const invariant = require('invariant');
|
||||
const {
|
||||
CLIPBOARD_COPY,
|
||||
CLIPBOARD_CUT,
|
||||
CLIPBOARD_PASTE
|
||||
} = require('../common/constants').IPCEvents;
|
||||
function copy(text) {
|
||||
if (text) {
|
||||
electron.clipboard.writeText(text);
|
||||
} else {
|
||||
electron.ipcRenderer.invoke(CLIPBOARD_COPY);
|
||||
}
|
||||
}
|
||||
function copyImage(imageArrayBuffer, imageSrc) {
|
||||
invariant(imageArrayBuffer != null, 'Image data is empty');
|
||||
const nativeImg = electron.nativeImage.createFromBuffer(imageArrayBuffer);
|
||||
electron.clipboard.write({
|
||||
html: `<img src="${imageSrc}">`,
|
||||
image: nativeImg
|
||||
});
|
||||
}
|
||||
function cut() {
|
||||
electron.ipcRenderer.invoke(CLIPBOARD_CUT);
|
||||
}
|
||||
function paste() {
|
||||
electron.ipcRenderer.invoke(CLIPBOARD_PASTE);
|
||||
}
|
||||
function read() {
|
||||
return electron.clipboard.readText();
|
||||
}
|
||||
module.exports = {
|
||||
copy,
|
||||
copyImage,
|
||||
cut,
|
||||
paste,
|
||||
read
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.deleteClip = deleteClip;
|
||||
exports.loadClip = loadClip;
|
||||
exports.loadClipsDirectory = loadClipsDirectory;
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
function loadClip(path) {
|
||||
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.LOAD_CLIP, path);
|
||||
}
|
||||
function loadClipsDirectory(path) {
|
||||
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.LOAD_CLIPS_DIRECTORY, path);
|
||||
}
|
||||
function deleteClip(path) {
|
||||
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.DELETE_CLIP, path);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.getMetadata = getMetadata;
|
||||
exports.triggerUnhandledException = triggerUnhandledException;
|
||||
exports.updateCrashReporter = updateCrashReporter;
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _crashReporterUtils = require("../../../common/crashReporterUtils");
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
let metadata = {};
|
||||
updateCrashReporter(metadata);
|
||||
async function updateCrashReporter(additionalMetadata) {
|
||||
const result = await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.CRASH_REPORTER_UPDATE_METADATA, additionalMetadata);
|
||||
metadata = result.metadata ?? {};
|
||||
(0, _crashReporterUtils.reconcileCrashReporterMetadata)(_electron.default.crashReporter, metadata);
|
||||
}
|
||||
function getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
// Internal test for unhandled JS exception
|
||||
async function triggerUnhandledException() {
|
||||
await _electron.default.ipcRenderer.invoke(_DiscordIPC.IPCEvents.UNHANDLED_JS_EXCEPTION);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
"use strict";
|
||||
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
async function getDesktopCaptureSources(options) {
|
||||
let sources = null;
|
||||
if (_electron.default.desktopCapturer != null) {
|
||||
// TODO(atlante45): For backwards compatibility with Electron 13, remove once we've fully
|
||||
// transitionned off of Electron 13
|
||||
sources = await _electron.default.desktopCapturer.getSources(options);
|
||||
} else {
|
||||
sources = await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.DESKTOP_CAPTURER_GET_SOURCES, options);
|
||||
}
|
||||
return sources.map(source => {
|
||||
return {
|
||||
id: source.id,
|
||||
name: source.name,
|
||||
url: source.thumbnail.toDataURL()
|
||||
};
|
||||
});
|
||||
}
|
||||
module.exports = {
|
||||
getDesktopCaptureSources
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
"use strict";
|
||||
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
const supportedFeatures = new Set(_DiscordIPC.DiscordIPC.renderer.sendSync(_DiscordIPC.IPCEvents.FEATURES_GET_BROWSER_FEATURES));
|
||||
function supports(feature) {
|
||||
return supportedFeatures.has(feature);
|
||||
}
|
||||
function declareSupported(feature) {
|
||||
supportedFeatures.add(feature);
|
||||
}
|
||||
module.exports = {
|
||||
supports,
|
||||
declareSupported
|
||||
};
|
|
@ -0,0 +1,167 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "basename", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _path.basename;
|
||||
}
|
||||
});
|
||||
exports.cleanupTempFiles = cleanupTempFiles;
|
||||
Object.defineProperty(exports, "dirname", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _path.dirname;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "extname", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _path.extname;
|
||||
}
|
||||
});
|
||||
exports.getModuleDataPathSync = getModuleDataPathSync;
|
||||
exports.getModulePath = getModulePath;
|
||||
Object.defineProperty(exports, "join", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _path.join;
|
||||
}
|
||||
});
|
||||
exports.openFiles = openFiles;
|
||||
exports.readLogFiles = readLogFiles;
|
||||
exports.readTimeSeriesLogFiles = readTimeSeriesLogFiles;
|
||||
exports.saveWithDialog = saveWithDialog;
|
||||
exports.showItemInFolder = showItemInFolder;
|
||||
exports.showOpenDialog = showOpenDialog;
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _originalFs = _interopRequireDefault(require("original-fs"));
|
||||
var _path = _interopRequireWildcard(require("path"));
|
||||
var _util = _interopRequireDefault(require("util"));
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
var _fileutils = require("../common/fileutils");
|
||||
var _paths = require("../common/paths");
|
||||
var _files = require("./files");
|
||||
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 */
|
||||
|
||||
// eslint-disable-line import/no-unresolved
|
||||
|
||||
// Reason for original-fs being import/no-unresolved: https://github.com/discord/discord/pull/74159#discussion_r893733771
|
||||
|
||||
const INVALID_FILENAME_CHAR_REGEX = /[^a-zA-Z0-9-_.]/g;
|
||||
const promiseFs = {
|
||||
readdir: _util.default.promisify(_originalFs.default.readdir),
|
||||
open: _util.default.promisify(_originalFs.default.open),
|
||||
fstat: _util.default.promisify(_originalFs.default.fstat),
|
||||
stat: _util.default.promisify(_originalFs.default.stat),
|
||||
unlink: _util.default.promisify(_originalFs.default.unlink),
|
||||
read: _util.default.promisify(_originalFs.default.read),
|
||||
close: _util.default.promisify(_originalFs.default.close)
|
||||
};
|
||||
async function saveWithDialog(fileContents, fileName) {
|
||||
if (INVALID_FILENAME_CHAR_REGEX.test(fileName)) {
|
||||
throw new Error('fileName has invalid characters');
|
||||
}
|
||||
const defaultPath = _path.default.join(await (0, _paths.getPath)('downloads'), fileName);
|
||||
const results = await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.FILE_MANAGER_SHOW_SAVE_DIALOG, {
|
||||
defaultPath
|
||||
});
|
||||
if (results != null && results.filePath != null) {
|
||||
_fs.default.writeFileSync(results.filePath, fileContents);
|
||||
}
|
||||
}
|
||||
async function showOpenDialog({
|
||||
filters,
|
||||
properties
|
||||
}) {
|
||||
const results = await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.FILE_MANAGER_SHOW_OPEN_DIALOG, {
|
||||
filters,
|
||||
properties
|
||||
});
|
||||
return results.filePaths;
|
||||
}
|
||||
async function readLogFiles(maxSize) {
|
||||
// MAX_DEBUG_LOG_FILES may need to be increased as more files are added.
|
||||
const modulePath = await getModulePath();
|
||||
const voicePath = _path.default.join(modulePath, 'discord_voice');
|
||||
const hookPath = _path.default.join(modulePath, 'discord_hook');
|
||||
const utilsPath = _path.default.join(modulePath, 'discord_utils');
|
||||
const filesToUpload = [_path.default.join(voicePath, 'discord-webrtc_0'), _path.default.join(voicePath, 'discord-webrtc_1'), _path.default.join(voicePath, 'discord-last-webrtc_0'), _path.default.join(voicePath, 'discord-last-webrtc_1'), _path.default.join(voicePath, 'audio_state.json'), _path.default.join(hookPath, 'hook.log'), _path.default.join(utilsPath, 'live_minidump.dmp')];
|
||||
const crashFiles = await (0, _paths.getCrashFiles)();
|
||||
if (crashFiles.length > 0) {
|
||||
filesToUpload.push(crashFiles[0]);
|
||||
}
|
||||
return (0, _fileutils.readFulfilledFiles)(filesToUpload, maxSize, false);
|
||||
}
|
||||
async function readTimeSeriesLogFiles(maxSize, blindChannelId) {
|
||||
if (blindChannelId == null) {
|
||||
console.error('readTimeSeriesLogFiles: blindChannelId missing.');
|
||||
return [];
|
||||
}
|
||||
const modulePath = await getModulePath();
|
||||
const voicePath = _path.default.join(modulePath, 'discord_voice');
|
||||
// Example filename: "channel.17812072731293278934.16605628624321906260.tsi"
|
||||
const filter = new RegExp(`^channel\\.${blindChannelId}\\.\\d+\\.(?:tsi|tsd)$`, 'i');
|
||||
const filenames = [];
|
||||
for (const file of await promiseFs.readdir(voicePath)) {
|
||||
if (filter.test(file)) {
|
||||
filenames.push(_path.default.join(voicePath, file));
|
||||
}
|
||||
}
|
||||
const allLogFiles = [...filenames];
|
||||
const maxLogFiles = 10; // 10 is arbitrary but seems reasonable as each would be ~1mb.
|
||||
if (filenames.length > maxLogFiles) {
|
||||
console.warn(`readTimeSeriesLogFiles: Exceeded limit of ${maxLogFiles} files, had ${filenames.length}.`);
|
||||
filenames.splice(maxLogFiles);
|
||||
}
|
||||
const readfiles = await (0, _fileutils.readFulfilledFiles)(filenames, maxSize, false);
|
||||
// Delete the files after they've been read.
|
||||
await Promise.all(allLogFiles.map(filename => promiseFs.unlink(filename)));
|
||||
return readfiles;
|
||||
}
|
||||
async function cleanupTempFiles() {
|
||||
// Since this runs on startup, handle and report all errors as cleanly as possible.
|
||||
try {
|
||||
const modulePath = await getModulePath();
|
||||
const voicePath = _path.default.join(modulePath, 'discord_voice');
|
||||
const deleteAgeTimeSpan = 1 * 24 * 60 * 60 * 1000; // 1 day.
|
||||
const deleteAge = new Date(Date.now() - deleteAgeTimeSpan);
|
||||
for (const filename of await promiseFs.readdir(voicePath)) {
|
||||
if (!(0, _files.isTempFile)(filename)) {
|
||||
continue;
|
||||
}
|
||||
const fullpath = _path.default.join(voicePath, filename);
|
||||
const stat = await promiseFs.stat(fullpath);
|
||||
if (!stat.isFile() || stat.mtime > deleteAge) {
|
||||
continue;
|
||||
}
|
||||
console.log(`cleanupTempFiles: Deleting "${fullpath}" due to age.`);
|
||||
try {
|
||||
await promiseFs.unlink(fullpath);
|
||||
} catch (e) {
|
||||
console.error(`cleanupTempFiles: Failed to unlink ${fullpath}: ${e}`);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`cleanupTempFiles: Failed ${e}`);
|
||||
}
|
||||
}
|
||||
function showItemInFolder(path) {
|
||||
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.FILE_MANAGER_SHOW_ITEM_IN_FOLDER, path);
|
||||
return Promise.resolve();
|
||||
}
|
||||
async function openFiles(dialogOptions, maxSize) {
|
||||
const filenames = await showOpenDialog(dialogOptions);
|
||||
return (0, _fileutils.readFulfilledFiles)(filenames, maxSize, true);
|
||||
}
|
||||
function getModulePath() {
|
||||
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.FILE_MANAGER_GET_MODULE_PATH);
|
||||
}
|
||||
function getModuleDataPathSync() {
|
||||
return _DiscordIPC.DiscordIPC.renderer.sendSync(_DiscordIPC.IPCEvents.FILE_MANAGER_GET_MODULE_DATA_PATH_SYNC);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.isTempFile = isTempFile;
|
||||
function isTempFile(filename) {
|
||||
return /(?:^channel\..+(?:tsi|tsd)$)|(?:^\.tmp.+)/i.test(filename);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.openOverlay = openOverlay;
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
function openOverlay(url) {
|
||||
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.GLOBAL_OVERLAY_OPEN, url);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
"use strict";
|
||||
|
||||
// @ts-nocheck
|
||||
/* eslint-disable */
|
||||
const electron = require('electron');
|
||||
const {
|
||||
GPU_SETTINGS_SET_ENABLE_HWACCEL,
|
||||
GPU_SETTINGS_GET_ENABLE_HWACCEL_SYNC
|
||||
} = require('../common/constants').IPCEvents;
|
||||
const hardwareAccelerationEnabled = electron.ipcRenderer.sendSync(GPU_SETTINGS_GET_ENABLE_HWACCEL_SYNC);
|
||||
function getEnableHardwareAcceleration() {
|
||||
return hardwareAccelerationEnabled;
|
||||
}
|
||||
async function setEnableHardwareAcceleration(enable) {
|
||||
electron.ipcRenderer.invoke(GPU_SETTINGS_SET_ENABLE_HWACCEL, enable);
|
||||
}
|
||||
module.exports = {
|
||||
getEnableHardwareAcceleration,
|
||||
setEnableHardwareAcceleration
|
||||
};
|
|
@ -0,0 +1,96 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const http = require('http');
|
||||
const https = require('https');
|
||||
const {
|
||||
CONSTANTS_GET
|
||||
} = require('../common/constants').IPCEvents;
|
||||
async function getAPIEndpoint() {
|
||||
const apiEndpoint = await electron.ipcRenderer.invoke(CONSTANTS_GET, 'API_ENDPOINT');
|
||||
if (apiEndpoint == null || apiEndpoint === '') {
|
||||
return null;
|
||||
}
|
||||
return apiEndpoint;
|
||||
}
|
||||
async function makeChunkedRequest(route, chunks, options) {
|
||||
/**
|
||||
* Given an array of chunks, make a slow request, only writing chunks
|
||||
* after a specified amount of time
|
||||
*
|
||||
* route: string
|
||||
* options: object
|
||||
* method: the method of the request
|
||||
* contentType: the content type of the request
|
||||
* chunkInterval: how long to wait to upload a chunk after the last chunk was flushed
|
||||
* token: the token to make an authorized request from
|
||||
* chunks: chunked body of the request to upload
|
||||
*/
|
||||
|
||||
const {
|
||||
method,
|
||||
chunkInterval,
|
||||
token,
|
||||
contentType
|
||||
} = options;
|
||||
let httpModule = http;
|
||||
if (route.startsWith('https')) {
|
||||
httpModule = https;
|
||||
}
|
||||
|
||||
// we will force the URL to hit only API_ENDPOINT
|
||||
const apiEndpoint = await getAPIEndpoint();
|
||||
if (apiEndpoint == null) {
|
||||
throw new Error('missing api endpoint setting');
|
||||
}
|
||||
const apiEndpointUrl = new URL(apiEndpoint);
|
||||
const url = new URL(route, apiEndpoint);
|
||||
url.protocol = apiEndpointUrl.protocol;
|
||||
url.host = apiEndpointUrl.host;
|
||||
if (!url.pathname.startsWith(apiEndpointUrl.pathname)) {
|
||||
url.pathname = `${apiEndpointUrl.pathname}${url.pathname}`;
|
||||
}
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let writeTimeout;
|
||||
const req = httpModule.request(url.toString(), {
|
||||
method,
|
||||
headers: {
|
||||
authorization: token,
|
||||
'Content-Type': contentType,
|
||||
'Content-Length': Buffer.byteLength(chunks.join(''))
|
||||
}
|
||||
}, res => {
|
||||
let responseData = '';
|
||||
res.setEncoding('utf8');
|
||||
res.on('data', chunk => {
|
||||
responseData += chunk;
|
||||
});
|
||||
res.on('end', () => {
|
||||
resolve({
|
||||
status: res.statusCode,
|
||||
body: responseData
|
||||
});
|
||||
});
|
||||
});
|
||||
req.on('error', e => {
|
||||
if (writeTimeout != null) {
|
||||
clearTimeout(writeTimeout);
|
||||
}
|
||||
reject(e);
|
||||
});
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
await new Promise(resolve => {
|
||||
req.write(chunks[i], () => {
|
||||
writeTimeout = setTimeout(resolve, chunkInterval);
|
||||
});
|
||||
});
|
||||
}
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
module.exports = {
|
||||
getAPIEndpoint,
|
||||
makeChunkedRequest: function (route, chunks, options, callback) {
|
||||
makeChunkedRequest(route, chunks, options).then(body => callback(null, body)).catch(err => callback(err));
|
||||
}
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const {
|
||||
getDiscordIPCEvent,
|
||||
IPCEvents
|
||||
} = require('../common/constants');
|
||||
const ipcRenderer = electron.ipcRenderer;
|
||||
const RENDERER_IPC_SEND_WHITELIST = new Set([IPCEvents.APP_BADGE_SET, IPCEvents.CHECK_FOR_UPDATES, IPCEvents.NOTIFICATION_CLOSE, IPCEvents.NOTIFICATION_SHOW, IPCEvents.NOTIFICATIONS_CLEAR, IPCEvents.OPEN_EXTERNAL_URL, IPCEvents.QUIT_AND_INSTALL, IPCEvents.SETTINGS_UPDATE_BACKGROUND_COLOR, IPCEvents.SYSTEM_TRAY_SET_ICON, IPCEvents.SYSTEM_TRAY_SET_APPLICATIONS, IPCEvents.THUMBAR_BUTTONS_UPDATE, IPCEvents.TOGGLE_MINIMIZE_TO_TRAY, IPCEvents.TOGGLE_OPEN_ON_STARTUP, IPCEvents.TOGGLE_START_MINIMIZED, IPCEvents.UPDATE_OPEN_ON_STARTUP, IPCEvents.UPDATER_HISTORY_QUERY_AND_TRUNCATE, IPCEvents.UPDATED_QUOTES]);
|
||||
const RENDERER_IPC_INVOKE_WHITELIST = new Set([IPCEvents.GET_MOUSE_COORDINATES]);
|
||||
function send(ev, ...args) {
|
||||
const prefixedEvent = getDiscordIPCEvent(ev);
|
||||
if (!RENDERER_IPC_SEND_WHITELIST.has(prefixedEvent)) {
|
||||
throw new Error('cannot send this event');
|
||||
}
|
||||
ipcRenderer.send(prefixedEvent, ...args);
|
||||
}
|
||||
function on(ev, callback) {
|
||||
ipcRenderer.on(getDiscordIPCEvent(ev), function () {
|
||||
// Sender is dangerous, do not expose.
|
||||
callback.apply(callback, [null, ...[...arguments].slice(1)]);
|
||||
});
|
||||
}
|
||||
function invoke(ev, ...args) {
|
||||
const prefixedEvent = getDiscordIPCEvent(ev);
|
||||
if (!RENDERER_IPC_INVOKE_WHITELIST.has(prefixedEvent)) {
|
||||
throw new Error('cannot invoke this event');
|
||||
}
|
||||
return ipcRenderer.invoke(prefixedEvent, ...args);
|
||||
}
|
||||
module.exports = {
|
||||
send,
|
||||
on,
|
||||
invoke
|
||||
};
|
|
@ -0,0 +1,458 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.readMinidump = readMinidump;
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _util = _interopRequireDefault(require("util"));
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
const exceptionTypes = {
|
||||
C0000005: 'EXCEPTION_ACCESS_VIOLATION',
|
||||
'80000002': 'EXCEPTION_DATATYPE_MISALIGNMENT',
|
||||
'80000003': 'EXCEPTION_BREAKPOINT',
|
||||
'80000004': 'EXCEPTION_SINGLE_STEP',
|
||||
C000008C: 'EXCEPTION_ARRAY_BOUNDS_EXCEEDED',
|
||||
C000008D: 'EXCEPTION_FLT_DENORMAL_OPERAND',
|
||||
C000008E: 'EXCEPTION_FLT_DIVIDE_BY_ZERO',
|
||||
C000008F: 'EXCEPTION_FLT_INEXACT_RESULT',
|
||||
C0000090: 'EXCEPTION_FLT_INVALID_OPERATION',
|
||||
C0000091: 'EXCEPTION_FLT_OVERFLOW',
|
||||
C0000092: 'EXCEPTION_FLT_STACK_CHECK',
|
||||
C0000093: 'EXCEPTION_FLT_UNDERFLOW',
|
||||
C0000094: 'EXCEPTION_INT_DIVIDE_BY_ZERO',
|
||||
C0000095: 'EXCEPTION_INT_OVERFLOW',
|
||||
C0000096: 'EXCEPTION_PRIV_INSTRUCTION',
|
||||
C0000006: 'EXCEPTION_IN_PAGE_ERROR',
|
||||
C000001D: 'EXCEPTION_ILLEGAL_INSTRUCTION',
|
||||
C0000025: 'EXCEPTION_NONCONTINUABLE_EXCEPTION',
|
||||
C00000FD: 'EXCEPTION_STACK_OVERFLOW',
|
||||
C0000026: 'EXCEPTION_INVALID_DISPOSITION',
|
||||
'80000001': 'EXCEPTION_GUARD_PAGE',
|
||||
C0000008: 'EXCEPTION_INVALID_HANDLE'
|
||||
};
|
||||
class FileReader {
|
||||
utf16Decoder = new _util.default.TextDecoder('utf-16');
|
||||
static promiseFs = Object.freeze({
|
||||
open: _util.default.promisify(_fs.default.open),
|
||||
read: _util.default.promisify(_fs.default.read),
|
||||
close: _util.default.promisify(_fs.default.close)
|
||||
});
|
||||
constructor(path, bufferSize = 2048) {
|
||||
this.handle = FileReader.promiseFs.open(path, 'r');
|
||||
this.buffer = new Uint8Array(bufferSize);
|
||||
}
|
||||
async read(u32toReadCount, position = null) {
|
||||
const byteSize = u32toReadCount * 4;
|
||||
await this.readCore(byteSize, position);
|
||||
return new ReadResult(this.buffer.buffer.slice(0, byteSize));
|
||||
}
|
||||
async readMinidumpString(rva) {
|
||||
if (rva === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_string
|
||||
await this.readCore(4, rva);
|
||||
const length = this.buffer[0] | this.buffer[1] << 8 | this.buffer[2] << 16 | this.buffer[3] << 24;
|
||||
await this.readCore(Math.min(length, this.buffer.byteLength), rva + 4);
|
||||
return this.utf16Decoder.decode(this.buffer.slice(0, length));
|
||||
}
|
||||
async readCore(byteLength, position = null) {
|
||||
if (byteLength > this.buffer.byteLength) {
|
||||
throw new Error(`Requested nuber of bytes ${byteLength} exceeds buffer size ${this.buffer.byteLength}.`);
|
||||
}
|
||||
if (this.handle == null) {
|
||||
throw new Error('Cannot use FileReader once closed.');
|
||||
}
|
||||
const handle = await this.handle;
|
||||
const readResult = await FileReader.promiseFs.read(handle, this.buffer, 0, byteLength, position);
|
||||
if (readResult.bytesRead < byteLength) {
|
||||
throw new Error(`FileReader failed to read enough bytes: 0x${readResult.bytesRead}`);
|
||||
}
|
||||
}
|
||||
async close() {
|
||||
if (this.handle == null) {
|
||||
return;
|
||||
}
|
||||
const handle = await this.handle;
|
||||
this.handle = null;
|
||||
await FileReader.promiseFs.close(handle);
|
||||
}
|
||||
}
|
||||
class ReadResult {
|
||||
index = 0;
|
||||
// irl, this should likely take the uint8 and work from there, but this is fine for us.
|
||||
// Maybe just steal my other impl here https://github.com/jlennox/WebWad/blob/main/wad.ts#L8
|
||||
// but we likely don't want to load the entire file at once. But who knows, maybe the system
|
||||
// call reduction is better and/or it irl doesn't matter either way.
|
||||
constructor(buffer) {
|
||||
this.u8 = new Uint8Array(buffer);
|
||||
this.u16 = new Uint16Array(buffer);
|
||||
this.u32 = new Uint32Array(buffer);
|
||||
}
|
||||
seek(index) {
|
||||
this.index = index;
|
||||
}
|
||||
readuint32() {
|
||||
const val = this.u32[this.index / 4];
|
||||
this.index += 4;
|
||||
return val;
|
||||
}
|
||||
readuint16() {
|
||||
const val = this.u16[this.index / 2];
|
||||
this.index += 2;
|
||||
return val;
|
||||
}
|
||||
readByteArray(count) {
|
||||
const val = Array.from(this.u8.slice(this.index, this.index + count));
|
||||
this.index += count;
|
||||
return val;
|
||||
}
|
||||
readuint64() {
|
||||
const u32Index = this.index / 4;
|
||||
const val = BigInt(this.u32[u32Index]) | BigInt(this.u32[u32Index + 1]) << BigInt(32);
|
||||
this.index += 8;
|
||||
return val;
|
||||
}
|
||||
}
|
||||
function isMinidumpFilename(filename) {
|
||||
return /\.dmp$/i.test(filename);
|
||||
}
|
||||
var MinidumpStreamType; // https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_header
|
||||
(function (MinidumpStreamType) {
|
||||
MinidumpStreamType[MinidumpStreamType["UnusedStream"] = 0] = "UnusedStream";
|
||||
MinidumpStreamType[MinidumpStreamType["ReservedStream0"] = 1] = "ReservedStream0";
|
||||
MinidumpStreamType[MinidumpStreamType["ReservedStream1"] = 2] = "ReservedStream1";
|
||||
MinidumpStreamType[MinidumpStreamType["ThreadListStream"] = 3] = "ThreadListStream";
|
||||
MinidumpStreamType[MinidumpStreamType["ModuleListStream"] = 4] = "ModuleListStream";
|
||||
MinidumpStreamType[MinidumpStreamType["MemoryListStream"] = 5] = "MemoryListStream";
|
||||
MinidumpStreamType[MinidumpStreamType["ExceptionStream"] = 6] = "ExceptionStream";
|
||||
MinidumpStreamType[MinidumpStreamType["SystemInfoStream"] = 7] = "SystemInfoStream";
|
||||
MinidumpStreamType[MinidumpStreamType["ThreadExListStream"] = 8] = "ThreadExListStream";
|
||||
MinidumpStreamType[MinidumpStreamType["Memory64ListStream"] = 9] = "Memory64ListStream";
|
||||
MinidumpStreamType[MinidumpStreamType["CommentStreamA"] = 10] = "CommentStreamA";
|
||||
MinidumpStreamType[MinidumpStreamType["CommentStreamW"] = 11] = "CommentStreamW";
|
||||
MinidumpStreamType[MinidumpStreamType["HandleDataStream"] = 12] = "HandleDataStream";
|
||||
MinidumpStreamType[MinidumpStreamType["FunctionTableStream"] = 13] = "FunctionTableStream";
|
||||
MinidumpStreamType[MinidumpStreamType["UnloadedModuleListStream"] = 14] = "UnloadedModuleListStream";
|
||||
MinidumpStreamType[MinidumpStreamType["MiscInfoStream"] = 15] = "MiscInfoStream";
|
||||
MinidumpStreamType[MinidumpStreamType["MemoryInfoListStream"] = 16] = "MemoryInfoListStream";
|
||||
MinidumpStreamType[MinidumpStreamType["ThreadInfoListStream"] = 17] = "ThreadInfoListStream";
|
||||
MinidumpStreamType[MinidumpStreamType["HandleOperationListStream"] = 18] = "HandleOperationListStream";
|
||||
MinidumpStreamType[MinidumpStreamType["TokenStream"] = 19] = "TokenStream";
|
||||
MinidumpStreamType[MinidumpStreamType["JavaScriptDataStream"] = 20] = "JavaScriptDataStream";
|
||||
MinidumpStreamType[MinidumpStreamType["SystemMemoryInfoStream"] = 21] = "SystemMemoryInfoStream";
|
||||
MinidumpStreamType[MinidumpStreamType["ProcessVmCountersStream"] = 22] = "ProcessVmCountersStream";
|
||||
MinidumpStreamType[MinidumpStreamType["IptTraceStream"] = 23] = "IptTraceStream";
|
||||
MinidumpStreamType[MinidumpStreamType["ThreadNamesStream"] = 24] = "ThreadNamesStream";
|
||||
MinidumpStreamType[MinidumpStreamType["ceStreamNull"] = 32768] = "ceStreamNull";
|
||||
MinidumpStreamType[MinidumpStreamType["ceStreamSystemInfo"] = 32769] = "ceStreamSystemInfo";
|
||||
MinidumpStreamType[MinidumpStreamType["ceStreamException"] = 32770] = "ceStreamException";
|
||||
MinidumpStreamType[MinidumpStreamType["ceStreamModuleList"] = 32771] = "ceStreamModuleList";
|
||||
MinidumpStreamType[MinidumpStreamType["ceStreamProcessList"] = 32772] = "ceStreamProcessList";
|
||||
MinidumpStreamType[MinidumpStreamType["ceStreamThreadList"] = 32773] = "ceStreamThreadList";
|
||||
MinidumpStreamType[MinidumpStreamType["ceStreamThreadContextList"] = 32774] = "ceStreamThreadContextList";
|
||||
MinidumpStreamType[MinidumpStreamType["ceStreamThreadCallStackList"] = 32775] = "ceStreamThreadCallStackList";
|
||||
MinidumpStreamType[MinidumpStreamType["ceStreamMemoryVirtualList"] = 32776] = "ceStreamMemoryVirtualList";
|
||||
MinidumpStreamType[MinidumpStreamType["ceStreamMemoryPhysicalList"] = 32777] = "ceStreamMemoryPhysicalList";
|
||||
MinidumpStreamType[MinidumpStreamType["ceStreamBucketParameters"] = 32778] = "ceStreamBucketParameters";
|
||||
MinidumpStreamType[MinidumpStreamType["ceStreamProcessModuleMap"] = 32779] = "ceStreamProcessModuleMap";
|
||||
MinidumpStreamType[MinidumpStreamType["ceStreamDiagnosisList"] = 32780] = "ceStreamDiagnosisList";
|
||||
MinidumpStreamType[MinidumpStreamType["LastReservedStream"] = 65535] = "LastReservedStream";
|
||||
})(MinidumpStreamType || (MinidumpStreamType = {}));
|
||||
class MINIDUMP_HEADER {
|
||||
static U32_SIZE = 4;
|
||||
constructor(reader) {
|
||||
this.signature = reader.readuint32();
|
||||
this.version = reader.readuint32();
|
||||
this.numberOfStreams = reader.readuint32();
|
||||
this.streamDirectoryOffset = reader.readuint32();
|
||||
}
|
||||
static async read(reader, position) {
|
||||
return new MINIDUMP_HEADER(await reader.read(MINIDUMP_HEADER.U32_SIZE, position));
|
||||
}
|
||||
}
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_directory
|
||||
class MINIDUMP_DIRECTORY {
|
||||
static U32_SIZE = 3;
|
||||
constructor(reader) {
|
||||
this.streamType = reader.readuint32();
|
||||
this.dataSize = reader.readuint32();
|
||||
this.dataOffset = reader.readuint32();
|
||||
}
|
||||
static async read(reader, position) {
|
||||
return new MINIDUMP_DIRECTORY(await reader.read(MINIDUMP_DIRECTORY.U32_SIZE, position));
|
||||
}
|
||||
}
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_exception_stream
|
||||
class MINIDUMP_EXCEPTION_STREAM {
|
||||
static U32_SIZE = 8;
|
||||
constructor(reader) {
|
||||
this.threadId = reader.readuint32();
|
||||
this.alignment = reader.readuint32();
|
||||
this.exceptionCode = reader.readuint32();
|
||||
this.exceptionFlags = reader.readuint32();
|
||||
this.exceptionRecord = reader.readuint64();
|
||||
this.exceptionAddress = reader.readuint64();
|
||||
}
|
||||
static async read(reader, position) {
|
||||
return new MINIDUMP_EXCEPTION_STREAM(await reader.read(MINIDUMP_EXCEPTION_STREAM.U32_SIZE, position));
|
||||
}
|
||||
getExceptionCodeString() {
|
||||
const exceptionCode = this.exceptionCode.toString(16).toUpperCase().padStart(8, '0');
|
||||
const exceptionString = exceptionTypes[exceptionCode] ?? exceptionCode;
|
||||
return exceptionString;
|
||||
}
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_location_descriptor
|
||||
class MINIDUMP_LOCATION_DESCRIPTOR {
|
||||
constructor(reader) {
|
||||
this.dataSize = reader.readuint32();
|
||||
this.rva = reader.readuint32();
|
||||
}
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_module_list
|
||||
class MINIDUMP_MODULE_LIST {
|
||||
static U32_SIZE = 1;
|
||||
constructor(reader) {
|
||||
this.numberOfModules = reader.readuint32();
|
||||
}
|
||||
static async read(reader, position) {
|
||||
return new MINIDUMP_MODULE_LIST(await reader.read(MINIDUMP_MODULE_LIST.U32_SIZE, position));
|
||||
}
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_module
|
||||
class MINIDUMP_MODULE {
|
||||
// sizeof(MINIDUMP_MODULE) 108
|
||||
// sizeof(VS_FIXEDFILEINFO) 52
|
||||
// sizeof(MINIDUMP_LOCATION_DESCRIPTOR) 8
|
||||
// sizeof(RVA) 4
|
||||
static U32_SIZE = 108 / 4;
|
||||
constructor(reader) {
|
||||
this.baseOfImage = reader.readuint64();
|
||||
this.sizeOfImage = reader.readuint32();
|
||||
this.checkSum = reader.readuint32();
|
||||
this.timeDateStamp = reader.readuint32();
|
||||
this.moduleNameRva = reader.readuint32();
|
||||
this.versionInfo = new VS_FIXEDFILEINFO(reader);
|
||||
this.cvRecord = new MINIDUMP_LOCATION_DESCRIPTOR(reader);
|
||||
this.miscRecord = new MINIDUMP_LOCATION_DESCRIPTOR(reader);
|
||||
this.reserved0 = reader.readuint64();
|
||||
this.reserved1 = reader.readuint64();
|
||||
}
|
||||
static async read(reader, position) {
|
||||
return new MINIDUMP_MODULE(await reader.read(MINIDUMP_MODULE.U32_SIZE, position));
|
||||
}
|
||||
containsAddress(address) {
|
||||
const endAddress = this.baseOfImage + BigInt(this.sizeOfImage);
|
||||
return this.baseOfImage <= address && endAddress > address;
|
||||
}
|
||||
async getModuleFileName(reader) {
|
||||
const moduleName = await reader.readMinidumpString(this.moduleNameRva);
|
||||
let dirPos = moduleName.lastIndexOf('\\');
|
||||
if (dirPos === -1) {
|
||||
dirPos = moduleName.lastIndexOf('/');
|
||||
}
|
||||
dirPos = dirPos === -1 ? 0 : dirPos + 1;
|
||||
return moduleName.slice(dirPos);
|
||||
}
|
||||
async getCVInfoIdString(reader) {
|
||||
return (await CV_INFO.read(reader, this.cvRecord.rva)).getIdString();
|
||||
}
|
||||
getCodeIdString() {
|
||||
return (this.timeDateStamp.toString(16).padStart(8, '0') + this.sizeOfImage.toString(16)).toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
|
||||
class VS_FIXEDFILEINFO {
|
||||
constructor(reader) {
|
||||
this.dwSignature = reader.readuint32();
|
||||
this.dwStrucVersion = reader.readuint32();
|
||||
this.dwFileVersionMS = reader.readuint32();
|
||||
this.dwFileVersionLS = reader.readuint32();
|
||||
this.dwProductVersionMS = reader.readuint32();
|
||||
this.dwProductVersionLS = reader.readuint32();
|
||||
this.dwFileFlagsMask = reader.readuint32();
|
||||
this.dwFileFlags = reader.readuint32();
|
||||
this.dwFileOS = reader.readuint32();
|
||||
this.dwFileType = reader.readuint32();
|
||||
this.dwFileSubtype = reader.readuint32();
|
||||
this.dwFileDateMS = reader.readuint32();
|
||||
this.dwFileDateLS = reader.readuint32();
|
||||
}
|
||||
getVersionString() {
|
||||
const first = this.dwProductVersionMS >> 16 & 0xffff;
|
||||
const second = this.dwProductVersionMS & 0xffff;
|
||||
const third = this.dwProductVersionLS >> 16 & 0xffff;
|
||||
const fourth = this.dwProductVersionLS & 0xffff;
|
||||
return `${first}.${second}.${third}.${fourth}`;
|
||||
}
|
||||
}
|
||||
|
||||
// This isn't spec'ed on the minidump page (from what I could tell):
|
||||
// https://github.com/rust-minidump/rust-minidump/blob/main/minidump/src/minidump.rs#L267
|
||||
// This returns the ID string that is used by the Mozilla tools for PDB lookup.
|
||||
class CV_INFO {
|
||||
static async read(reader, position) {
|
||||
if (position === 0) {
|
||||
return new CV_INFO_UNKNOWN(0);
|
||||
}
|
||||
|
||||
// 6 is the largest.
|
||||
const readResult = await reader.read(6, position);
|
||||
const cvSignature = readResult.readuint32();
|
||||
switch (cvSignature) {
|
||||
case CV_INFO_PDB20.SIGNATURE:
|
||||
return new CV_INFO_PDB20(readResult);
|
||||
case CV_INFO_PDB70.SIGNATURE:
|
||||
return new CV_INFO_PDB70(readResult);
|
||||
case CV_INFO_ELF.SIGNATURE:
|
||||
return new CV_INFO_ELF();
|
||||
default:
|
||||
return new CV_INFO_UNKNOWN(cvSignature);
|
||||
}
|
||||
}
|
||||
}
|
||||
class CV_INFO_PDB20 {
|
||||
static SIGNATURE = 0x3031424e;
|
||||
constructor(reader) {
|
||||
this.cvOffset = reader.readuint32();
|
||||
this.signature = reader.readuint32();
|
||||
this.age = reader.readuint32();
|
||||
}
|
||||
getIdString() {
|
||||
// TODO: Probably uncommon at this point.
|
||||
return 'CV_INFO_PDB20';
|
||||
}
|
||||
}
|
||||
class GUID {
|
||||
// fixed 8 length.
|
||||
|
||||
constructor(reader) {
|
||||
this.data1 = reader.readuint32();
|
||||
this.data2 = reader.readuint16();
|
||||
this.data3 = reader.readuint16();
|
||||
this.data4 = reader.readByteArray(8);
|
||||
}
|
||||
toString() {
|
||||
if (this.data4.length !== 8) {
|
||||
return 'Invalid';
|
||||
}
|
||||
return this.data1.toString(16).padStart(4, '0') + this.data2.toString(16).padStart(2, '0') + this.data3.toString(16).padStart(2, '0') + this.data4.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
}
|
||||
class CV_INFO_PDB70 {
|
||||
static SIGNATURE = 0x53445352;
|
||||
constructor(reader) {
|
||||
this.signature = new GUID(reader);
|
||||
this.age = reader.readuint32();
|
||||
}
|
||||
getIdString() {
|
||||
// https://randomascii.wordpress.com/2013/03/09/symbols-the-microsoft-way/
|
||||
return (this.signature.toString() + this.age.toString(16)).toUpperCase();
|
||||
}
|
||||
}
|
||||
class CV_INFO_ELF {
|
||||
static SIGNATURE = 0x4270454c;
|
||||
getIdString() {
|
||||
// TODO: Would be needed for macOS/linux support presumably?
|
||||
return 'CV_INFO_ELF';
|
||||
}
|
||||
}
|
||||
class CV_INFO_UNKNOWN {
|
||||
constructor(cvSignature) {
|
||||
this.cvSignature = cvSignature;
|
||||
}
|
||||
getIdString() {
|
||||
return 'CV_INFO_UNKNOWN:' + this.cvSignature.toString(16).padStart(4, '0');
|
||||
}
|
||||
}
|
||||
async function readMinidump(file) {
|
||||
if (file == null || !isMinidumpFilename(file)) return null;
|
||||
let reader = null;
|
||||
const info = {};
|
||||
try {
|
||||
reader = new FileReader(file);
|
||||
const header = await MINIDUMP_HEADER.read(reader, 0);
|
||||
if (header.signature !== 0x504d444d) {
|
||||
console.log(`readMinidump Bad signature: 0x${header.signature.toString(16)}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Arbitrary number. Just a sanity check.
|
||||
if (header.numberOfStreams > 0x100) {
|
||||
console.log(`readMinidump Bad numberOfStreams: 0x${header.numberOfStreams.toString(16)}`);
|
||||
return null;
|
||||
}
|
||||
const streamLookup = {};
|
||||
|
||||
// First create a lookup because we want to process the entries in a specific order.
|
||||
for (let i = 0; i < header.numberOfStreams; ++i) {
|
||||
const streamOffset = header.streamDirectoryOffset + i * 12;
|
||||
const entry = await MINIDUMP_DIRECTORY.read(reader, streamOffset);
|
||||
|
||||
// We only care about a limited amount of stream types, so lets avoid some of the overhead.
|
||||
switch (entry.streamType) {
|
||||
case MinidumpStreamType.ExceptionStream:
|
||||
case MinidumpStreamType.ModuleListStream:
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
streamLookup[entry.streamType] = entry;
|
||||
}
|
||||
const exceptionStreamEntry = streamLookup[MinidumpStreamType.ExceptionStream];
|
||||
if (exceptionStreamEntry == null) {
|
||||
console.log(`readMinidump: No ExceptionStream found.`);
|
||||
return null;
|
||||
}
|
||||
const exceptionStream = await MINIDUMP_EXCEPTION_STREAM.read(reader, exceptionStreamEntry.dataOffset);
|
||||
info.exceptionString = exceptionStream.getExceptionCodeString();
|
||||
const exceptionAddrString = exceptionStream.exceptionAddress.toString(16);
|
||||
console.log(`readMinidump exceptionCode: ${info.exceptionString}, exceptionAddress ${exceptionAddrString}`);
|
||||
const moduleStreamEntry = streamLookup[MinidumpStreamType.ModuleListStream];
|
||||
// Skip if `exceptionAddress` is 0 since there will be no crashing module.
|
||||
if (moduleStreamEntry != null && exceptionStream.exceptionAddress !== BigInt(0)) {
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_module_list
|
||||
|
||||
// Do not read them all at once. This 1) allows us to exit early, 2) would require a variable sized buffer
|
||||
// instead of our smaller fixed size buffer.
|
||||
const moduleList = await MINIDUMP_MODULE_LIST.read(reader, moduleStreamEntry.dataOffset);
|
||||
// Sanity check, this number is arbitrary.
|
||||
if (moduleList.numberOfModules > 0x200) {
|
||||
console.log(`readMinidump ModuleListstream Bad numberOfModules: 0x${moduleList.numberOfModules.toString(16)}`);
|
||||
return info;
|
||||
}
|
||||
let moduleEntryOffset = moduleStreamEntry.dataOffset + 4;
|
||||
for (let i = 0; i < moduleList.numberOfModules; ++i) {
|
||||
const module = await MINIDUMP_MODULE.read(reader, moduleEntryOffset);
|
||||
moduleEntryOffset += MINIDUMP_MODULE.U32_SIZE * 4;
|
||||
if (module.containsAddress(exceptionStream.exceptionAddress)) {
|
||||
info.exceptionModuleName = await module.getModuleFileName(reader);
|
||||
info.exceptionModuleVersion = module.versionInfo.getVersionString();
|
||||
info.relativeCrashAddress = (exceptionStream.exceptionAddress - module.baseOfImage).toString(16);
|
||||
info.exceptionModuleCodeId = module.getCodeIdString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(`readMinidump exception: ${e} ${e === null || e === void 0 ? void 0 : e.stack}`);
|
||||
return null;
|
||||
} finally {
|
||||
var _reader;
|
||||
(_reader = reader) === null || _reader === void 0 ? void 0 : _reader.close();
|
||||
}
|
||||
console.log(`readMinidump result ${JSON.stringify(info)}`);
|
||||
return info;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.getNewestMinidumpInformation = getNewestMinidumpInformation;
|
||||
var _processUtils = require("../../../common/processUtils");
|
||||
var _paths = require("../common/paths");
|
||||
var _minidump = require("./minidump");
|
||||
/* eslint-disable no-console */
|
||||
|
||||
// This is unfortunately in its own file because Jest breaks when it sees original-fs.
|
||||
async function getNewestMinidumpInformation() {
|
||||
if (!_processUtils.IS_WIN) return null;
|
||||
try {
|
||||
const files = await (0, _paths.getCrashFiles)();
|
||||
if (files == null || files.length === 0) return null;
|
||||
return await (0, _minidump.readMinidump)(files[0]);
|
||||
} catch (e) {
|
||||
console.log(`getNewestMinidumpInformation exception: ${e}`);
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const {
|
||||
NATIVE_MODULES_GET_PATHS,
|
||||
NATIVE_MODULES_INSTALL,
|
||||
NATIVE_MODULES_GET_HAS_NEW_UPDATER
|
||||
} = require('../common/constants').IPCEvents;
|
||||
const modulePromises = {};
|
||||
function getSanitizedModulePaths() {
|
||||
let sanitizedModulePaths = [];
|
||||
const {
|
||||
mainAppDirname,
|
||||
browserModulePaths
|
||||
} = electron.ipcRenderer.sendSync(NATIVE_MODULES_GET_PATHS);
|
||||
browserModulePaths.forEach(modulePath => {
|
||||
if (!modulePath.includes('electron.asar')) {
|
||||
sanitizedModulePaths.push(modulePath);
|
||||
}
|
||||
});
|
||||
const rendererModulePaths = require('module')._nodeModulePaths(mainAppDirname);
|
||||
sanitizedModulePaths = sanitizedModulePaths.concat(rendererModulePaths.slice(0, 2));
|
||||
return sanitizedModulePaths;
|
||||
}
|
||||
function getHasNewUpdater() {
|
||||
return electron.ipcRenderer.sendSync(NATIVE_MODULES_GET_HAS_NEW_UPDATER);
|
||||
}
|
||||
async function ensureModule(name) {
|
||||
if (modulePromises[name] == null) {
|
||||
modulePromises[name] = electron.ipcRenderer.invoke(NATIVE_MODULES_INSTALL, name);
|
||||
}
|
||||
const moduleInstall = modulePromises[name];
|
||||
await moduleInstall.catch(e => {
|
||||
modulePromises[name] = null;
|
||||
return Promise.reject(e);
|
||||
});
|
||||
module.paths = getSanitizedModulePaths();
|
||||
}
|
||||
function requireModule(name) {
|
||||
if (!/^discord_[a-z0-9_-]+$/.test(name) && name !== 'erlpack') {
|
||||
throw new Error('"' + String(name) + '" is not a whitelisted native module');
|
||||
}
|
||||
return require(name);
|
||||
}
|
||||
module.paths = getSanitizedModulePaths();
|
||||
module.exports = {
|
||||
ensureModule,
|
||||
requireModule,
|
||||
canBootstrapNewUpdater: !getHasNewUpdater()
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
"use strict";
|
||||
|
||||
const os = require('os');
|
||||
const process = require('process');
|
||||
let arch = os.arch();
|
||||
if (process.platform === 'win32' && process.env['PROCESSOR_ARCHITEW6432'] != null) {
|
||||
arch = 'x64';
|
||||
}
|
||||
module.exports = {
|
||||
release: os.release(),
|
||||
arch
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const EventEmitter = require('events');
|
||||
const {
|
||||
POWER_MONITOR_RESUME,
|
||||
POWER_MONITOR_SUSPEND,
|
||||
POWER_MONITOR_LOCK_SCREEN,
|
||||
POWER_MONITOR_UNLOCK_SCREEN,
|
||||
POWER_MONITOR_GET_SYSTEM_IDLE_TIME
|
||||
} = require('../common/constants').IPCEvents;
|
||||
const events = new EventEmitter();
|
||||
electron.ipcRenderer.on(POWER_MONITOR_RESUME, () => {
|
||||
events.emit('resume');
|
||||
});
|
||||
electron.ipcRenderer.on(POWER_MONITOR_SUSPEND, () => {
|
||||
events.emit('suspend');
|
||||
});
|
||||
electron.ipcRenderer.on(POWER_MONITOR_LOCK_SCREEN, () => {
|
||||
events.emit('lock-screen');
|
||||
});
|
||||
electron.ipcRenderer.on(POWER_MONITOR_UNLOCK_SCREEN, () => {
|
||||
events.emit('unlock-screen');
|
||||
});
|
||||
function on() {
|
||||
events.on.apply(events, arguments);
|
||||
}
|
||||
function removeListener() {
|
||||
events.removeListener.apply(events, arguments);
|
||||
}
|
||||
function removeAllListeners() {
|
||||
events.removeAllListeners.apply(events, arguments);
|
||||
}
|
||||
async function getSystemIdleTimeMs() {
|
||||
return electron.ipcRenderer.invoke(POWER_MONITOR_GET_SYSTEM_IDLE_TIME);
|
||||
}
|
||||
module.exports = {
|
||||
on,
|
||||
removeListener,
|
||||
removeAllListeners,
|
||||
getSystemIdleTimeMs
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const {
|
||||
POWER_SAVE_BLOCKER_BLOCK_DISPLAY_SLEEP,
|
||||
POWER_SAVE_BLOCKER_UNBLOCK_DISPLAY_SLEEP,
|
||||
POWER_SAVE_BLOCKER_CLEANUP_DISPLAY_SLEEP
|
||||
} = require('../common/constants').IPCEvents;
|
||||
async function blockDisplaySleep() {
|
||||
return electron.ipcRenderer.invoke(POWER_SAVE_BLOCKER_BLOCK_DISPLAY_SLEEP);
|
||||
}
|
||||
async function unblockDisplaySleep(id) {
|
||||
return electron.ipcRenderer.invoke(POWER_SAVE_BLOCKER_UNBLOCK_DISPLAY_SLEEP, id);
|
||||
}
|
||||
async function cleanupDisplaySleep() {
|
||||
return electron.ipcRenderer.invoke(POWER_SAVE_BLOCKER_CLEANUP_DISPLAY_SLEEP);
|
||||
}
|
||||
module.exports = {
|
||||
blockDisplaySleep,
|
||||
unblockDisplaySleep,
|
||||
cleanupDisplaySleep
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
|
||||
const process = require('process');
|
||||
const env = process.env;
|
||||
module.exports = {
|
||||
platform: process.platform,
|
||||
arch: process.arch,
|
||||
env: {
|
||||
DISCORD_TEST: env['DISCORD_TEST'],
|
||||
DISCORD_GATEWAY_PLAINTEXT: env['DISCORD_GATEWAY_PLAINTEXT'],
|
||||
DISCORD_DISALLOW_POPUPS: env['DISCORD_DISALLOW_POPUPS'],
|
||||
LOCALAPPDATA: env['LOCALAPPDATA'],
|
||||
'PROGRAMFILES(X86)': env['PROGRAMFILES(X86)'],
|
||||
PROGRAMFILES: env['PROGRAMFILES'],
|
||||
PROGRAMW6432: env['PROGRAMW6432'],
|
||||
PROGRAMDATA: env['PROGRAMDATA']
|
||||
}
|
||||
};
|
|
@ -0,0 +1,98 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.flushCookies = flushCookies;
|
||||
exports.flushDNSCache = flushDNSCache;
|
||||
exports.flushStorageData = flushStorageData;
|
||||
exports.getCPUCoreCount = getCPUCoreCount;
|
||||
exports.getCurrentCPUUsagePercent = getCurrentCPUUsagePercent;
|
||||
exports.getCurrentMemoryUsageKB = getCurrentMemoryUsageKB;
|
||||
exports.getLastCrash = getLastCrash;
|
||||
exports.getMainArgvSync = getMainArgvSync;
|
||||
exports.getSystemInfo = getSystemInfo;
|
||||
exports.purgeMemory = purgeMemory;
|
||||
exports.setCrashInformation = setCrashInformation;
|
||||
var _electron = _interopRequireDefault(require("electron"));
|
||||
var _os = _interopRequireDefault(require("os"));
|
||||
var _process = _interopRequireDefault(require("process"));
|
||||
var _DiscordIPC = require("../common/DiscordIPC");
|
||||
var _minidumpReader = require("./minidumpReader");
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
// Note: CPU interval should be kept insync with Android's DeviceResourceUsageMonitor interval.
|
||||
const CPU_USAGE_GATHER_INTERVAL = 1000;
|
||||
const MEMORY_USAGE_GATHER_INTERVAL = 5000;
|
||||
const mainArgv = _DiscordIPC.DiscordIPC.renderer.sendSync(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_MAIN_ARGV_SYNC);
|
||||
let totalProcessorUsagePercent = 0;
|
||||
let totalMemoryUsageKB = 0;
|
||||
const cpuCoreCount = _os.default.cpus().length;
|
||||
setInterval(() => {
|
||||
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_CPU_USAGE).then(usage => totalProcessorUsagePercent = usage);
|
||||
}, CPU_USAGE_GATHER_INTERVAL);
|
||||
let memoryUsageTimerRunning = false;
|
||||
function getCurrentMemoryUsageKB() {
|
||||
// Lazy initialize because this is only needed when the native process_utils are not available/updated.
|
||||
if (memoryUsageTimerRunning) {
|
||||
return totalMemoryUsageKB;
|
||||
}
|
||||
memoryUsageTimerRunning = true;
|
||||
function computeMemoryUsage() {
|
||||
const memoryUsage = _process.default.memoryUsage();
|
||||
return (memoryUsage.heapTotal + memoryUsage.external) / 1024;
|
||||
}
|
||||
setInterval(() => {
|
||||
totalMemoryUsageKB = computeMemoryUsage();
|
||||
}, MEMORY_USAGE_GATHER_INTERVAL);
|
||||
totalMemoryUsageKB = computeMemoryUsage();
|
||||
return totalMemoryUsageKB;
|
||||
}
|
||||
function flushDNSCache() {
|
||||
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_FLUSH_DNS_CACHE);
|
||||
}
|
||||
async function getLastCrash() {
|
||||
const lastCrash = await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_LAST_CRASH);
|
||||
const minidumpInformation = lastCrash.id != null ? await (0, _minidumpReader.getNewestMinidumpInformation)() : null;
|
||||
return {
|
||||
date: lastCrash.date,
|
||||
id: lastCrash.id,
|
||||
rendererCrashReason: lastCrash.rendererCrashReason,
|
||||
rendererCrashExitCode: lastCrash.rendererCrashExitCode,
|
||||
minidumpInformation,
|
||||
storedInformation: lastCrash.storedInformation
|
||||
};
|
||||
}
|
||||
async function flushCookies(callback) {
|
||||
try {
|
||||
await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_FLUSH_COOKIES);
|
||||
callback();
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
}
|
||||
function getSystemInfo() {
|
||||
return _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_GET_SYSTEM_INFO);
|
||||
}
|
||||
async function flushStorageData(callback) {
|
||||
try {
|
||||
await _DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_FLUSH_STORAGE_DATA);
|
||||
callback();
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
}
|
||||
function purgeMemory() {
|
||||
_electron.default.webFrame.clearCache();
|
||||
}
|
||||
function getCurrentCPUUsagePercent() {
|
||||
return totalProcessorUsagePercent;
|
||||
}
|
||||
function getCPUCoreCount() {
|
||||
return cpuCoreCount;
|
||||
}
|
||||
function getMainArgvSync() {
|
||||
return mainArgv;
|
||||
}
|
||||
function setCrashInformation(crashInformation, state) {
|
||||
_DiscordIPC.DiscordIPC.renderer.invoke(_DiscordIPC.IPCEvents.PROCESS_UTILS_SET_CRASH_INFORMATION, crashInformation, state);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const {
|
||||
SAFE_STORAGE_DECRYPT_STRING,
|
||||
SAFE_STORAGE_ENCRYPT_STRING,
|
||||
SAFE_STORAGE_IS_ENCRYPTION_AVAILABLE
|
||||
} = require('../common/constants').IPCEvents;
|
||||
function isEncryptionAvailable() {
|
||||
return electron.ipcRenderer.sendSync(SAFE_STORAGE_IS_ENCRYPTION_AVAILABLE);
|
||||
}
|
||||
function decryptString(encrypted) {
|
||||
return electron.ipcRenderer.sendSync(SAFE_STORAGE_DECRYPT_STRING, encrypted);
|
||||
}
|
||||
function encryptString(plainText) {
|
||||
return electron.ipcRenderer.sendSync(SAFE_STORAGE_ENCRYPT_STRING, plainText);
|
||||
}
|
||||
module.exports = {
|
||||
isEncryptionAvailable,
|
||||
decryptString,
|
||||
encryptString
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const {
|
||||
SETTINGS_GET,
|
||||
SETTINGS_SET,
|
||||
SETTINGS_GET_SYNC
|
||||
} = require('../common/constants').IPCEvents;
|
||||
|
||||
// Updating app settings directly from the renderer is considered deprecated.
|
||||
// Voice still sets a few options, so we whitelist those.
|
||||
const RENDERER_SET_WHITELIST = ['audioSubsystem', 'useLegacyAudioDevice', 'debugLogging'];
|
||||
async function get(name, defaultValue) {
|
||||
return electron.ipcRenderer.invoke(SETTINGS_GET, name, defaultValue);
|
||||
}
|
||||
async function set(name, value) {
|
||||
if (!RENDERER_SET_WHITELIST.includes(name)) {
|
||||
throw new Error('cannot set this setting key');
|
||||
}
|
||||
return electron.ipcRenderer.invoke(SETTINGS_SET, name, value);
|
||||
}
|
||||
function getSync(name, defaultValue) {
|
||||
return electron.ipcRenderer.sendSync(SETTINGS_GET_SYNC, name, defaultValue);
|
||||
}
|
||||
module.exports = {
|
||||
get,
|
||||
set,
|
||||
getSync
|
||||
};
|
|
@ -0,0 +1,48 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const EventEmitter = require('events');
|
||||
const {
|
||||
SPELLCHECK_RESULT,
|
||||
SPELLCHECK_REPLACE_MISSPELLING,
|
||||
SPELLCHECK_GET_AVAILABLE_DICTIONARIES,
|
||||
SPELLCHECK_SET_LOCALE,
|
||||
SPELLCHECK_SET_LEARNED_WORDS
|
||||
} = require('../common/constants').IPCEvents;
|
||||
const events = new EventEmitter();
|
||||
electron.ipcRenderer.on(SPELLCHECK_RESULT, handleSpellcheckData);
|
||||
function handleSpellcheckData(_, misspelledWord, dictionarySuggestions) {
|
||||
events.emit('spellcheck-result', misspelledWord, dictionarySuggestions);
|
||||
}
|
||||
function on() {
|
||||
events.on.apply(events, arguments);
|
||||
}
|
||||
function removeListener() {
|
||||
events.removeListener.apply(events, arguments);
|
||||
}
|
||||
async function getAvailableDictionaries() {
|
||||
return electron.ipcRenderer.invoke(SPELLCHECK_GET_AVAILABLE_DICTIONARIES);
|
||||
}
|
||||
async function setLocale(locale) {
|
||||
let succeeded = true;
|
||||
try {
|
||||
await electron.ipcRenderer.invoke(SPELLCHECK_SET_LOCALE, locale);
|
||||
} catch (_) {
|
||||
succeeded = false;
|
||||
}
|
||||
return succeeded;
|
||||
}
|
||||
async function setLearnedWords(learnedWords) {
|
||||
return electron.ipcRenderer.invoke(SPELLCHECK_SET_LEARNED_WORDS, learnedWords);
|
||||
}
|
||||
async function replaceMisspelling(correction) {
|
||||
return electron.ipcRenderer.invoke(SPELLCHECK_REPLACE_MISSPELLING, correction);
|
||||
}
|
||||
module.exports = {
|
||||
on,
|
||||
removeListener,
|
||||
getAvailableDictionaries,
|
||||
setLocale,
|
||||
setLearnedWords,
|
||||
replaceMisspelling
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _constants = require("../common/constants");
|
||||
var _ipc = require("./ipc");
|
||||
function setThumbarButtons(buttons, isSystemDarkMode) {
|
||||
return (0, _ipc.send)(_constants.IPCEvents.THUMBAR_BUTTONS_UPDATE, buttons, isSystemDarkMode);
|
||||
}
|
||||
var _default = {
|
||||
setThumbarButtons
|
||||
};
|
||||
exports.default = _default;
|
||||
module.exports = exports.default;
|
|
@ -0,0 +1,23 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const {
|
||||
USER_DATA_CACHE_SAVE,
|
||||
USER_DATA_CACHE_GET,
|
||||
USER_DATA_CACHE_DELETE
|
||||
} = require('../common/constants').IPCEvents;
|
||||
async function getCached() {
|
||||
const cached = await electron.ipcRenderer.invoke(USER_DATA_CACHE_GET);
|
||||
return cached;
|
||||
}
|
||||
function cacheUserData(userData) {
|
||||
electron.ipcRenderer.send(USER_DATA_CACHE_SAVE, userData);
|
||||
}
|
||||
function deleteCache() {
|
||||
electron.ipcRenderer.send(USER_DATA_CACHE_DELETE);
|
||||
}
|
||||
module.exports = {
|
||||
getCached,
|
||||
cacheUserData,
|
||||
deleteCache
|
||||
};
|
|
@ -0,0 +1,95 @@
|
|||
"use strict";
|
||||
|
||||
const electron = require('electron');
|
||||
const {
|
||||
WINDOW_BLUR,
|
||||
WINDOW_CLOSE,
|
||||
WINDOW_FOCUS,
|
||||
WINDOW_MAXIMIZE,
|
||||
WINDOW_MINIMIZE,
|
||||
WINDOW_RESTORE,
|
||||
WINDOW_FLASH_FRAME,
|
||||
WINDOW_TOGGLE_FULLSCREEN,
|
||||
WINDOW_SET_BACKGROUND_THROTTLING,
|
||||
WINDOW_SET_PROGRESS_BAR,
|
||||
WINDOW_IS_ALWAYS_ON_TOP,
|
||||
WINDOW_SET_ALWAYS_ON_TOP,
|
||||
WINDOW_DEVTOOLS_OPENED,
|
||||
WINDOW_DEVTOOLS_CLOSED
|
||||
} = require('../common/constants').IPCEvents;
|
||||
let devtoolsOpenedCallback = () => {};
|
||||
let devtoolsClosedCallback = () => {};
|
||||
electron.ipcRenderer.on(WINDOW_DEVTOOLS_OPENED, async _ => {
|
||||
if (devtoolsOpenedCallback != null) {
|
||||
devtoolsOpenedCallback();
|
||||
}
|
||||
});
|
||||
electron.ipcRenderer.on(WINDOW_DEVTOOLS_CLOSED, async _ => {
|
||||
if (devtoolsClosedCallback != null) {
|
||||
devtoolsClosedCallback();
|
||||
}
|
||||
});
|
||||
async function flashFrame(flag) {
|
||||
electron.ipcRenderer.invoke(WINDOW_FLASH_FRAME, flag);
|
||||
}
|
||||
async function minimize(key) {
|
||||
electron.ipcRenderer.invoke(WINDOW_MINIMIZE, key);
|
||||
}
|
||||
async function restore(key) {
|
||||
electron.ipcRenderer.invoke(WINDOW_RESTORE, key);
|
||||
}
|
||||
async function maximize(key) {
|
||||
electron.ipcRenderer.invoke(WINDOW_MAXIMIZE, key);
|
||||
}
|
||||
async function focus(_hack, key) {
|
||||
electron.ipcRenderer.invoke(WINDOW_FOCUS, key);
|
||||
}
|
||||
async function setAlwaysOnTop(key, enabled) {
|
||||
return electron.ipcRenderer.invoke(WINDOW_SET_ALWAYS_ON_TOP, key, enabled);
|
||||
}
|
||||
async function isAlwaysOnTop(key) {
|
||||
return electron.ipcRenderer.invoke(WINDOW_IS_ALWAYS_ON_TOP, key);
|
||||
}
|
||||
async function blur(key) {
|
||||
electron.ipcRenderer.invoke(WINDOW_BLUR, key);
|
||||
}
|
||||
async function setProgressBar(progress, key) {
|
||||
electron.ipcRenderer.invoke(WINDOW_SET_PROGRESS_BAR, key, progress);
|
||||
}
|
||||
async function fullscreen(key) {
|
||||
electron.ipcRenderer.invoke(WINDOW_TOGGLE_FULLSCREEN, key);
|
||||
}
|
||||
async function close(key) {
|
||||
electron.ipcRenderer.invoke(WINDOW_CLOSE, key);
|
||||
}
|
||||
async function setZoomFactor(factor) {
|
||||
if (!electron.webFrame.setZoomFactor) return;
|
||||
electron.webFrame.setZoomFactor(factor / 100);
|
||||
}
|
||||
async function setBackgroundThrottling(enabled) {
|
||||
electron.ipcRenderer.invoke(WINDOW_SET_BACKGROUND_THROTTLING, enabled);
|
||||
}
|
||||
async function setDevtoolsCallbacks(onOpened, onClosed) {
|
||||
devtoolsOpenedCallback = onOpened;
|
||||
devtoolsClosedCallback = onClosed;
|
||||
}
|
||||
|
||||
// To synchronize web vs desktop release features
|
||||
const USE_OSX_NATIVE_TRAFFIC_LIGHTS = true;
|
||||
module.exports = {
|
||||
flashFrame,
|
||||
minimize,
|
||||
restore,
|
||||
maximize,
|
||||
focus,
|
||||
blur,
|
||||
fullscreen,
|
||||
close,
|
||||
setAlwaysOnTop,
|
||||
isAlwaysOnTop,
|
||||
setZoomFactor,
|
||||
setBackgroundThrottling,
|
||||
setProgressBar,
|
||||
setDevtoolsCallbacks,
|
||||
USE_OSX_NATIVE_TRAFFIC_LIGHTS
|
||||
};
|
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 15 KiB |
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="20px" height="20px"
|
||||
viewBox="40 40 20 20" enable-background="new 40 40 20 20" xml:space="preserve">
|
||||
<title>Slice 1</title>
|
||||
<description>Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
|
||||
<g id="Page_1">
|
||||
<path id="Close" fill="#99aab5" d="M40.445,42.853l2.408-2.408c0.593-0.593,1.555-0.593,2.147,0l5,5l5-5
|
||||
c0.593-0.593,1.554-0.593,2.147,0l2.408,2.408c0.593,0.593,0.593,1.554,0,2.147l-5,5l5,5c0.593,0.593,0.592,1.554,0,2.147
|
||||
l-2.408,2.408c-0.593,0.593-1.555,0.593-2.147,0l-5-5l-5,5c-0.593,0.593-1.554,0.593-2.147,0l-2.408-2.408
|
||||
c-0.593-0.593-0.593-1.554,0-2.147l5-5l-5-5C39.852,44.407,39.852,43.445,40.445,42.853z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 168 190" enable-background="new 0 0 168 190" xml:space="preserve">
|
||||
<g>
|
||||
<rect x="14.4" y="46.1" fill="#FFFFFF" width="139.2" height="97.7"/>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="66.6616" y1="79.7119" x2="66.6616" y2="100.7434">
|
||||
<stop offset="0" style="stop-color:#7491D5"/>
|
||||
<stop offset="1" style="stop-color:#4E68A0"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_1_)" d="M66.7,79.7c-5.4,0-9.8,4.7-9.8,10.5c0,5.8,4.4,10.5,9.8,10.5c5.4,0,9.8-4.7,9.8-10.5
|
||||
C76.5,84.4,72.1,79.7,66.7,79.7z"/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="101.661" y1="79.7119" x2="101.661" y2="100.7434">
|
||||
<stop offset="0" style="stop-color:#7491D5"/>
|
||||
<stop offset="1" style="stop-color:#4E68A0"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_2_)" d="M101.7,79.7c-5.4,0-9.8,4.7-9.8,10.5c0,5.8,4.4,10.5,9.8,10.5c5.4,0,9.8-4.7,9.8-10.5
|
||||
C111.5,84.4,107.1,79.7,101.7,79.7z"/>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="84" y1="-4.545736e-07" x2="84" y2="190">
|
||||
<stop offset="0" style="stop-color:#7491D5"/>
|
||||
<stop offset="1" style="stop-color:#4E68A0"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#SVGID_3_)" d="M148.4,0H19.6C8.8,0,0,8.8,0,19.6v128.4c0,10.8,8.8,19.6,19.6,19.6h108.9l-5.1-17.5l12.3,11.3
|
||||
l11.6,10.7L168,190v-41.9v-9.5V19.6C168,8.8,159.2,0,148.4,0z M111.3,124.1c0,0-3.4-4.1-6.3-7.7c12.6-3.5,17.4-11.3,17.4-11.3
|
||||
c-4,2.6-7.7,4.4-11.1,5.6c-4.8,2-9.5,3.3-14,4.1c-9.2,1.7-17.6,1.3-24.9-0.1c-5.5-1-10.2-2.5-14.1-4.1c-2.2-0.8-4.6-1.9-7.1-3.3
|
||||
c-0.3-0.2-0.6-0.3-0.9-0.5c-0.1-0.1-0.3-0.2-0.4-0.2c-1.7-1-2.6-1.6-2.6-1.6s4.6,7.6,16.8,11.2c-2.9,3.6-6.4,7.9-6.4,7.9
|
||||
c-21.2-0.6-29.3-14.5-29.3-14.5c0-30.6,13.8-55.4,13.8-55.4c13.8-10.3,26.9-10,26.9-10l1,1.1C52.8,50.3,45,57.9,45,57.9
|
||||
s2.1-1.2,5.7-2.7c10.3-4.5,18.4-5.7,21.8-6c0.5-0.1,1.1-0.2,1.6-0.2c5.9-0.7,12.5-0.9,19.4-0.2c9.1,1,18.9,3.7,28.9,9.1
|
||||
c0,0-7.5-7.2-23.9-12.1l1.3-1.5c0,0,13.1-0.3,26.9,10c0,0,13.8,24.8,13.8,55.4C140.6,109.6,132.5,123.5,111.3,124.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 153 B |
After Width: | Height: | Size: 189 B |
After Width: | Height: | Size: 232 B |
After Width: | Height: | Size: 238 B |
After Width: | Height: | Size: 205 B |
After Width: | Height: | Size: 281 B |
After Width: | Height: | Size: 294 B |
After Width: | Height: | Size: 229 B |
After Width: | Height: | Size: 301 B |
After Width: | Height: | Size: 421 B |
After Width: | Height: | Size: 540 B |
After Width: | Height: | Size: 233 B |