Skip to content

Instantly share code, notes, and snippets.

@PurpShell
Forked from Iucasmaia/maia.js
Last active August 9, 2023 23:08
Show Gist options
  • Save PurpShell/39034f965112ea4ac2da5960ab05c4cd to your computer and use it in GitHub Desktop.
Save PurpShell/39034f965112ea4ac2da5960ab05c4cd to your computer and use it in GitHub Desktop.
Message Collector for Baileys v4 and above
const { WAProto } = require('@whiskeysockets/baileys');
// Message Collectors / Wait for Message
class MessageCollection {
// Internal object to temporarily store msgs
#msgs = {};
// Is the socket event handler binded?
isBinded = false;
socket = null;
constructor(socket) {
this.socket = socket;
this.bind();
}
/** Ran by default */
bind() {
if (!this.isBinded) this.isBinded = true;
const listener = this.socket?.ev?.listeners("messages.upsert").find(a => a === this.#handleMessage);
if (listener) {
throw new Error('Multiple MessageCollection instances for one socket shouldn\'t be made. Instead only make one instance and then use its functions.');
}
this.socket.ev.on("messages.upsert", this.#handleMessage);
}
/** Unbind the socket */
unbind() {
this.socket.ev.off("messages.upsert", this.#handleMessage);
}
/**
* Function to cancel all concurrent jobs
*/
cancelAll() {
for (const job in this.#msgs) {
clearTimeout(this.#msgs[job].timeout);
this.#msgs[job].reject(new Error("Job canceled"));
this.#msgs[job].resolve(this.#msgs[job].msgs);
delete this.#msgs[job];
}
}
/** A function to wait for messages
* @param {Object} options - Wait for message options
* @param {?number} options.timeout - Timeout in milliseconds, defaults to 30 seconds
* @param {?string} options.jid - Only wait for messages from this ID
* @param {?number} options.maxMsgs - Maximum number of messages to collect (defaults to 1)
* @param {?(msg: WAProto.IWebMessageInfo) => true | false} options.filterFunction Filter results gathered, will only run on results after the other options.
* @returns {Array<WAProto.IWebMessageInfo>} Array of messages collected
*/
async waitForMessages(options) {
// Bind the event listener
if (this.isBinded == false) this.bind();
// Assigning default options
const { timeout = 30 * 1000, jid = '', maxMsgs = 1, filterFunction = () => true } = options;
return new Promise((resolve, reject) => {
// Id for the object entry ({0: {timeout, ....}})
const identifier = Object.keys(this.#msgs).length;
const cancel = () => {
delete this.#msgs[identifier];
}
// Adding a job
this.#msgs[identifier] = {
timeout: setTimeout(() => {
if (this.#msgs[identifier]?.msgs?.length < 1) {
resolve([]);
} else {
resolve(this.#msgs[identifier]?.msgs);
}
cancel();
}, timeout),
msgs: [],
filterFunction: (message) => {
if (maxMsgs > 1) {
if (maxMsgs >= this.#msgs[identifier]?.msgs?.length) {
resolve(this.#msgs[identifier].msgs);
clearTimeout(this.#msgs[identifier].timeout);
cancel();
}
if (jid.length > 0) {
if (jid == message.key.remoteJid) {
if (filterFunction() === true) {
// No function was provided
this.#msgs[identifier].msgs.push(message);
} else {
const result = filterFunction(message);
if (result === true) {
this.#msgs[identifier].msgs.push(message);
}
}
}
}
}
},
resolve,
reject
};
});
}
// Internal event handler
#handleMessage(event) {
if (event?.type == 'notify') {
// Message
const message = event.messages[0];
// Unbind the event listener when there are no active jobs
if (Object.keys(this.#msgs).length === 0) this.unbind();
for (const job in this.#msgs) {
const { filterFunction } = this.#msgs[job];
filterFunction(message);
}
}
}
}
// Exporting the module
export default MessageCollection;
// good old JS support
module.exports = MessageCollection;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment