Skip to content

Instantly share code, notes, and snippets.

@Ratismal
Last active June 30, 2019 15:45
Show Gist options
  • Save Ratismal/a99262408922ba2ca2e9ffb367bc80c5 to your computer and use it in GitHub Desktop.
Save Ratismal/a99262408922ba2ca2e9ffb367bc80c5 to your computer and use it in GitHub Desktop.
A simple method to handle awaiting messages
/*
* The premise of a message-awaiter is simple. You need the following:
* 1. An object to store messages
* 2. A function to populate the object
* 3. A hook to check this object
*
* DISCLAIMER: This gist is untested and should only be looked at for learning purposes.
* Please do not directly copy/paste it into your production environment.
*/
/**
* A container to put await information into. Will have the folloing data structure:
* {
* channelId: {
* userId: {
* resolve: Function(),
* reject: Function(),
* callback: Function()
* }
* }
* }
*/
var awaitedMessages = {};
/**
* @description This functions takes a message object, and a verification callback.
* The callback is used to verify input, rather than return a result.
* You may expand this as needed.
* @param {Message} msg The message object
* @param {Function} callback A verification callback, taking a new Message object and returning a boolean
* @param {Number} timeout Amount of time in milliseconds before rejecting the request. Defaults to 300000 (5 minutes). Set to -1 to never expire.
* @returns {Promise}
*/
function awaitMessage(msg, callback, timeout = 300000) {
return new Promise((resolve, reject) => {
/* Verify the contents of the object */
if (!awaitedMessages[msg.channel.id])
awaitedMessages[msg.channel.id] = {};
/* Create an optional timeout */
let timer;
if (timeout >= 0) {
timer = setTimeout(function() {
delete awaitedMessages[msg.channel.id][msg.author.id];
reject(new Error(`Request timed out (${timeout}ms)`));
}, timeout);
}
/* Check for an existing entry, and remove if neccesary */
if (awaitedMessages[msg.channel.id][msg.author.id]) {
awaitedMessages[msg.channel.id][msg.author.id].reject();
}
/* Create an empty entry for the user, overwriting any old one */
awaitedMessages[msg.channel.id][msg.author.id] = {
/* Resolving function */
resolve: function(msg2) {
clearTimeout(timer);
resolve(msg2);
},
/* Rejecting function */
reject: function() {
clearTimeout(timer);
reject(new Error('Request was overwritten'));
},
callback
};
});
}
/**
* Finally, we need to hook into the awaitedMessages object.
*/
bot.on('messageCreate', msg => {
/* Check if the object has the right channel-author combo */
if (awaitedMessages.hasOwnProperty(msg.channel.id)
&& awaitedMessages[msg.channel.id].hasOwnProperty(msg.author.id)) {
/* Verify input */
if (awaitedMessages[msg.channel.id][msg.author.id].callback(msg)) {
/* Resolve the promise */
awaitedMessages[msg.channel.id][msg.author.id].resolve(msg);
}
}
});
/**
* Examples
*/
/* eslint-disable no-undef */
// Return a message containing the word "meow", case insensitive
awaitMessage(msg, msg2 => msg2.content.toLowerCase().includes('meow'))
.then(msg2 => {
// Do what you want with msg2
});
// Return a message containing a number
awaitMessage(msg, msg2 => !isNaN(parseInt(msg2.content)))
.then(msg2 => {
// Do what you want with msg2
});
/* eslint-enable no-undef */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment