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} */ 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>} * @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(/(? x.replace(/^ +/, '')); for (let indepCommand of independentCommands) commandSequence.push(indepCommand .split(/(? 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 });