Plugin improvements and JSDoc

This commit is contained in:
Isaac 2021-02-17 20:17:35 +00:00
parent 7e67161cf1
commit 14d7c32742
No known key found for this signature in database
GPG Key ID: 279D1F53391CED07
6 changed files with 222 additions and 25 deletions

View File

@ -62,7 +62,6 @@ markdown_extensions:
permalink: true permalink: true
- footnotes - footnotes
- meta - meta
# pymd
- pymdownx.arithmatex - pymdownx.arithmatex
- pymdownx.betterem: - pymdownx.betterem:
smart_enable: all smart_enable: all

View File

@ -66,6 +66,7 @@ const log = new Logger({
const I18n = require('@eartharoid/i18n'); const I18n = require('@eartharoid/i18n');
const { CommandManager } = require('./modules/commands'); const { CommandManager } = require('./modules/commands');
const { PluginManager } = require('./modules/plugins');
const { const {
Client, Client,
@ -84,20 +85,29 @@ class Bot extends Client {
intents: Intents.NON_PRIVILEGED, intents: Intents.NON_PRIVILEGED,
} }
}); });
/** The global bot configuration */
Object.assign(this, { this.config= config;
commands: new CommandManager(this), /** A sequelize instance */
config, this.db = require('./database')(log), // this.db.models.Ticket...
db: require('./database')(log), // this.db.models.Ticket... /** A leekslazylogger instance */
log, this.log = log;
i18n: new I18n(path('./src/locales'), 'en-GB') /** An @eartharoid/i18n instance */
}); this.i18n = new I18n(path('./src/locales'), 'en-GB');
// set the max listeners for each event to the number in the config
this.setMaxListeners(this.config.max_listeners); this.setMaxListeners(this.config.max_listeners);
// check for updates
require('./updater')(this); require('./updater')(this);
// load internal listeners
require('./modules/listeners')(this); require('./modules/listeners')(this);
require('./modules/plugins')(this);
/** The command manager, used by internal and plugin commands */
this.commands = new CommandManager(this);
/** The plugin manager */
this.plugins = new PluginManager(this);
// load plugins
this.plugins.load();
this.log.info('Connecting to Discord API...'); this.log.info('Connecting to Discord API...');

View File

@ -1,14 +0,0 @@
module.exports = client => {
client.config.plugins.forEach(plugin => {
try {
let package = require(`${plugin}/package.json`);
client.log.plugins(`Loading ${package.name} v${package.version} by ${package.author?.name || 'unknown'}`);
require(plugin)(client);
} catch (e) {
client.log.warn(`An error occurred whilst loading ${plugin}, have you installed it?`);
client.log.error(e);
return process.exit();
}
});
};

View File

@ -0,0 +1,4 @@
module.exports = {
PluginManager: require('./manager'),
Plugin: require('./plugin')
};

View File

