Skip to content

Commit

Permalink
feat: use threads (#552)
Browse files Browse the repository at this point in the history
  • Loading branch information
TobiTenno authored Sep 25, 2022
1 parent a473bba commit efee0fd
Show file tree
Hide file tree
Showing 22 changed files with 312 additions and 139 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:
SSH_USER: ${{ secrets.SSH_USER }}
SSH_KEY: ${{ secrets.SSH_KEY }}
SSH_BOT_HOST: ${{ secrets.SSH_BOT_HOST }}
SSH_WORKER_HOST: ${{ secrets.SSH_WORKER_HOST }}
SSH_BOT_PORT: ${{ secrets.SSH_BOT_PORT }}
DEPLOY_BRANCH: ${{ secrets.DEPLOY_BRANCH }}
- name: Stop Bot Process
if: ${{ steps.release.outputs.release == 'yes' }}
Expand Down
8 changes: 8 additions & 0 deletions jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"types": ["discord.js", "node"]
},
"exclude": ["node_modules"]
}
8 changes: 6 additions & 2 deletions src/embeds/FissureEmbed.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import BaseEmbed from './BaseEmbed.js';

import { assetBase, wikiBase } from '../utilities/CommonFunctions.js';
import { wikiBase, cdn } from '../utilities/CommonFunctions.js';
import { rTime } from '../utilities/Wrappers.js';

const fissureThumb = `${assetBase}${assetBase.endsWith('/') ? '' : '/'}img/fissure-sm.png`;
const fissureThumb = cdn('img/fissure-sm.png');
const steelPath = cdn('img/steelpath-h.png');

