Handle native modules not loading

This commit is contained in:
Samuel Elliott 2019-03-10 02:48:18 +00:00
parent 68a8187964
commit 988fe4dd7c
No known key found for this signature in database
GPG Key ID: 8420C7CDE43DC4D6
9 changed files with 119 additions and 9 deletions

View File

@ -13,6 +13,7 @@ import BdCss from './styles/index.scss';
import { Events, Globals, Settings, Database, Updater, ModuleManager, PluginManager, ThemeManager, ExtModuleManager, Vendor, Patcher, MonkeyPatch, ReactComponents, ReactHelpers, ReactAutoPatcher, DiscordApi, BdWebApi, Connectivity, Cache, Reflection, PackageInstaller } from 'modules';
import { ClientLogger as Logger, ClientIPC, Utils, Axi } from 'common';
import { BuiltinManager, EmoteModule, ReactDevtoolsModule, VueDevtoolsModule, TrackingProtection, E2EE } from 'builtin';
import { ErrorEvent } from 'structs';
import electron from 'electron';
import path from 'path';
@ -70,6 +71,9 @@ class BetterDiscord {
this.globalReady = this.globalReady.bind(this);
Events.on('global-ready', this.globalReady);
Globals.initg();
this.showNativeModuleErrors = this.showNativeModuleErrors.bind(this);
Events.on('show-native-module-errors', this.showNativeModuleErrors);
}
globalReady() {
@ -80,6 +84,9 @@ class BetterDiscord {
async init() {
try {
Logger.log('main', ['Native module errors', Globals.nativeModuleErrors]);
Events.emit('show-native-module-errors');
await Database.init();
await Settings.loadSettings();
await ModuleManager.initModules();
@ -103,6 +110,23 @@ class BetterDiscord {
}
}
showNativeModuleErrors() {
if (!Globals.nativeModuleErrorCount) return;
return Modals.error({
header: `${Globals.nativeModuleErrorCount} native module${Globals.nativeModuleErrorCount !== 1 ? 's' : ''} failed to load`,
module: 'core',
type: 'err',
message: 'Some features will be unavailable. This normally happens when Discord updates Electron. Make sure you\'re running the latest version of Discord and BetterDiscord and try again.'
+ (tests ? ' You can also try recompiling native modules.' : ''),
content: Object.entries(Globals.nativeModuleErrors).map(([name, err]) => new ErrorEvent({
module: name,
message: `Failed to load ${name}`,
err
}))
});
}
initTests() {
let notifications = 0;
function showDummyNotif() { // eslint-disable-line no-inner-declarations

View File

@ -42,6 +42,9 @@ export default new class extends Module {
});
this.setState({ config });
const nativeModuleErrors = await ClientIPC.getNativeModuleErrors();
this.setState({ nativeModuleErrors });
// This is for Discord to stop error reporting :3
window.BetterDiscord = {
version: config.version,
@ -105,4 +108,12 @@ export default new class extends Module {
return this.config.versions.core;
}
get nativeModuleErrors() {
return this.state.nativeModuleErrors;
}
get nativeModuleErrorCount() {
return Object.keys(this.nativeModuleErrors).length;
}
}

View File

@ -58,6 +58,20 @@
}
}
.bd-sidebarMessage {
display: flex;
padding: 6px 10px;
cursor: pointer;
.bd-materialDesignIcon {
margin-right: 10px;
}
&.bd-err svg {
fill: $colerr;
}
}
.bd-info {
display: flex;
align-items: flex-end;

View File

@ -16,6 +16,15 @@
<MiClose size="17"/>
<span class="bd-xText">ESC</span>
</div>
<div v-if="nativeModuleErrorCount" class="bd-sidebarMessage bd-err" @click="showNativeModuleErrors">
<MiError size="20" />
<div>
<strong>{{ nativeModuleErrorCount }} native module{{ nativeModuleErrorCount !== 1 ? 's' : '' }} failed to load.</strong>
Some features will be unavailable.
</div>
</div>
<template v-for="(category, text) in sidebar">
<SidebarItem :item="{text, type: 'header'}" />
<SidebarItem v-for="i in category" :key="i.id" :item="i" :active="item && i.id === item.id" @click="itemOnClick(i.id)" />
@ -70,7 +79,7 @@
import { shell } from 'electron';
import { SidebarView, Sidebar, SidebarItem, ContentColumn } from './sidebar';
import { SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView, UpdaterView, ConnectivityView, SuperSecretView } from './bd';
import { SvgX, MiGithubCircle, MiWeb, MiClose, MiTwitterCircle } from './common';
import { SvgX, MiGithubCircle, MiWeb, MiClose, MiTwitterCircle, MiError } from './common';
export default {
data() {
@ -89,7 +98,7 @@
components: {
SidebarView, Sidebar, SidebarItem, ContentColumn,
SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView, UpdaterView, ConnectivityView, SuperSecretView,
MiGithubCircle, MiWeb, MiClose, MiTwitterCircle
MiGithubCircle, MiWeb, MiClose, MiTwitterCircle, MiError
},
computed: {
sidebar() {
@ -103,6 +112,9 @@
},
versionString() {
return Globals.version;
},
nativeModuleErrorCount() {
return Globals.nativeModuleErrorCount;
}
},
methods: {
@ -126,6 +138,9 @@
},
openTwitter() {
shell.openExternal('https://twitter.com/Jiiksi');
},
showNativeModuleErrors() {
Events.emit('show-native-module-errors');
}
},
watch: {

View File

@ -3,6 +3,8 @@
:class="{'bd-err': modal.event.type && modal.event.type === 'err'}">
<MiError v-if="modal.event.type === 'err'" slot="icon" size="20"/>
<div slot="body">
<p v-if="modal.event.message">{{ modal.event.message }}</p>
<div v-for="(content, index) in modal.event.content">
<div class="bd-modalError" :class="{'bd-open': content.showStack}">
<div class="bd-modalErrorTitle bd-flex">

View File

@ -104,6 +104,10 @@ const ClientIPC = new class ClientIPC {
return this.send('native-open', options);
}
getNativeModuleErrors() {
return this.send('getNativeModuleErrors');
}
compileSass(options) {
return this.send('compileSass', options);
}

View File

@ -42,13 +42,12 @@ const TEST_ARGS = () => {
const TEST_EDITOR = TESTS && true;
import path from 'path';
import sass from 'node-sass';
import { BrowserWindow as OriginalBrowserWindow, dialog, session, shell } from 'electron';
import deepmerge from 'deepmerge';
import ContentSecurityPolicy from 'csp-parse';
import keytar from 'keytar';
import { FileUtils, BDIpc, Config, WindowUtils, Updater, Editor, Database } from './modules';
import { sass, keytar, native_module_errors } from './modules';
const packageJson = require(path.resolve(__dirname, 'package.json'));
const sparkplug = path.resolve(__dirname, 'sparkplug.js');
@ -80,7 +79,14 @@ class Comms {
});
});
BDIpc.on('bd-getNativeModuleErrors', () => native_module_errors, true);
BDIpc.on('bd-compileSass', (event, options) => {
if (!sass) {
event.reject(native_module_errors.sass);
return;
}
if (typeof options.path === 'string' && typeof options.data === 'string') {
options.data = `${options.data} @import '${options.path.replace(/\\/g, '\\\\').replace(/'/g, '\\\'')}';`;
options.path = undefined;
@ -94,10 +100,22 @@ class Comms {
BDIpc.on('bd-dba', (event, options) => this.bd.database.exec(options), true);
BDIpc.on('bd-keytar-get', (event, { service, account }) => keytar.getPassword(service, account), true);
BDIpc.on('bd-keytar-set', (event, { service, account, password }) => keytar.setPassword(service, account, password), true);
BDIpc.on('bd-keytar-delete', (event, { service, account }) => keytar.deletePassword(service, account), true);
BDIpc.on('bd-keytar-find-credentials', (event, { service }) => keytar.findCredentials(service), true);
BDIpc.on('bd-keytar-get', (event, { service, account }) => {
if (!keytar) throw native_module_errors.keytar;
return keytar.getPassword(service, account);
}, true);
BDIpc.on('bd-keytar-set', (event, { service, account, password }) => {
if (!keytar) throw native_module_errors.keytar;
return keytar.setPassword(service, account, password);
}, true);
BDIpc.on('bd-keytar-delete', (event, { service, account }) => {
if (!keytar) throw native_module_errors.keytar;
return keytar.deletePassword(service, account);
}, true);
BDIpc.on('bd-keytar-find-credentials', (event, { service }) => {
if (!keytar) throw native_module_errors.keytar;
return keytar.findCredentials(service);
}, true);
BDIpc.on('bd-readDataFile', async (event, fileName) => {
const rf = await FileUtils.readFile(path.resolve(configProxy().getPath('data'), fileName));

View File

@ -14,9 +14,10 @@ import { BrowserWindow } from 'electron';
import Module from './modulebase';
import { WindowUtils, FileUtils } from './utils';
import BDIpc from './bdipc';
import sass from 'node-sass';
import chokidar from 'chokidar';
import { sass, native_module_errors } from '.';
export default class Editor extends Module {
constructor(bd, path) {
@ -123,6 +124,11 @@ export default class Editor extends Module {
return;
}
if (!sass) {
event.reject(native_module_errors.sass);
return;
}
style = await Promise.all(style.split('\n').map(async(line) => {
if (!line.startsWith('@import')) return line;
const filename = line.split(' ')[1].replace(/'|"|;/g, '');

View File

@ -5,3 +5,19 @@ export { default as CSSEditor } from './csseditor';
export { default as Editor } from './editor';
export { default as Database } from './database';
export { default as Updater } from './updater';
export const native_module_errors = {};
try {
exports.sass = require('node-sass');
} catch (err) {
console.error('[BetterDiscord] Error loading node-sass', err);
native_module_errors.sass = err instanceof Error ? {message: err.message, stack: err.stack} : err;
}
try {
exports.keytar = require('keytar');
} catch (err) {
console.error('[BetterDiscord] Error loading keytar', err);
native_module_errors.keytar = err instanceof Error ? {message: err.message, stack: err.stack} : err;
}