Cleanup core

This commit is contained in:
Samuel Elliott 2018-03-21 17:41:27 +00:00
parent a4a130bfc6
commit dc44af6968
No known key found for this signature in database
GPG Key ID: 8420C7CDE43DC4D6
8 changed files with 143 additions and 141 deletions

View File

@ -15,43 +15,40 @@ const { FileUtils, BDIpc, Config, WindowUtils, CSSEditor, Database } = require('
const { BrowserWindow, dialog } = require('electron');
const tests = true;
const _basePath = __dirname;
const _basePath = tests ? path.resolve(__dirname, '..', '..') : __dirname;
const _baseDataPath = tests ? path.resolve(_basePath, 'tests') : _basePath;
const sparkplug = path.resolve(__dirname, 'sparkplug.js');
const _clientScript = tests
? path.resolve(__dirname, '..', '..', 'client', 'dist', 'betterdiscord.client.js')
: path.resolve(__dirname, 'betterdiscord.client.js');
const _dataPath = tests
? path.resolve(__dirname, '..', '..', 'tests', 'data')
: path.resolve(__dirname, 'data');
const _extPath = tests
? path.resolve(__dirname, '..', '..', 'tests', 'ext')
: path.resolve(__dirname, 'ext');
const _pluginPath = path.resolve(_extPath, 'plugins');
const _themePath = path.resolve(_extPath, 'themes');
const _modulePath = path.resolve(_extPath, 'modules');
? path.resolve(_basePath, 'client', 'dist', 'betterdiscord.client.js')
: path.resolve(_basePath, 'betterdiscord.client.js');
const _cssEditorPath = tests
? path.resolve(__dirname, '..', '..', 'csseditor', 'dist')
: path.resolve(__dirname, 'csseditor');
const _dataPath = path.resolve(_baseDataPath, 'data');
const _extPath = path.resolve(_baseDataPath, 'ext');
const _pluginPath = path.resolve(_extPath, 'plugins');
const _themePath = path.resolve(_extPath, 'themes');
const _modulePath = path.resolve(_extPath, 'modules');
const paths = [
{ id: 'base', path: _basePath.replace(/\\/g, '/') },
{ id: 'cs', path: _clientScript.replace(/\\/g, '/') },
{ id: 'data', path: _dataPath.replace(/\\/g, '/') },
{ id: 'ext', path: _extPath.replace(/\\/g, '/') },
{ id: 'plugins', path: _pluginPath.replace(/\\/g, '/') },
{ id: 'themes', path: _themePath.replace(/\\/g, '/') },
{ id: 'modules', path: _modulePath.replace(/\\/g, '/') },
{ id: 'csseditor', path: _cssEditorPath.replace(/\\/g, '/') }
{ id: 'base', path: _basePath },
{ id: 'cs', path: _clientScript },
{ id: 'data', path: _dataPath },
{ id: 'ext', path: _extPath },
{ id: 'plugins', path: _pluginPath },
{ id: 'themes', path: _themePath },
{ id: 'modules', path: _modulePath },
{ id: 'csseditor', path: _cssEditorPath }
];
const sparkplug = path.resolve(__dirname, 'sparkplug.js').replace(/\\/g, '/');
const Common = {};
const globals = {
version: '2.0.0a',
paths
}
const dbInstance = new Database(paths.find(path => path.id === 'data').path);
};
class Comms {
@ -61,9 +58,7 @@ class Comms {
}
initListeners() {
BDIpc.on('bd-getConfig', o => {
o.reply(Common.Config.config);
});
BDIpc.on('bd-getConfig', o => o.reply(this.bd.config.config));
BDIpc.on('bd-sendToDiscord', event => this.bd.windowUtils.send(event.args.channel, event.args.message));
@ -71,9 +66,6 @@ class Comms {
// BDIpc.on('bd-setScss', o => this.bd.csseditor.setSCSS(o.args.scss));
BDIpc.on('bd-sendToCssEditor', o => this.bd.csseditor.send(o.args.channel, o.args.data));
BDIpc.on('bd-readFile', this.readFile);
BDIpc.on('bd-readJson', o => this.readFile(o, true));
BDIpc.on('bd-native-open', o => {
dialog.showOpenDialog(BrowserWindow.fromWebContents(o.ipcEvent.sender), o.args, filenames => {
o.reply(filenames);
@ -88,36 +80,22 @@ class Comms {
}
sass.render(o.args, (err, result) => {
if (err) {
o.reply({ err });
return;
}
o.reply(result);
if (err) return o.reply({ err });
else o.reply(result);
});
});
BDIpc.on('bd-dba', o => {
(async () => {
try {
const ret = await dbInstance.exec(o.args);
o.reply(ret);
o.reply(await this.bd.dbInstance.exec(o.args));
} catch (err) {
o.reply({err});
o.reply({ err });
}
})();
});
}
async readFile(o, json) {
const { path } = o.args;
try {
const readFile = json ? await FileUtils.readJsonFromFile(path) : await FileUtils.readFile(path);
o.reply(readFile);
} catch (err) {
o.reply(err);
}
}
async send(channel, message) {
BDIpc.send(channel, message);
}
@ -135,23 +113,25 @@ class BetterDiscord {
this.injectScripts = this.injectScripts.bind(this);
this.ignite = this.ignite.bind(this);
Common.Config = new Config(globals);
this.config = new Config(args || globals);
this.dbInstance = new Database(this.config.paths.find(path => path.id === 'data').path);
this.comms = new Comms(this);
this.init();
}
async init() {
const window = await this.waitForWindow();
this.windowUtils = new WindowUtils({ window });
await this.waitForWindowUtils();
await FileUtils.ensureDirectory(paths.find(path => path.id === 'ext').path);
await FileUtils.ensureDirectory(this.config.paths.find(path => path.id === 'ext').path);
this.csseditor = new CSSEditor(this, paths.find(path => path.id === 'csseditor').path);
this.csseditor = new CSSEditor(this, this.config.paths.find(path => path.id === 'csseditor').path);
this.windowUtils.events('did-get-response-details', () => this.ignite(this.windowUtils.window));
this.windowUtils.events('did-finish-load', e => this.injectScripts(true));
this.windowUtils.on('did-get-response-details', () => this.ignite());
this.windowUtils.on('did-finish-load', e => this.injectScripts(true));
this.windowUtils.events('did-navigate-in-page', (event, url, isMainFrame) => {
this.windowUtils.on('did-navigate-in-page', (event, url, isMainFrame) => {
this.windowUtils.send('did-navigate-in-page', { event, url, isMainFrame });
});
@ -166,10 +146,8 @@ class BetterDiscord {
const defer = setInterval(() => {
const windows = BrowserWindow.getAllWindows();
if (windows.length > 0) {
windows.forEach(window => {
self.ignite(window);
});
for (let window of windows) {
BetterDiscord.ignite(window);
}
if (windows.length === 1 && windows[0].webContents.getURL().includes('discordapp.com')) {
@ -180,23 +158,45 @@ class BetterDiscord {
});
}
ignite(window) {
//Hook things that Discord removes from global. These will be removed again in the client script
window.webContents.executeJavaScript(`require("${sparkplug}");`);
async waitForWindowUtils() {
if (this.windowUtils) return this.windowUtils;
const window = await this.waitForWindow();
return this.windowUtils = new WindowUtils({ window });
}
get window() {
return this.windowUtils ? this.windowUtils.window : undefined;
}
/**
* Hooks things that Discord removes from global. These will be removed again in the client script.
*/
ignite() {
return BetterDiscord.ignite(this.window);
}
/**
* Hooks things that Discord removes from global. These will be removed again in the client script.
* @param {BrowserWindow} window The window to inject the sparkplug script into
*/
static ignite(window) {
return WindowUtils.injectScript(window, sparkplug);
}
/**
* Injects the client script into the main window.
* @param {Boolean} reload Whether the main window was reloaded
*/
async injectScripts(reload = false) {
console.log(`RELOAD? ${reload}`);
if (!tests) {
const files = await FileUtils.listDirectory(paths.find(path => path.id === 'base').path);
const files = await FileUtils.listDirectory(this.config.paths.find(path => path.id === 'base').path);
const latestCs = FileUtils.resolveLatest(files, file => file.endsWith('.js') && file.startsWith('client.'), file => file.replace('client.', '').replace('.js', ''), 'client.', '.js');
paths.find(path => path.id === 'cs').path = path.resolve(paths.find(path => path.id === 'base').path, latestCs).replace(/\\/g, '/');
this.config.paths.find(path => path.id === 'cs').path = path.resolve(this.config.paths.find(path => path.id === 'base').path, latestCs);
}
this.windowUtils.injectScript(paths.find(path => path.id === 'cs').path);
return this.windowUtils.injectScript(this.config.paths.find(path => path.id === 'cs').path);
}
get fileUtils() { return FileUtils; }
}
module.exports = {

View File

@ -5,14 +5,15 @@
* https://github.com/JsSucks - https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* LICENSE file in the root directory of this source tree.
*/
const { Module } = require('./modulebase');
const { ipcMain } = require('electron');
class BDIpcEvent extends Module {
constructor(event, args) {
super(args);
this.ipcEvent = event;
@ -34,10 +35,9 @@ class BDIpcEvent extends Module {
}
class BDIpc {
static on(channel, cb) {
ipcMain.on(channel, (event, args) => cb(new BDIpcEvent(event, args)));
}
}
module.exports = { BDIpc };
module.exports = { BDIpc };

View File

@ -5,7 +5,7 @@
* https://github.com/JsSucks - https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* LICENSE file in the root directory of this source tree.
*/
const { Module } = require('./modulebase');
@ -22,11 +22,11 @@ class Config extends Module {
get config() {
return {
'version': this.version,
'paths': this.paths
version: this.version,
paths: this.paths
};
}
}
module.exports = { Config };
module.exports = { Config };

View File

@ -22,6 +22,10 @@ class CSSEditor extends Module {
this.bd = bd;
}
/**
* Opens an editor and replies to an IPC event.
* @param {BDIpcEvent} event
*/
openEditor(o) {
if (this.editor) {
if (this.editor.isFocused()) return;
@ -32,12 +36,7 @@ class CSSEditor extends Module {
return;
}
const options = this.options;
for (let option in o.args) {
if (o.args.hasOwnProperty(option)) {
options[option] = o.args[option];
}
}
const options = Object.assign({}, this.options, o.message);
this.editor = new BrowserWindow(options);
this.editor.loadURL('about:blank');
@ -59,20 +58,34 @@ class CSSEditor extends Module {
});
}
/**
* Sets the SCSS in the editor.
*/
setSCSS(scss) {
this.send('set-scss', scss);
}
/**
* Sends data to the editor.
* @param {String} channel
* @param {Any} data
*/
send(channel, data) {
if (!this.editor) return;
this.editor.webContents.send(channel, data);
}
/**
* Sets the CSS editor's always on top flag.
*/
set alwaysOnTop(state) {
if (!this.editor) return;
this.editor.setAlwaysOnTop(state);
}
/**
* Default options to pass to BrowserWindow.
*/
get options() {
return {
width: 800,
@ -81,7 +94,7 @@ class CSSEditor extends Module {
frame: false
};
}
}
module.exports = { CSSEditor };

View File

@ -10,7 +10,7 @@
const Datastore = require('nedb');
class Database {
class Database {
constructor(dbPath) {
this.exec = this.exec.bind(this);

View File

@ -5,20 +5,19 @@
* https://github.com/JsSucks - https://betterdiscord.net
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/*
Base Module that every non-static module should extend
* LICENSE file in the root directory of this source tree.
*/
/**
* Base Module that every non-static module should extend.
*/
class Module {
constructor(args) {
this.__ = {
state: args,
args
}
};
this.init();
}
@ -33,4 +32,4 @@ class Module {
}
module.exports = { Module };
module.exports = { Module };

View File

@ -10,43 +10,35 @@
// TODO Use common
const
path = require('path'),
fs = require('fs');
const path = require('path');
const fs = require('fs');
const { Module } = require('./modulebase');
class Utils {
static async tryParseJson(jsonString) {
try {
return JSON.parse(jsonString);
}catch(err) {
} catch (err) {
throw ({
'message': 'Failed to parse json',
message: 'Failed to parse json',
err
});
}
}
static get timestamp() {
return 'Timestamp';
}
}
class FileUtils {
static async fileExists(path) {
return new Promise((resolve, reject) => {
fs.stat(path, (err, stats) => {
if(err) return reject({
'message': `No such file or directory: ${err.path}`,
message: `No such file or directory: ${err.path}`,
err
});
if(!stats.isFile()) return reject({
'message': `Not a file: ${path}`,
message: `Not a file: ${path}`,
stats
});
@ -59,12 +51,12 @@ class FileUtils {
return new Promise((resolve, reject) => {
fs.stat(path, (err, stats) => {
if(err) return reject({
'message': `Directory does not exist: ${path}`,
message: `Directory does not exist: ${path}`,
err
});
if(!stats.isDirectory()) return reject({
'message': `Not a directory: ${path}`,
message: `Not a directory: ${path}`,
stats
});
@ -76,14 +68,14 @@ class FileUtils {
static async readFile(path) {
try {
await this.fileExists(path);
} catch(err) {
throw(err);
} catch (err) {
throw err;
}
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf-8', (err, data) => {
if(err) reject({
'message': `Could not read file: ${path}`,
if(err) return reject({
message: `Could not read file: ${path}`,
err
});
@ -97,14 +89,13 @@ class FileUtils {
try {
readFile = await this.readFile(path);
} catch(err) {
throw(err);
throw err;
}
try {
const parsed = await Utils.tryParseJson(readFile);
return parsed;
} catch(err) {
throw(Object.assign(err, { path }));
return await Utils.tryParseJson(readFile);
} catch (err) {
throw Object.assign(err, { path });
}
}
@ -113,8 +104,8 @@ class FileUtils {
await this.directoryExists(path);
return new Promise((resolve, reject) => {
fs.readdir(path, (err, files) => {
if (err) return reject(err);
resolve(files);
if (err) reject(err);
else resolve(files);
});
});
} catch (err) {
@ -145,11 +136,8 @@ class FileUtils {
static async createDirectory(path) {
return new Promise((resolve, reject) => {
fs.mkdir(path, err => {
if (err) {
if (err.code === 'EEXIST') return resolve();
else return reject(err);
}
resolve();
if (err) reject(err);
else resolve();
});
});
}
@ -170,7 +158,6 @@ class FileUtils {
}
class WindowUtils extends Module {
bindings() {
this.openDevTools = this.openDevTools.bind(this);
this.executeJavascript = this.executeJavascript.bind(this);
@ -194,16 +181,20 @@ class WindowUtils extends Module {
}
injectScript(fpath, variable) {
console.log(`Injecting: ${fpath}`);
return WindowUtils.injectScript(this.window, fpath, variable);
}
static injectScript(window, fpath, variable) {
// console.log(`Injecting: ${fpath}`);
const escaped_path = fpath.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
const escaped_variable = variable ? variable.replace(/\\/g, '\\\\').replace(/"/g, '\\"') : null;
if (variable) this.executeJavascript(`window["${escaped_variable}"] = require("${escaped_path}");`);
else this.executeJavascript(`require("${escaped_path}");`);
if (variable) window.executeJavaScript(`window["${escaped_variable}"] = require("${escaped_path}");`);
else window.executeJavaScript(`require("${escaped_path}");`);
}
events(event, callback) {
on(event, callback) {
this.webContents.on(event, callback);
}
@ -211,7 +202,6 @@ class WindowUtils extends Module {
channel = channel.startsWith('bd-') ? channel : `bd-${channel}`;
this.webContents.send(channel, message);
}
}
module.exports = {

View File

@ -33,18 +33,18 @@
</template>
<script>
import '../../node_modules/codemirror/addon/scroll/simplescrollbars.js';
import '../../node_modules/codemirror/mode/css/css.js';
import '../../node_modules/codemirror/addon/hint/css-hint.js';
import '../../node_modules/codemirror/addon/search/search.js';
import '../../node_modules/codemirror/addon/search/searchcursor.js';
import '../../node_modules/codemirror/addon/search/jump-to-line.js';
import '../../node_modules/codemirror/addon/dialog/dialog.js';
import '../../node_modules/codemirror/addon/hint/show-hint.js';
import BDIpc from './BDIpc';
const { remote } = window.require('electron');
import { remote } from 'electron';
import 'codemirror/addon/scroll/simplescrollbars.js';
import 'codemirror/mode/css/css.js';
import 'codemirror/addon/hint/css-hint.js';
import 'codemirror/addon/search/search.js';
import 'codemirror/addon/search/searchcursor.js';
import 'codemirror/addon/search/jump-to-line.js';
import 'codemirror/addon/dialog/dialog.js';
import 'codemirror/addon/hint/show-hint.js';
const ExcludedIntelliSenseTriggerKeys = {
'8': 'backspace',