Added command listing

- improved asynchronous command feature
- added waterfall to resolve array answers
- added function and array type to answerMessage types
pull/36/head
Trivernis 6 years ago
parent 13493d8db5
commit dd2a49209f

@ -6,6 +6,7 @@ const Discord = require("discord.js"),
utils = require('./lib/utils'),
config = require('./config.json'),
args = require('args-parser')(process.argv),
waterfall = require('promise-waterfall'),
sqliteAsync = require('./lib/sqliteAsync'),
authToken = args.token || config.api.botToken,
prefix = args.prefix || config.prefix || '~',
@ -177,7 +178,7 @@ class Bot {
try {
await msg.reply('Shutting down...');
logger.debug('Destroying client...');
} catch(err) {
} catch (err) {
logger.error(err.message);
logger.debug(err.stack);
}
@ -192,7 +193,7 @@ class Bot {
await this.webServer.stop();
logger.debug(`Exiting Process...`);
process.exit(0);
} catch(err) {
} catch (err) {
logger.error(err.message);
logger.debug(err.stack);
}
@ -261,7 +262,7 @@ class Bot {
game: {name: `${gamepresence} | ${pr}`, type: "PLAYING"},
status: 'online'
}).then(() => logger.debug(`Presence rotation to ${pr}`))
.catch((err) => logger.warn(err.message));
.catch((err) => logger.warn(err.message));
}
@ -325,20 +326,22 @@ class Bot {
* @param msg
* @param answer
*/
answerMessage(msg, answer) {
if (answer instanceof Promise || answer)
if (answer instanceof Discord.RichEmbed) {
(this.mention) ? msg.reply('', answer) : msg.channel.send('', answer);
} else if (answer instanceof Promise) {
answer
.then((answer) => this.answerMessage(msg, answer))
.catch((error) => this.answerMessage(msg, error));
} else {
(this.mention) ? msg.reply(answer) : msg.channel.send(answer);
}
else
logger.verbose(`Empty answer won't be send.`);
async answerMessage(msg, answer) {
if (answer instanceof Discord.RichEmbed) {
(this.mention) ? msg.reply('', answer) : msg.channel.send('', answer);
} else if (answer instanceof Promise) {
let resolvedAnswer = await answer;
await this.answerMessage(msg, resolvedAnswer);
} else if (answer instanceof Array) {
let answerPromises = [];
for (let answerPart of answer)
answerPromises.push(async () => await this.answerMessage(msg, answerPart));
await waterfall(answerPromises);
} else if ({}.toString.call(answer) === '[object Function]') {
await this.answerMessage(msg, answer());
} else if (answer) {
(this.mention) ? msg.reply(answer) : msg.channel.send(answer);
}
}
/**

@ -103,18 +103,19 @@ exports.Servant = class {
}
/**
* Parses the message and executes the command callback for the found command entry in the commands dict
* Processes the command
* @param msg
* @param globResult
* @param content
* @returns {*}
*/
parseCommand(msg) {
let globResult = parseGlobalCommand(msg);
logger.debug(`Global command result is ${globResult}`);
let content = msg.content;
processCommand(msg, globResult, content, returnFunction) {
let command = (content.match(/^.\w+/) || [])[0];
if (!command || !this.commands[command]) return globResult;
if (!command || !this.commands[command])
return globResult;
let cmd = this.commands[command];
if (!checkPermission(msg, cmd.role)) return 'No Permission';
if (!checkPermission(msg, cmd.role))
return 'No Permission';
logger.debug(`Permission <${cmd.role || 'all'}> granted for command ${command} for user <${msg.author.tag}>`);
let argvars = content.match(/(?<= )\S+/g) || [];
let kwargs = {};
@ -125,9 +126,7 @@ exports.Servant = class {
let argv = argvars.slice(nLength);
logger.debug(`Executing callback for command: ${command}, kwargs: ${kwargs}, argv: ${argv}`);
try {
let locResult = cmd.callback(msg, kwargs, argv);
if (locResult instanceof Promise)
return locResult; // because Promise equals false in conditional
let locResult = returnFunction? () => cmd.callback(msg, kwargs, argv) : cmd.callback(msg, kwargs, argv);
return locResult || globResult;
} catch (err) {
logger.error(err.message);
@ -135,6 +134,28 @@ exports.Servant = class {
}
}
/**
* Parses the message and executes the command callback for the found command entry in the commands dict
* @param msg
* @returns {*}
*/
parseCommand(msg) {
let globResult = parseGlobalCommand(msg);
logger.debug(`Global command result is ${globResult}`);
let content = msg.content;
let commands = content.split(';').map(x => x.replace(/^ +/, ''));
if (commands.length === 1) {
return this.processCommand(msg, globResult, content);
} else {
let answers = [];
for (let i = 0; i < commands.length; i++)
answers.push(this.processCommand(msg, globResult[i], commands[i],
true)); // return function to avoid "race conditions"
return answers;
}
}
};
/**
@ -158,7 +179,8 @@ exports.createGlobalCommand = function (command, call, args, description, role)
'args': args || [],
'description': description,
'callback': call,
'role': role
'role': role,
'name': command
};
logger.debug(`Created global command: ${command}, args: ${args}`);
};
@ -209,26 +231,48 @@ exports.init = function (prefix) {
}, ['command'], "Shows this help.");
};
/**
* Parses the message by calling the assigned function for the command with arguments
* @param msg
*/
function parseGlobalCommand(msg) {
let content = msg.content;
let command = (content.match(/^.\w+/) || [])[0];
if (!command || !globCommands[command]) return false;
let cmd = globCommands[command];
if (!checkPermission(msg, cmd.role)) return false;
logger.debug(`Permission <${cmd.role}> granted for command ${command} for user <${msg.author.tag}>`);
function processCommand(cmd, msg, content, returnFunction) {
let argvars = content.match(/(?<= )\S+/g) || [];
let kwargs = {};
let nLength = Math.min(cmd.args.length, argvars.length);
for (let i = 0; i < nLength; i++)
kwargs[cmd.args[i]] = argvars[i];
let argv = argvars.slice(nLength);
logger.debug(`Executing callback for command: ${command}, kwargs: ${JSON.stringify(kwargs)}, argv: ${argv}`);
return cmd.callback(msg, kwargs, argv);
logger.debug(`Executing callback for command: ${cmd.name}, kwargs: ${JSON.stringify(kwargs)}, argv: ${argv}`);
return returnFunction? () => cmd.callback(msg, kwargs, argv) : cmd.callback(msg, kwargs, argv);
}
/**
* Parses the message by calling the assigned function for the command with arguments
* @param msg
*/
function parseGlobalCommand(msg) {
let content = msg.content;
let commands = content.split(';').map(x => x.replace(/^ +/, ''));
if (commands.length === 1) {
let command = (content.match(/^.\w+/) || [])[0];
if (!command || !globCommands[command])
return false;
let cmd = globCommands[command];
if (!checkPermission(msg, cmd.role))
return false;
logger.debug(`Permission <${cmd.role}> granted for command ${command} for user <${msg.author.tag}>`);
return processCommand(cmd, msg, content);
} else {
let answers = [];
for (let commandPart of commands) {
let command = (commandPart.match(/^.\w+/) || [])[0];
if (command && globCommands[command]) {
let cmd = globCommands[command];
if (checkPermission(msg, cmd.role)) {
logger.debug(`Permission <${cmd.role}> granted for command ${command} for user <${msg.author.tag}>`);
answers.push(processCommand(cmd, msg, commandPart,
true)); // return an function to avoid "race conditions"
}
}
}
return answers;
}
}
/**

@ -6,6 +6,7 @@ const cmd = require('./cmd'),
fs = require('fs-extra'),
servercmd = require('../commands/servercommands'),
Discord = require('discord.js'),
waterfall = require('promise-waterfall'),
dataDir = config.dataPath || './data';
let logger = require('winston');
@ -72,19 +73,23 @@ exports.GuildHandler = class {
* @param msg
* @param answer
*/
answerMessage(msg, answer) {
async answerMessage(msg, answer) {
if (answer instanceof Promise || answer)
if (answer instanceof Discord.RichEmbed) {
(this.mention) ? msg.reply('', answer) : msg.channel.send('', answer);
} else if (answer instanceof Promise) {
answer
.then((resolvedAnswer) => this.answerMessage(msg, resolvedAnswer))
.catch((error) => this.answerMessage(msg, error));
let resolvedAnswer = await answer;
await this.answerMessage(msg, resolvedAnswer);
} else if (answer instanceof Array) {
let answerPromises = [];
for (let answerPart of answer)
answerPromises.push(async () => await this.answerMessage(msg, answerPart));
await waterfall(answerPromises);
} else if ({}.toString.call(answer) === '[object Function]') { // check if the answer is of type function
await this.answerMessage(msg, answer());
} else {
(this.mention) ? msg.reply(answer) : msg.channel.send(answer);
}
else
logger.debug(`Empty answer won't be send.`);
}
/**
@ -98,8 +103,7 @@ exports.GuildHandler = class {
'INSERT INTO messages (author, creation_timestamp, author_name, content) values (?, ?, ?, ?)',
[msg.author.id, msg.createdTimestamp, msg.author.username, msg.content]
);
this.answerMessage(msg, this.servant.parseCommand(msg));
await this.answerMessage(msg, this.servant.parseCommand(msg));
}
/**
@ -111,9 +115,9 @@ exports.GuildHandler = class {
async connectAndPlay(vc, url, next) {
if (!this.dj.connected) {
await this.dj.connect(vc);
this.dj.playYouTube(url, next);
await this.dj.playYouTube(url, next);
} else {
this.dj.playYouTube(url, next);
await this.dj.playYouTube(url, next);
}
}

@ -34,10 +34,15 @@ exports.DJ = class {
* VoiceChannel is saved as object variable.
*/
async connect(voiceChannel) {
this.voiceChannel = voiceChannel || this.voiceChannel;
if (this.connected)
this.stop();
if (voiceChannel && this.voiceChannel !== voiceChannel) {
this.voiceChannel = voiceChannel;
this.stop();
} else {
return;
}
else
this.voiceChannel = voiceChannel;
logger.verbose(`Connecting to voiceChannel ${this.voiceChannel.name}`);
let connection = await this.voiceChannel.join();
logger.info(`Connected to Voicechannel ${this.voiceChannel.name}`);
@ -72,8 +77,10 @@ exports.DJ = class {
* @param voiceChannel
*/
updateChannel(voiceChannel) {
this.voiceChannel = voiceChannel;
logger.debug(`Updated voiceChannel to ${this.voiceChannel.name}`);
if (voiceChannel) {
this.voiceChannel = voiceChannel;
logger.debug(`Updated voiceChannel to ${this.voiceChannel.name}`);
}
}
/**
@ -258,7 +265,6 @@ exports.DJ = class {
logger.debug("Ended dispatcher");
}
if (this.conn) {
this.conn.channel.leave();
this.conn.disconnect();
this.conn = null;
logger.debug("Ended connection");

@ -25,6 +25,7 @@
"js-sha512": "0.8.0",
"node-sass": "4.11.0",
"opusscript": "0.0.6",
"promise-waterfall": "^0.1.0",
"pug": "2.0.3",
"sqlite3": "4.0.6",
"winston": "3.2.1",

@ -71,7 +71,7 @@ head
span#dj-queueCount
| Songs in Queue
span.cell
| Next
| Next
span#dj-queueDisplayCount 0
| Songs:
#dj-songQueue

Loading…
Cancel
Save