curate/src/messageawaiter.js
2020-08-10 23:08:26 -05:00

154 lines
No EOL
5.5 KiB
JavaScript

const Halt = require('./structures/Halt');
const ReactionCollector = require('./structures/ReactionCollector');
/**
* Handles async message functions
*/
class MessageAwaiter {
constructor(client) {
this.client = client;
this.halts = new Map();
this.reactionCollectors = new Map();
}
/**
* Creates a halt. This pauses any events in the event handler for a specific channel and user.
* This allows any async functions to handle any follow-up messages.
* @param {string} channelID The channel's ID
* @param {string} userID The user's ID
* @param {number} [timeout=30000] The time until the halt is auto-cleared
*/
createHalt(channelID, userID, timeout = 30000) {
const id = `${channelID}:${userID}`;
if (this.halts.has(id)) this.halts.get(id).end();
const halt = new Halt(this, timeout);
halt.once('end', () => this.halts.delete(id));
this.halts.set(id, halt);
return halt;
}
/**
* Creates a reaction collector. Any reactions from the user will be emitted from the collector.
* @param {string} message The message to collect from
* @param {string} userID The user's ID
* @param {number} [timeout=30000] The time until the halt is auto-cleared
*/
createReactionCollector(message, userID, timeout = 30000) {
const id = `${message.id}:${userID}`;
if (this.reactionCollectors.has(id)) this.reactionCollectors.get(id).end();
const collector = new ReactionCollector(this, timeout);
collector.once('end', () => this.reactionCollectors.delete(id));
this.reactionCollectors.set(id, collector);
return collector;
}
/**
* Gets an ongoing halt based on a message
* @param {Message} message
*/
getHalt(message) {
const id = `${message.channel.id}:${message.author.id}`;
return this.halts.get(id);
}
/**
* Processes a halt based on a message
* @param {Message} message
*/
processHalt(message) {
const id = `${message.channel.id}:${message.author.id}`;
if (this.halts.has(id)) {
const halt = this.halts.get(id);
halt._onMessage(message);
return true;
}
return false;
}
/**
* Awaits the next message from a user
* @param {Message} message The message to wait for
* @param {Object} [options] The options for the await
* @param {number} [options.filter] The message filter
* @param {number} [options.timeout=30000] The timeout for the halt
* @returns {?Message}
*/
awaitMessage(message, { filter = () => true, timeout = 30000 } = {}) {
return new Promise(resolve => {
const halt = this.createHalt(message.channel.id, message.author.id, timeout);
let foundMessage = null;
halt.on('message', nextMessage => {
if (filter(nextMessage)) {
foundMessage = nextMessage;
halt.end();
}
});
halt.on('end', () => resolve(foundMessage));
});
}
/**
* Same as {@see #awaitMessage}, but is used for getting user input via next message
* @param {Message} message The message to wait for
* @param {Object} [options] The options for the await
* @param {number} [options.filter] The message filter
* @param {number} [options.timeout=30000] The timeout for the halt
* @param {string} [options.header] The content to put in the bot message
* @returns {?Message}
*/
async getInput(message, { filter = () => true, timeout = 30000, header = null } = {}) {
await message.channel.createMessage(`<@${message.author.id}>, ` +
(header || 'Type the message you want to input.') + '\n\n' +
`Typing "<@!${this.client.user.id}> cancel" will cancel the input.`);
return new Promise(resolve => {
const halt = this.createHalt(message.channel.id, message.author.id, timeout);
let handled = false, input = null;
halt.on('message', nextMessage => {
if (filter(nextMessage)) {
const cancelRegex = new RegExp(`^(?:<@!?${this.client.user.id}>\\s?)(cancel|stop|end)$`);
if (!nextMessage.content || cancelRegex.test(nextMessage.content.toLowerCase())) {
handled = true;
message.channel.createMessage(`<@${message.author.id}>, Your last input was canceled.`);
} else input = nextMessage.content;
halt.end();
}
});
halt.on('end', async () => {
if (!input && !handled)
await message.channel.createMessage(`<@${message.author.id}>, Your last input was canceled.`);
resolve(input);
});
});
}
/**
* Same as {@see #awaitMessage}, but is used for confirmation
* @param {Message} message The message to wait for
* @param {Object} [options] The options for the await
* @param {number} [options.timeout=30000] The timeout for the halt
* @param {string} [options.header] The content to put in the bot message
* @returns {?Message}
*/
async confirm(message, { timeout = 30000, header = null } = {}) {
await message.channel.createMessage(`<@${message.author.id}>, ` +
(header || 'Are you sure you want to do this?') + '\n\n' +
'Type `yes` to confirm. Any other message will cancel the confirmation.');
return new Promise(resolve => {
const halt = this.createHalt(message.channel.id, message.author.id, timeout);
let input = false;
halt.on('message', nextMessage => {
input = nextMessage.content === 'yes';
halt.end();
});
halt.on('end', async () => {
if (!input)
await message.channel.createMessage(`<@${message.author.id}>, Confirmation canceled.`);
resolve(input);
});
});
}
}
MessageAwaiter.Halt = Halt;
module.exports = MessageAwaiter;