/**
* Generates fissure embeds
Expand Down Expand Up @@ -47,6 +48,9 @@ export default class FissureEmbed extends BaseEmbed {
this.footer.text = i18n`Expires `;
this.timestamp = new Date(f.expiry).getTime();
this.thumbnail.url = fissureThumb;
if (f.isHard) {
this.setImage(steelPath);
}
}

this.color = 0x4aa1b2;
Expand Down
4 changes: 2 additions & 2 deletions src/interactions/channels/Templates.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Discord from 'discord.js';
import Discord, { Permissions } from 'discord.js';
import BaseEmbed from '../../embeds/BaseEmbed.js';
import { games } from '../../utilities/CommonFunctions.js';
import Interaction from '../../models/Interaction.js';
Expand All @@ -15,10 +15,10 @@ const tc = {
};

export default class Templates extends Interaction {
static elevated = true;
static enabled = games.includes('ROOMS');
static command = {
...cmds.templates,
defaultMemberPermissions: Permissions.FLAGS.MANAGE_GUILD,
options: [
{
...cmds['templates.add'],
Expand Down
16 changes: 11 additions & 5 deletions src/interactions/core/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -355,11 +355,10 @@ export default class Settings extends Interaction {
.filter((id) => id)
.map((id) => guild.roles.cache.get(id.trim()));

static elevated = true;
static enabled = true;
static command = {
...cmds.settings,
// defaultPermission: false,
defaultMemberPermissions: Permissions.FLAGS.MANAGE_GUILD,
options: [
{
...cmds['settings.set'],
Expand Down Expand Up @@ -511,9 +510,13 @@ export default class Settings extends Interaction {
} Manage Webhooks`,
];

const isThread = interaction.channel.isThread();
const channel = isThread ? interaction.channel.parent : interaction.channel;
const thread = isThread ? interaction.channel : undefined;

const trackables = {
events: await ctx.settings.getTrackedEventTypes(interaction.channel),
items: await ctx.settings.getTrackedItems(interaction.channel),
events: await ctx.settings.getTrackedEventTypes(channel, thread),
items: await ctx.settings.getTrackedItems(channel, thread),
};
trackingReadinessTokens.push(
trackables.events.length
Expand All @@ -529,7 +532,10 @@ export default class Settings extends Interaction {
embed.addField('Trackable Ready', trackingReadinessTokens.join('\n'));

// General
embed.addField('General Ids', `Guild: \`${interaction.guild.id}\`\nChannel: \`${interaction.channel.id}\``);
embed.addField(
'General Ids',
`Guild: \`${interaction.guild.id}\`\nChannel: \`${channel.id}\`${thread ? `\nThread: \`${thread.id}\`` : ''}`
);

embed.setTimestamp(new Date());
embed.setFooter({ text: `Uptime: ${timeDeltaToString(interaction.client.uptime)}` });
Expand Down
4 changes: 2 additions & 2 deletions src/interactions/core/su.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Discord from 'discord.js';
import Discord, { Permissions } from 'discord.js';
import InteractionHandler from '../../eventHandlers/InteractionHandler.js';
import logger from '../../utilities/Logger.js';
import ServerInfoEmbed from '../../embeds/ServerInfoEmbed.js';
Expand All @@ -16,8 +16,8 @@ export default class Settings extends Interaction {
static command = {
name: 'su',
description: 'Super User',
defaultPermission: false,
ownerOnly: true,
defaultMemberPermissions: Permissions.FLAGS.ADMINISTRATOR,
options: [
{
name: 'restart',
Expand Down
5 changes: 3 additions & 2 deletions src/interactions/custom/CustomCommands.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Discord from 'discord.js';
import Discord, { Permissions } from 'discord.js';
import { createGroupedArray } from '../../utilities/CommonFunctions.js';
import Collectors from '../../utilities/Collectors.js';
import Interaction from '../../models/Interaction.js';
Expand All @@ -12,9 +12,10 @@ const nameReg = /^[\w-]{1,32}$/u;

export default class CustomCommands extends Interaction {
static enabled = true;
static elevated = true;

static command = {
...cmds.cc,
defaultMemberPermissions: Permissions.FLAGS.MANAGE_GUILD,
options: [
{
...cmds['cc.add'],
Expand Down
103 changes: 83 additions & 20 deletions src/interactions/tracking/Tracking.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Discord, { MessageButton } from 'discord.js';
import Discord, { MessageButton, Permissions } from 'discord.js';
import Interaction from '../../models/Interaction.js';
import {
chunkify,
Expand Down Expand Up @@ -26,20 +26,29 @@ const chunkerate = (track) => {
const itemString = !track.items.length ? 'None' : track.items.map((i) => `\`${i}\``).join(', ');
const eventString = !track.events.length ? 'None' : track.events.map((m) => `\`${m}\``).join(', ');
const format = `**Current Items:**\n${itemString}\n\n**Current Events:**\n${eventString}`;
return chunkify({ string: format, maxLength: 2000, breakChar: ',' });
return chunkify({ string: format, maxLength: 500, breakChar: ',' });
};

const subgrouped = ['arbitration', 'fissures', 'twitter'];

export default class Settings extends Interaction {
static elevated = true;
static command = {
...cmds.tracking,
// defaultPermission: false,
defaultMemberPermissions: Permissions.FLAGS.MANAGE_GUILD,
options: [
{
...cmds['tracking.manage'],
type: Types.SUB_COMMAND,
options: [
{
...cmds['tracking.manage.channel'],
type: Types.CHANNEL,
},
{
...cmds['tracking.manage.thread'],
type: Types.CHANNEL,
},
],
},
{
...cmds['tracking.custom'],
Expand All @@ -65,6 +74,10 @@ export default class Settings extends Interaction {
...cmds['tracking.custom.clear-prepend'],
type: Types.BOOLEAN,
},
{
...cmds['tracking.custom.thread'],
type: Types.CHANNEL,
},
],
},
],
Expand All @@ -74,10 +87,42 @@ export default class Settings extends Interaction {
await interaction?.deferReply({ ephemeral: false });
const { options } = interaction;
const action = options?.getSubcommand();
let channel;
let thread;
let isThread;
if (options?.getChannel('channel')) {
if (options?.getChannel('channel').type !== 'GUILD_TEXT') {
return interaction.editReply({
ephemeral: ctx.ephemerate,
content: `:warning: ${options.getChannel('channel')} is not a text channel. :warning:`,
});
}
channel = options.getChannel('channel');
}
if (!channel) {
isThread = interaction.channel.isThread();
channel = isThread ? interaction.channel.parent : interaction.channel;
thread = isThread ? interaction.channel : undefined;
}
if (options.getChannel('thread')?.isThread?.()) {
thread = options.getChannel('thread');
if (thread.parent.id !== channel.id) {
return interaction.editReply({
ephemeral: ctx.ephemerate,
content: `:warning: ${thread} is not a thread in ${channel} :warning:`,
});
}
} else if (options.getChannel('thread')) {
return interaction.editReply({
ephemeral: ctx.ephemerate,
content: `:warning: ${options.getChannel('thread')} is not a thread channel :warning:`,
});
}
if (action === 'manage') {
const original = Object.freeze({
items: await ctx.settings.getTrackedItems(interaction.channel),
events: await ctx.settings.getTrackedEventTypes(interaction.channel),
items: await ctx.settings.getTrackedItems(channel, thread),
events: await ctx.settings.getTrackedEventTypes(channel, thread),
thread,
});
const current = { ...original };
let chunks = chunkerate(current);
Expand Down Expand Up @@ -305,9 +350,9 @@ export default class Settings extends Interaction {
await button?.deferUpdate();
switch (button?.customId) {
case 'save':
await ctx.settings.setTrackables(interaction.channel, current);
await ctx.settings.setTrackables(channel, current);
buttonCollector.stop('limit');
await this.#generateWebhook(interaction, ctx);
await this.#generateWebhook(interaction, ctx, channel);
return message.edit({
content: chunks[page],
components: [
Expand Down Expand Up @@ -391,10 +436,25 @@ export default class Settings extends Interaction {
}
if (page > chunks.length - 1) page = chunks.length - 1;
if (page < 0) page = 0;
return message.edit({
content: chunks[page],
components: createGroupsRow(),
});
if (chunks[page]) {
return message.edit({
content: chunks[page],
components: createGroupsRow(),
});
}
if (chunks[page - 1]) {
page -= 1;
} else if (chunks[page + 1]) {
page += 1;
} else if (chunks[0]) {
page = 0;
}
if (chunks[page]) {
return message.edit({
content: chunks[page],
components: createGroupsRow(),
});
}
};
buttonCollector.on('collect', buttonHandler);
}
Expand All @@ -414,8 +474,6 @@ export default class Settings extends Interaction {
);
const prepend = options.getString('prepend');
const clear = options.getBoolean('clear-prepend');
const channel =
options?.getChannel('channel')?.type === 'GUILD_TEXT' ? options.getChannel('channel') : interaction.channel;

if (clear && Object.keys(remove)?.length) {
await Promise.all(
Expand All @@ -434,11 +492,11 @@ export default class Settings extends Interaction {
ephemeral: ctx.ephemerate,
});
}
if (add?.events?.length) await ctx.settings.trackEventTypes(channel, add.events);
if (add?.items?.length) await ctx.settings.trackItems(channel, add.items);
if (add?.events?.length) await ctx.settings.trackEventTypes(channel, add.events, thread);
if (add?.items?.length) await ctx.settings.trackItems(channel, add.items, thread);
const addString = ctx.i18n`Added ${add?.events?.length || 0} events, ${add?.items?.length || 0} items`;
if (remove?.events?.length) await ctx.settings.untrackEventTypes(channel, remove.events);
if (remove?.items?.length && !clear) await ctx.settings.untrackItems(channel, remove.items);
if (remove?.events?.length) await ctx.settings.untrackEventTypes(channel, remove.events, thread);
if (remove?.items?.length && !clear) await ctx.settings.untrackItems(channel, remove.items, thread);
const removeString = ctx.i18n`Removed ${remove?.events?.length} events, ${remove?.items?.length} items`;
await interaction.editReply({ content: `${addString}\n${removeString}`, ephemeral: ctx.ephemerate });

Expand All @@ -448,6 +506,7 @@ export default class Settings extends Interaction {
Discord.Util.removeMentions(prepend)
)}\` for ${add?.events?.length || 0} events, ${add?.items?.length || 0} items`;
await interaction.editReply({
ephemeral: ctx.ephemerate,
content: `${addString}\n${removeString}\n${pingsString}`,
});
}
Expand All @@ -460,8 +519,9 @@ export default class Settings extends Interaction {
* @param {Discord.CommandInteraction} interaction message containing channel context
* @param {CommandContext} ctx to set up everything
* @param {Discord.TextChannel} [channel] to set up
* @param {Discord.ThreadChannel} [thread] to post to
*/
static async #generateWebhook(interaction, ctx, channel) {
static async #generateWebhook(interaction, ctx, channel, thread) {
channel = channel || interaction.channel;
if (channel.permissionsFor(interaction.client.user).has('MANAGE_WEBHOOKS')) {
let webhook;
Expand Down Expand Up @@ -506,7 +566,10 @@ export default class Settings extends Interaction {
if (webhook.url) {
try {
await interaction.followUp(`${emojify('green_tick')} Webhook setup complete.`);
await webhook.send(':diamond_shape_with_a_dot_inside: Webhook initialized');
await webhook.send({
content: ':diamond_shape_with_a_dot_inside: Webhook initialized',
threadId: thread?.id,
});
if (!webhook.avatar.startsWith('http')) webhook.avatar = ctx.settings.defaults.avatar;
} catch (e) {
ctx.logger.error(e);
Expand Down
6 changes: 4 additions & 2 deletions src/notifications/Broadcaster.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,16 @@ export default class Broadcaster {
const channels = cachedEvents.includes(type)
? this.workerCache.getKey(`${type}:${platform}`)
: await this.settings.getAgnosticNotifications(type, platform, items);
if (!channels.length) {
if (!channels?.length) {
logger.silly(`No channels on ${platform} tracking ${type}... continuing`, 'WS');
return;
}

await Promise.all(
channels.map(async (channelId) => {
channels.map(async ({ channelId, threadId }) => {
if (typeof channelId === 'undefined' || !channelId.length) return;
const ctx = await this.settings.getCommandContext(channelId);
ctx.threadId = threadId;

// localeCompare should return 0 if equal, so non-zero's will be truthy
if (embed.locale && ctx.language.localeCompare(embed.locale)) {
Expand All @@ -75,6 +76,7 @@ export default class Broadcaster {
}

try {
/** @type {string} */
const content = this.workerCache.getKey('pings')[`${guild.id}:${[type].concat(items || [])}`] || '';
await webhook(ctx, { content, embeds: [embed] });
} catch (e) {
Expand Down
24 changes: 12 additions & 12 deletions src/notifications/Worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,18 @@ class Worker {
}
async hydrateQueries() {
const sDate = Date.now();
await Promise.all(
cachedEvents.map(async (cachedEvent) =>
Promise.all(
activePlatforms.map(async (platform) => {
deps.workerCache.setKey(
`${cachedEvent}:${platform}`,
await deps.settings.getAgnosticNotifications(cachedEvent, platform)
);
})
)
)
);
const promises = [];
cachedEvents.forEach((cachedEvent) => {
activePlatforms.forEach((platform) => {
promises.push(
(async () => {
const notifications = await deps.settings.getAgnosticNotifications(cachedEvent, platform);
deps.workerCache.setKey(`${cachedEvent}:${platform}`, notifications);
})()
);
});
});
await Promise.all(promises);
deps.workerCache.save(true);
const eDate = Date.now();
logger.info(`query hydration took ${String(eDate - sDate).red}ms`, 'DB');
Expand Down
2 changes: 1 addition & 1 deletion src/notifications/worldstate/Notifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ export default class Notifier {
if (!nightwave) return;
return perLanguage(async ({ i18n, locale }) => {
if (nightwave.activeChallenges.length) {
return Promise.mapSeries(nightwave.active, async (challenge) => {
return Promise?.mapSeries(nightwave?.active, async (challenge) => {
const nwCopy = { ...nightwave };
nwCopy.activeChallenges = [challenge];
const embed = new embeds.Nightwave(nwCopy, { platform, i18n, locale });
Expand Down
Loading

0 comments on commit efee0fd

Please sign in to comment.