[core] fully migrate to InteractionPaginator

This commit is contained in:
derpystuff 2022-05-22 17:55:16 +02:00
parent b1cc10c6ef
commit eb0ba140f3
15 changed files with 176 additions and 303 deletions

View file

@ -22,11 +22,6 @@ const categories = {
"dev": `${icon("analytics")} Development` "dev": `${icon("analytics")} Development`
} }
const reactions = {
previousPage: "⬅️",
nextPage: "➡️"
};
module.exports = { module.exports = {
name: 'help', name: 'help',
label: 'command', label: 'command',
@ -58,10 +53,9 @@ module.exports = {
pages = formatPaginationEmbeds(pages) pages = formatPaginationEmbeds(pages)
const message = context.message const message = context.message
const paging = await paginator.createReactionPaginator({ const paging = await paginator.createPaginator({
message, message,
pages, pages
reactions
}); });
} }
}, },

View file

@ -1,11 +1,6 @@
const { Constants } = require('detritus-client'); const { Constants } = require('detritus-client');
const { paginator } = require('../../../../labscore/client'); const { paginator } = require('../../../../labscore/client');
const reactions = {
previousPage: "⬅️",
nextPage: "➡️"
};
const createEmbedMessage = (title, description) => ({ const createEmbedMessage = (title, description) => ({
embeds: [{ title, description }] embeds: [{ title, description }]
}); });
@ -25,13 +20,11 @@ module.exports = {
createEmbedMessage("Page2", "eee"), createEmbedMessage("Page2", "eee"),
createEmbedMessage("Page 3", "h") createEmbedMessage("Page 3", "h")
] ]
const paging = await paginator.createReactionPaginator({ const paging = await paginator.createPaginator({
// message is the message the user has sent // message is the message the user has sent
message, message,
// pages is an array of pages (will be passed as parameter in Message#edit) // pages is an array of pages (will be passed as parameter in Message#edit)
pages, pages
// reactions is an object that includes `previousPage` and `nextPage` emojis (defined above)
reactions
}); });
}, },
}; };

View file

