const Discord = require('discord.js');
const plugin_name_to_class = require('./plugins/index.js').name_to_class;
/**
* CoolPal is a bot for Discord with plugins.
*
* @example
* // Copy the plugin configuration file from examples and fill in API keys
* // and the Discord API token
* fs.readFile('path/to/your/configuration/file.json', (err, data) => {
* if (err) {
* throw err;
* }
*
* let configuration = JSON.parse(data);
*
* let pal = new CoolPal(configuration);
* pal.start();
* });
*/
class CoolPal {
/**
* Create your pal.
*
* @constructs CoolPal
*
* @param {Object} config - The high level configuration object for CoolPal.
* @param {string} config.token - A token for the Discord API.
* @param {Object[]} config.plugins - Plugins to enable.
* @param {string} config.plugins[].name - The name of a plugin.
* @param {Object} config.plugins[].configuration - Configuration specific to the plugin.
*
* @todo Throw an error if no token is provided.
*/
constructor(config) {
/**
* @member {Object} CoolPal#config - The high level configuration object for CoolPal.
*/
this.config = config;
/**
* @member {Object} CoolPal#client - A Discord API client.
*/
this.client = new Discord.Client();
/**
* @member {Object} CoolPal#discord_token - A Discord bot API token.
*/
this.discord_token = this.config.token;
/**
* @member {Object[]} CoolPal#prefix - The prefix for all plugin commands.
*/
this.prefix = this.config.prefix || '!';
/**
* @member {Object[]} CoolPal#_event_types - A list of unique event types.
* @private
*/
this._event_types = [];
/**
* @member {Object[]} CoolPal#_plugins - A list of configured plugin instances.
* @private
*/
this._plugins = [];
// End of member variables
this._configure_plugins(this.config.plugins);
}
/**
* Return a list of plugins
*
* @return {Object[]} A list of plugin for this instance.
*
* @example
* // Iterate over the plugins
* for (let plugin of pal.plugins) {
* console.log(plugin.command)
* }
*
*/
get plugins() {
return this._plugins;
}
/**
* Starts the event loop.
*
* @example
* let pal = CoolPal({
* token: process.env.DISCORD_TOKEN,
* plugins: []
* });
* pal.start();
*/
start() {
this._login();
this._ready();
this._receive_events();
}
/**
* Creates an instance of a plugin using a plugin config
*
* @param {Object} plugin_config - The configuration object for a plugin
* @param {string} plugin_config.name - The name of the plugin
* @param {Object} plugin_config.configuration - An object that changes plugin functionality
*
* @returns An instance of the class corresponding to plugin_config.name
* @private
*/
_configure_plugin(plugin_config) {
let plugin_class = plugin_name_to_class[plugin_config.name];
return new plugin_class(plugin_config.configuration);
}
/**
* Instantiates multiple plugins based on a configuration file.
*
* @param {Object[]} plugins_config - Highest level configuration object for multiple plugins.
*
* @private
*/
_configure_plugins(plugins_config) {
for (let plugin_config of plugins_config) {
this._register_plugin(this._configure_plugin(plugin_config));
}
}
/**
* Adds a plugin to the instance and configured event types to handle new events.
*
* @param {Object} plugin - A single configured plugin that extends Plugin.
* @private
*/
_register_plugin(plugin) {
this._plugins.push(plugin);
for (let event_type of plugin.supported_event_types) {
if (!this._event_types.includes(event_type)) {
this._event_types.push(event_type);
}
}
}
/**
* Logs in to the Discord API.
*
* @private
*/
_login() {
this.client.login(this.discord_token);
}
/**
* Logs in to the Discord API.
*
* @private
*
* @todo Allow user to set their ready message
*/
_ready() {
this.client.on('ready', () => {
console.log('Just saying im ready');
});
}
/**
* Register an event type to be received by all plugins.
*
* @private
*
* @todo Allow user to set their ready message
*/
_receive_event(event_type) {
this.client.on(event_type, event => {
for (let plugin of this._plugins) {
let handled_event = plugin.handle_event(event_type, event, {
client: this.client,
prefix: this.prefix
});
}
});
}
/**
* Registers all event types to be receives by all plugins.
*
* @private
*/
_receive_events() {
for (let event_type of this._event_types) {
this._receive_event(event_type);
}
}
};
module.exports = CoolPal;