@ -0,0 +1,110 @@
// eslint-disable-next-line no-unused-vars
const { Collection, Client } = require('discord.js');
// eslint-disable-next-line no-unused-vars
const Plugin = require('./plugin');
const fs = require('fs');
const { join } = require('path');
const { path } = require('../../utils/fs');
/** Manages the loading of plugins */
module.exports = class PluginManager {
/**
* Create a PluginManager instance
* @param {Client} client
*/
constructor(client) {
/** The Discord Client */
this.client = client;
/** A discord.js Collection (Map) of loaded plugins */
this.plugins = new Collection();
/** Array of official plugins to be used to check if a plugin is official */
this.official = [
'dsctickets.portal'
];
}
/**
* Register and load a plugin
* @param {Boolean} npm Installed by NPM?
* @param {Plugin} Main The Plugin class
* @param {Object} pkg Contents of package.json
*/
registerPlugin(npm, Main, pkg) {
let {
name: id,
version,
author,
description
} = pkg;
if (this.plugins.has(id)) {
this.client.log.warn(`[PLUGINS] A plugin with the ID "${id}" is already loaded, skipping`);
return;
}
if (typeof author === 'object') {
author = author.name || 'unknown';
}
let loading = npm ? 'Loading' : 'Sideloading';
this.client.log.plugins(`${loading} "${id}" v${version} by ${author}`);
let about = {
id,
version,
author,
description
};
this.plugins.set(id, about);
try {
let plugin = new Main(this.client, id);
plugin.load();
this.plugins.set(id, Object.assign(about, {
name: plugin.name || id,
}));
} catch (e) {
if (npm) {
this.client.log.warn(`An error occurred whilst loading "${id}"`);
} else {
this.client.log.warn(`An error occurred whilst sideloading "${id}"; have you manually installed its dependencies?`);
}
this.client.log.error(e);
process.exit();
}
}
/**
* Automatically register and load plugins
*/
load() {
// normal plugins (NPM)
this.client.config.plugins.forEach(plugin => {
try {
let pkg = require(`${plugin}/package.json`);
let main = require(plugin);
this.registerPlugin(true, main, pkg);
} catch (e) {
this.client.log.warn(`An error occurred whilst loading ${plugin}; have you installed it?`);
this.client.log.error(e);
process.exit();
}
});
// sideload plugins for development
const dirs = fs.readdirSync(path('./user/plugins'));
dirs.forEach(dir => {
if (!fs.existsSync(path(`./user/plugins/${dir}/package.json`))) return;
let pkg = require(`../../../user/plugins/${dir}/package.json`);
let main = require(join(`../../../user/plugins/${dir}/`, pkg.main));
this.registerPlugin(false, main, pkg);
});
}
};

View File

@ -0,0 +1,88 @@
/* eslint-disable no-unused-vars */
const { Client } = require('discord.js');
const fs = require('fs');
const { join } = require('path');
const { path } = require('../../utils/fs');
/** A plugin */
module.exports = class Plugin {
/**
* Create a new Plugin
* @param {Client} client The Discord Client
* @param {String} id The plugin ID
* @param {Object} options Plugin options
* @param {String} options.name A human-friendly name (can be different to the name in package.json)
*/
constructor(client, id, options) {
if (typeof options === 'object') {
/** The human-friendly name of the plugin */
this.name = options.name || id;
}
/** The Discord Client */
this.client = client;
/** The PluginManager */
this.manager = this.client.plugins;
// Object.assign(this, this.manager.plugins.get(id));
// make JSDoc happy
let {
version,
author,
description
} = this.manager.plugins.get(id);
/** The unique ID of the plugin (NPM package name) */
this.id = id;
/** The version of the plugin (NPM package version) */
this.version = version;
/** The plugin author's name (NPM package author) */
this.author = author;
/** The plugin description (NPM package description) */
this.description = description;
this.directory = {};
/** A cleaned version of the plugin's ID suitable for use in the directory name */
this.directory.name = this.id.replace(/@[-_a-zA-Z0-9]+\//, '');
/** The absolute path of the plugin directory */
this.directory.path = path(`./user/plugins/${this.directory.name}`);
}
/**
* Create the plugin directory if it doesn't already exist
* @returns {Boolean} True if created, false if it already existed
*/
createDirectory() {
if (!fs.existsSync(this.directory.path)) {
this.client.log.plugins(`Creating plugin directory for "${this.name}"`);
fs.mkdirSync(this.directory.path);
return true;
} else {
return false;
}
}
/**
* Create the plugin config file if it doesn't already exist
* @param {Object} template The default config template
* @returns {Boolean} True if created, false if it already existed
*/
createConfig(template) {
this.createDirectory();
let file = join(this.directory.path, 'config.json');
if (!fs.existsSync(file)) {
this.client.log.plugins(`Creating plugin config file for "${this.name}"`);
fs.writeFileSync(file, JSON.stringify(template, null, 2));
return true;
} else {
return false;
}
}
/**
* The main function where your code should go. Create functions and event listeners here
*/
load() {}
};