@ -25,11 +25,6 @@ function createImageResultPage(context, result){
return res; return res;
} }
const reactions = {
previousPage: "⬅️",
nextPage: "➡️"
};
module.exports = { module.exports = {
name: 'bingimage', name: 'bingimage',
label: 'query', label: 'query',
@ -54,10 +49,9 @@ module.exports = {
pages = formatPaginationEmbeds(pages) pages = formatPaginationEmbeds(pages)
const message = context.message const message = context.message
const paging = await paginator.createReactionPaginator({ const paging = await paginator.createPaginator({
message, message,
pages, pages
reactions
}); });
}catch(e){ }catch(e){
console.log(e) console.log(e)

View file

@ -21,11 +21,6 @@ function createSearchResultPage(context, result){
return res; return res;
} }
const reactions = {
previousPage: "⬅️",
nextPage: "➡️"
};
module.exports = { module.exports = {
name: 'bing', name: 'bing',
label: 'query', label: 'query',
@ -50,10 +45,9 @@ module.exports = {
pages = formatPaginationEmbeds(pages) pages = formatPaginationEmbeds(pages)
const message = context.message const message = context.message
const paging = await paginator.createReactionPaginator({ const paging = await paginator.createPaginator({
message, message,
pages, pages
reactions
}); });
}catch(e){ }catch(e){
console.log(e) console.log(e)

View file

@ -25,11 +25,6 @@ function createImageResultPage(context, result){
return res; return res;
} }
const reactions = {
previousPage: "⬅️",
nextPage: "➡️"
};
module.exports = { module.exports = {
name: 'image', name: 'image',
label: 'query', label: 'query',
@ -54,10 +49,9 @@ module.exports = {
pages = formatPaginationEmbeds(pages) pages = formatPaginationEmbeds(pages)
const message = context.message const message = context.message
const paging = await paginator.createReactionPaginator({ const paging = await paginator.createPaginator({
message, message,
pages, pages
reactions
}); });
}catch(e){ }catch(e){
console.log(e) console.log(e)

View file

@ -22,11 +22,6 @@ function createSearchResultPage(context, result){
return res; return res;
} }
const reactions = {
previousPage: "⬅️",
nextPage: "➡️"
};
module.exports = { module.exports = {
name: 'google', name: 'google',
label: 'query', label: 'query',
@ -51,10 +46,9 @@ module.exports = {
pages = formatPaginationEmbeds(pages) pages = formatPaginationEmbeds(pages)
const message = context.message const message = context.message
const paging = await paginator.createReactionPaginator({ const paging = await paginator.createPaginator({
message, message,
pages, pages
reactions
}); });
}catch(e){ }catch(e){
console.log(e) console.log(e)

View file

@ -5,11 +5,6 @@ const { STATICS } = require('../../../labscore/utils/statics')
const { lyrics } = require('../../../labscore/api'); const { lyrics } = require('../../../labscore/api');
const { paginator } = require('../../../labscore/client'); const { paginator } = require('../../../labscore/client');
const reactions = {
previousPage: "⬅️",
nextPage: "➡️"
};
function createLyricsPage(context, search, fields){ function createLyricsPage(context, search, fields){
let em= createEmbed("default", context, { let em= createEmbed("default", context, {
description: `**${search.body.song.title}**\n*Released ${search.body.song.release}*\n\n`, description: `**${search.body.song.title}**\n*Released ${search.body.song.release}*\n\n`,
@ -70,10 +65,9 @@ module.exports = {
const message = context.message const message = context.message
pages = formatPaginationEmbeds(pages) pages = formatPaginationEmbeds(pages)
const paging = await paginator.createReactionPaginator({ const paging = await paginator.createPaginator({
message, message,
pages, pages
reactions
}); });
return; return;
} }

View file

@ -23,11 +23,6 @@ function createWolframPage(context, pod){
return res; return res;
} }
const reactions = {
previousPage: "⬅️",
nextPage: "➡️"
};
module.exports = { module.exports = {
name: 'wolframalpha', name: 'wolframalpha',
label: 'query', label: 'query',
@ -52,10 +47,9 @@ module.exports = {
pages = formatPaginationEmbeds(pages) pages = formatPaginationEmbeds(pages)
const message = context.message const message = context.message
const paging = await paginator.createReactionPaginator({ const paging = await paginator.createPaginator({
message, message,
pages, pages
reactions
}); });
}catch(e){ }catch(e){
console.log(e) console.log(e)

View file

@ -21,7 +21,7 @@ const cluster = new ClusterClient("", {
// Create this clusters paginator // Create this clusters paginator
const paginator = new Paginator(cluster, { const paginator = new Paginator(cluster, {
maxTime: 120000, maxTime: 300000,
pageLoop: true, pageLoop: true,
pageNumber: true pageNumber: true
}); });

View file

@ -11,9 +11,7 @@ module.exports = class BasePaginator extends EventEmitter {
this.index = 0; this.index = 0;
this.targetUser = data.targetUser || this.message.author.id; this.targetUser = data.targetUser || this.message.author.id;
// Reference to reply function // TODO: use editOrReply, kill old paginator if it exists
// Uses context.editOrReply if an instance of Context was passed
// Defaults to message.reply
this.editOrReply = (data.message.editOrReply || data.message.reply).bind(data.message); this.editOrReply = (data.message.editOrReply || data.message.reply).bind(data.message);
} }

View file

@ -0,0 +1,8 @@
const BasePaginator = require("./BasePaginator");
module.exports = class InteractionPaginator extends BasePaginator {
constructor(client, data) {
super(client, data);
this.waitingForPage = null;
}
};

View file

@ -1,4 +1,4 @@
const ReactionPaginator = require("./ReactionPaginator"); const InteractionPaginator = require("./InteractionPaginator");
const assert = require("assert"); const assert = require("assert");
const { Constants, Utils } = require('detritus-client') const { Constants, Utils } = require('detritus-client')
@ -6,18 +6,19 @@ const { Components, ComponentActionRow } = Utils
const { InteractionCallbackTypes } = Constants const { InteractionCallbackTypes } = Constants
const allowedEvents = new Set([ const allowedEvents = new Set([
"MESSAGE_REACTION_ADD", "MESSAGE_CREATE"
"MESSAGE_CREATE"
]); ]);
function deprecate(message) { function deprecate(message) {
console.warn(`[detritus-pagination] Deprecation warning: ${message}`); console.warn(`[detritus-pagination] Deprecation warning: ${message}`);
} }
const ButtonEmoji = Object.freeze({ const ButtonEmoji = Object.freeze({
NEXT: '<:right:977871577758707782>', NEXT: '<:right:977871577758707782>',
PREVIOUS: '<:left:977871577532211200>', PREVIOUS: '<:left:977871577532211200>',
STOP: '<:ico_trash:929498022386221096>' STOP: '<:ico_trash:929498022386221096>',
// NEXT: '<:next_page:977894273376727050>',
// PREVIOUS: '<:previous_page:977894273443844167>'
}) })
const { hasOwnProperty } = Object.prototype; const { hasOwnProperty } = Object.prototype;
@ -27,179 +28,143 @@ const { hasOwnProperty } = Object.prototype;
const instances = new WeakSet(); const instances = new WeakSet();
module.exports = class Paginator { module.exports = class Paginator {
constructor(client, data = {}) { constructor(client, data = {}) {
if (instances.has(client)) { if (instances.has(client)) {
deprecate("Avoid attaching multiple Paginators to the same client, as it can lead to memory leaks"); deprecate("Avoid attaching multiple Paginators to the same client, as it can lead to memory leaks");
} else { } else {
instances.add(client); instances.add(client);
}
assert.ok(
hasOwnProperty.call(client, "gateway"),
"Provided `client` has no `gateway` property. Consider using `require('detritus-pagination').PaginatorCluster` if you're using CommandClient."
);
this.client = client;
this.maxTime = data.maxTime || 300000;
this.pageLoop = typeof data.pageLoop !== "boolean" ? false : data.pageLoop;
this.pageNumber = typeof data.pageNumber !== "boolean" ? false : data.pageNumber;
this.activeListeners = [];
this.client.gateway.on("packet", async packet => {
const {
d: data,
t: event
} = packet;
if (!data) return;
if (!allowedEvents.has(event)) return;
for (const listener of this.activeListeners) {
if (!(listener instanceof ReactionPaginator)) continue;
if (!listener.commandMessage) continue;
if (listener.isCommandMessage(data.message_id) &&
listener.isTarget(data.user_id)) {
await this.handleReactionEvent(data, listener);
} else if (event === "MESSAGE_CREATE" &&
listener.isInChannel(data.channel_id) &&
listener.isTarget(data.user_id) &&
listener.waitingForPage) {
await this.handleMessageEvent(data, listener);
}
}
});
} }
async handleButtonEvent(context) { assert.ok(
// Get listener hasOwnProperty.call(client, "gateway"),
let listener; "Provided `client` has no `gateway` property. Consider using `require('detritus-pagination').PaginatorCluster` if you're using CommandClient."
for (const l of this.activeListeners) { );
if (!(l instanceof ReactionPaginator)) continue;
if (!l.commandMessage) continue;
if (l.isCommandMessage(context.message.id)) { this.client = client;
listener = l this.maxTime = data.maxTime || 300000;
} this.pageLoop = typeof data.pageLoop !== "boolean" ? false : data.pageLoop;
} this.pageNumber = typeof data.pageNumber !== "boolean" ? false : data.pageNumber;
this.activeListeners = [];
if(!listener.isTarget(context.user.id)) { this.client.gateway.on("packet", async packet => {
await context.respond(InteractionCallbackTypes.DEFERRED_UPDATE_MESSAGE) const {
return; d: data,
} t: event
} = packet;
if (!data) return;
if (!allowedEvents.has(event)) return;
switch (context.customId) { for (const listener of this.activeListeners) {
case "next": if (!(listener instanceof InteractionPaginator)) continue;
//await context.respond(InteractionCallbackTypes.DEFERRED_UPDATE_MESSAGE) if (!listener.commandMessage) continue;
//listener.next();
await context.respond(InteractionCallbackTypes.UPDATE_MESSAGE, await listener.getNext()) if (event === "MESSAGE_CREATE" &&
break; listener.isInChannel(data.channel_id) &&
case "previous": listener.isTarget(data.user_id) &&
await context.respond(InteractionCallbackTypes.UPDATE_MESSAGE, await listener.getPrevious()) listener.waitingForPage) {
break; await this.handleMessageEvent(data, listener);
case "stop":
await context.respond(InteractionCallbackTypes.DEFERRED_UPDATE_MESSAGE)
listener.stop();
break;
} }
}
});
}
async handleButtonEvent(context) {
// Get listener
let listener;
for (const l of this.activeListeners) {
if (!(l instanceof InteractionPaginator)) continue;
if (!l.commandMessage) continue;
if (l.isCommandMessage(context.message.id)) {
listener = l
}
} }
// TODO: Clean up legacy code from ReactionPaginator if (!listener.isTarget(context.user.id)) {
await context.respond(InteractionCallbackTypes.DEFERRED_UPDATE_MESSAGE)
// Legacy return;
async handleReactionEvent(data, listener) {
switch (data.emoji.name) {
case listener.reactions.nextPage:
listener.next();
break;
case listener.reactions.previousPage:
listener.previous();
break;
case listener.reactions.firstPage:
listener.jumpTo(0);
break;
case listener.reactions.lastPage:
listener.jumpTo(listener.pages.length - 1);
break;
case listener.reactions.stop:
listener.stop();
break;
case listener.reactions.skipTo:
if (listener.waitingForPage) return;
listener.waitingForPage = await this.client.rest.createMessage(data.channel_id, "What page do you want to go to?");
break;
default:
if (!Object.values(listener.reactions).includes(data.emoji.name)) return;
}
listener.emit("raw", data);
listener.clearReaction(data.emoji.name);
} }
async handleMessageEvent(data, listener) { switch (context.customId) {
const page = parseInt(data.content, 10); case "next":
if (isNaN(page)) { //await context.respond(InteractionCallbackTypes.DEFERRED_UPDATE_MESSAGE)
return; //listener.next();
} await context.respond(InteractionCallbackTypes.UPDATE_MESSAGE, await listener.getNext())
break;
case "previous":
await context.respond(InteractionCallbackTypes.UPDATE_MESSAGE, await listener.getPrevious())
break;
case "stop":
await context.respond(InteractionCallbackTypes.DEFERRED_UPDATE_MESSAGE)
listener.stop();
break;
}
}
listener.jumpTo(page - 1) async handleMessageEvent(data, listener) {
.then(async () => { const page = parseInt(data.content, 10);
try { if (isNaN(page)) {
await listener.waitingForPage.delete(); return;
await this.client.rest.deleteMessage(data.channel_id, data.id);
} catch (e) { }
listener.waitingForPage = null;
}).catch(() => { });
} }
async components(listener) { listener.jumpTo(page - 1)
const components = new Components({ .then(async () => {
timeout: this.expires, try {
run: this.handleButtonEvent.bind(this), await listener.waitingForPage.delete();
}); await this.client.rest.deleteMessage(data.channel_id, data.id);
} catch (e) { }
components.createButton({ listener.waitingForPage = null;
customId: "previous", }).catch(() => { });
disabled: 0, }
style: 2,
emoji: ButtonEmoji.PREVIOUS
});
components.createButton({
customId: "next",
disabled: 0,
style: 2,
emoji: ButtonEmoji.NEXT
});
//components.createButton({ async components(listener) {
// customId: "stop", const components = new Components({
// disabled: 0, timeout: this.expires,
// style: 2, run: this.handleButtonEvent.bind(this),
// emoji: ButtonEmoji.STOP });
//});
return components; components.createButton({
customId: "previous",
disabled: 0,
style: 2,
emoji: ButtonEmoji.PREVIOUS
});
components.createButton({
customId: "next",
disabled: 0,
style: 2,
emoji: ButtonEmoji.NEXT
});
//components.createButton({
// customId: "stop",
// disabled: 0,
// style: 2,
// emoji: ButtonEmoji.STOP
//});
return components;
}
async createPaginator(data) {
if (this.pageNumber && Array.isArray(data.pages)) {
for (let i = 0; i < data.pages.length; ++i) {
const element = data.pages[i];
}
} }
async createReactionPaginator(data) { const instance = new InteractionPaginator(this, data);
if (this.pageNumber && Array.isArray(data.pages)) { this.activeListeners.push(instance);
for (let i = 0; i < data.pages.length; ++i) {
const element = data.pages[i];
} setTimeout(() => {
} instance.stop(true);
}, data.maxTime || this.maxTime);
const instance = new ReactionPaginator(this, data); if (instance.commandMessage === null && data.pages) {
this.activeListeners.push(instance); await instance.init();
setTimeout(() => {
instance.stop(true);
}, data.maxTime || this.maxTime);
if (instance.commandMessage === null && data.pages) {
await instance.init();
}
//await instance.addReactions();
return instance;
} }
return instance;
}
}; };

View file

@ -3,35 +3,35 @@ const Paginator = require("./Paginator");
const assert = require("assert"); const assert = require("assert");
module.exports = class PaginatorCluster { module.exports = class PaginatorCluster {
constructor(clusterClient, data = {}) { constructor(clusterClient, data = {}) {
assert.ok( assert.ok(
clusterClient instanceof ClusterClient, clusterClient instanceof ClusterClient,
"clusterClient must be an instance of ClusterClient" "clusterClient must be an instance of ClusterClient"
); );
const paginators = new WeakMap(); const paginators = new WeakMap();
for (const [, client] of clusterClient.shards) { for (const [, client] of clusterClient.shards) {
paginators.set(client, new Paginator(client, data)); paginators.set(client, new Paginator(client, data));
}
this.data = data;
this.paginators = paginators;
} }
findOrSetPaginator(client) { this.data = data;
const cachedPaginator = this.paginators.get(client); this.paginators = paginators;
if (cachedPaginator) return cachedPaginator; }
const paginator = new Paginator(client, this.data); findOrSetPaginator(client) {
this.paginators.set(client, paginator); const cachedPaginator = this.paginators.get(client);
if (cachedPaginator) return cachedPaginator;
return paginator; const paginator = new Paginator(client, this.data);
} this.paginators.set(client, paginator);
createReactionPaginator(data) { return paginator;
const targetPaginator = this.findOrSetPaginator(data.message.client); }
return targetPaginator.createReactionPaginator(data); createPaginator(data) {
} const targetPaginator = this.findOrSetPaginator(data.message.client);
return targetPaginator.createPaginator(data);
}
} }

View file

@ -1,48 +0,0 @@
const BasePaginator = require("./BasePaginator");
module.exports = class ReactionPaginator extends BasePaginator {
constructor(client, data) {
super(client, data);
this.waitingForPage = null;
this.reactions = data.reactions || {
firstPage: "⏮️",
previousPage: "⬅️",
nextPage: "➡️",
lastPage: "⏭️",
skipTo: "🔢",
stop: "⏹️"
};
}
async addReactions() {
if (!this.commandMessage) return;
for (const reactions of Object.values(this.reactions)) {
if (this.isShared) {
for (const msg of this.commandMessage.values()) {
await msg.react(reactions).catch();
}
} else {
await this.commandMessage.react(reactions).catch(() => {});
}
}
}
// TODO: this only works if cache is enabled
// perhaps add option to use REST API to fetch all reactions?
async clearReactions() {
const reactions = this.isShared ? Array.from(this.commandMessage.values()).map(x => Array.from(x.reactions.values())).flat() : this.commandMessage.reactions.values();
for (const reaction of reactions) {
this.clearReaction(reaction.emoji.name);
}
}
async clearReaction(emoji) {
const reaction = this.commandMessage.reactions.find(x => x.emoji.name === emoji);
if (reaction) {
reaction.delete(this.message.author.id).catch(() => {});
}
}
};

View file

@ -9,7 +9,6 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"detritus-client": "^0.17.0-beta.12", "detritus-client": "^0.17.0-beta.12",
"detritus-pagination": "^1.4.0",
"dotenv": "^16.0.1", "dotenv": "^16.0.1",
"express": "^4.17.1", "express": "^4.17.1",
"superagent": "^7.1.1" "superagent": "^7.1.1"