You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
discordbot.js/lib/MessageLib.js

153 lines
5.3 KiB
JavaScript

const cmdLib = require('./CommandLib'),
config = require('../config.json'),
Discord = require('discord.js'),
promiseWaterfall = require('promise-waterfall');
class MessageHandler {
/**
* Message Handler to handle messages. Listens on the
* client message event.
* @param client {Discord.Client}
* @param logger {winston.logger}
*/
constructor (client, logger) {
this.logger = logger;
this.discordClient = client;
this.globalCmdHandler = new cmdLib.CommandHandler(config.prefix,
cmdLib.CommandScopes.Global);
this.userCmdHandler = new cmdLib.CommandHandler(config.prefix,
cmdLib.CommandScopes.User);
this.guildCmdHandler = new cmdLib.CommandHandler(config.prefix,
cmdLib.CommandScopes.Guild);
this._registerEvents();
}
/**
* Returns the handler fitting the scope
* @param scope {Number}
* @returns {cmdLib.CommandHandler}
*/
getHandler(scope) {
switch (scope) {
case cmdLib.CommandScopes.Global:
return this.globalCmdHandler;
case cmdLib.CommandScopes.Guild:
return this.guildCmdHandler;
case cmdLib.CommandScopes.User:
return this.userCmdHandler;
}
}
/**
* Registers a command module to a command handler.
* @param CommandModule {cmdLib.CommandModule}
* @param options {Object} Options passed to the module constructor.
* @returns {Promise<void>}
*/
async registerCommandModule(CommandModule, options) {
this.logger.info(`Registering command module ${CommandModule.name}...`);
let cmdModule = new CommandModule(options);
await cmdModule.register(this.getHandler(cmdModule.scope));
}
/**
* Registering event handlers.
* @private
*/
_registerEvents() {
this.logger.debug('Registering message event...');
this.discordClient.on('message', async (msg) => {
this.logger.debug(`<${msg.guild? msg.channel.name+'@'+msg.guild.name : 'PRIVATE'}> ${msg.author.tag}: ${msg.content}`);
if (msg.author !== this.discordClient.user) {
let sequence = this._parseSyntax(msg);
this.logger.debug(`Syntax parsing returned: ${JSON.stringify(sequence)}`);
await this._executeCommandSequence(sequence, msg);
this.logger.debug('Executed command sequence');
}
});
}
/**
* Parses the syntax of a message into a command array.
* @param message
* @returns {Array<Array<String>>}
* @private
*/
_parseSyntax(message) {
this.logger.debug('Parsing command sequence...');
let commandSequence = [];
let content = message.content;
let strings = content.match(/".+?"/g) || [];
for (let string of strings)
content = content.replace(string, string // escape all special chars
.replace(';', '\\;')
.replace('&', '\\&'));
let independentCommands = content // independent command sequende with ;
.split(/(?<!\\);/g)
.map(x => x.replace(/^ +/, ''));
for (let indepCommand of independentCommands)
commandSequence.push(indepCommand
.split(/(?<!\\)&&/g) // dependend sequence with && (like unix)
.map(x => x.replace(/^ +/, ''))
);
return commandSequence;
}
/**
* Executes a sequence of commands
*/
async _executeCommandSequence(cmdSequence, message) {
this.logger.debug(`Executing command sequence: ${JSON.stringify(cmdSequence)} ...`);
let scopeCmdHandler = this._getScopeHandler(message);
await Promise.all(cmdSequence.map((sq) => promiseWaterfall(sq.map((cmd) => async () => {
try {
this.logger.debug(`Executing command ${cmd}`);
let globalResult = await this.globalCmdHandler.handleCommand(cmd, message);
let scopeResult = await scopeCmdHandler.handleCommand(cmd, message);
this.logger.debug(`globalResult: ${globalResult}, scopeResult: ${scopeResult}`);
if (scopeResult)
this._answerMessage(message, scopeResult);
else if (globalResult)
this._answerMessage(message, globalResult);
} catch (err) {
this.logger.verbose(err.message);
this.logger.silly(err.stack);
}
}))));
}
/**
* Returns two commandHandlers for the messages scope.
* @param message
* @private
*/
_getScopeHandler(message) {
if (message && message.guild)
return this.guildCmdHandler;
else
return this.userCmdHandler;
}
/**
* Answers
* @param message {Discord.Message}
* @param answer {String | Discord.RichEmbed}
* @private
*/
_answerMessage(message, answer) {
this.logger.debug(`Sending answer ${answer}`);
if (answer)
if (answer instanceof Discord.RichEmbed)
message.channel.send('', answer);
else
message.channel.send(answer);
}
}
Object.assign(exports, {
MessageHandler: MessageHandler
});