refactor subscriptions to use sqlite w/ knex
This commit is contained in:
parent
57b96ce082
commit
e57ebd47d2
|
@ -8,4 +8,5 @@ dist/
|
||||||
/counter.json
|
/counter.json
|
||||||
/counterMessageID.txt
|
/counterMessageID.txt
|
||||||
/counterCream.json
|
/counterCream.json
|
||||||
/counterCreamMessageID.txt
|
/counterCreamMessageID.txt
|
||||||
|
/*.sqlite
|
|
@ -1,4 +1,3 @@
|
||||||
{
|
{
|
||||||
"token": "token",
|
"token": "token"
|
||||||
"disableDaytimeAnnouncements": false
|
|
||||||
}
|
}
|
|
@ -1,15 +0,0 @@
|
||||||
const fs = require("node:fs");
|
|
||||||
const { REST, Routes } = require("discord.js");
|
|
||||||
const {token} = require('./config.json');
|
|
||||||
|
|
||||||
const rest = new REST({ version: "9" }).setToken(token);
|
|
||||||
|
|
||||||
rest.get(Routes.applicationGuildCommands('898850107892596776', '587108210121506816')).then((data) => {
|
|
||||||
const promises = [];
|
|
||||||
for (const command of data) {
|
|
||||||
const deleteUrl = `${Routes.applicationGuildCommands('898850107892596776', '587108210121506816')}/${command.id}`;
|
|
||||||
promises.push(rest.delete(deleteUrl));
|
|
||||||
}
|
|
||||||
console.log(`Removing ${promises.length} commands...`);
|
|
||||||
Promise.all(promises).then(() => console.log('Done!'));
|
|
||||||
});
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
pnpm run build && pm2 restart foggy-v2
|
|
|
@ -7,8 +7,7 @@
|
||||||
"start": "tsc && node deploy-commands.cjs && node dist/index.js",
|
"start": "tsc && node deploy-commands.cjs && node dist/index.js",
|
||||||
"dev": "tsc && node dist/index.js",
|
"dev": "tsc && node dist/index.js",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"deploy-commands": "tsc && node deploy-commands.cjs",
|
"deploy-commands": "tsc && node deploy-commands.cjs"
|
||||||
"delete-commands": "tsc && node delete-commands.cjs"
|
|
||||||
},
|
},
|
||||||
"author": "oatmealine",
|
"author": "oatmealine",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
|
@ -16,8 +15,10 @@
|
||||||
"d3-array": "^2.12.1",
|
"d3-array": "^2.12.1",
|
||||||
"discord.js": "^14.13.0",
|
"discord.js": "^14.13.0",
|
||||||
"got": "^11.8.6",
|
"got": "^11.8.6",
|
||||||
|
"knex": "^3.0.1",
|
||||||
"parse-color": "^1.0.0",
|
"parse-color": "^1.0.0",
|
||||||
"random-seed": "^0.3.0"
|
"random-seed": "^0.3.0",
|
||||||
|
"sqlite3": "^5.1.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/d3-array": "^3.0.9",
|
"@types/d3-array": "^3.0.9",
|
||||||
|
|
863
pnpm-lock.yaml
863
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
||||||
import { Interaction, SlashCommandBuilder } from 'discord.js';
|
import { Interaction, SlashCommandBuilder } from 'discord.js';
|
||||||
import { saveSubscriptions, subscriptions, timeAnnouncements } from '../lib/subscriptions';
|
import { isSubscribed, subscribe, timeAnnouncements, unsubscribe } from '../lib/subscriptions';
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
|
@ -19,19 +19,18 @@ module.exports = {
|
||||||
await interaction.deferReply({ephemeral: true});
|
await interaction.deferReply({ephemeral: true});
|
||||||
|
|
||||||
const announcementType = interaction.options.getString('type', true);
|
const announcementType = interaction.options.getString('type', true);
|
||||||
|
const channel = interaction.channelId;
|
||||||
|
|
||||||
if (subscriptions[announcementType] && subscriptions[announcementType].includes(interaction.channelId)) {
|
if (await isSubscribed(announcementType, channel)) {
|
||||||
subscriptions[announcementType] = subscriptions[announcementType].filter(id => id !== interaction.channelId);
|
await unsubscribe(announcementType, channel);
|
||||||
await interaction.followUp({
|
await interaction.followUp({
|
||||||
content: `<#${interaction.channelId}> has been unsubscribed from \`${announcementType}\``
|
content: `<#${interaction.channelId}> has been unsubscribed from \`${announcementType}\``
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
subscriptions[announcementType] = subscriptions[announcementType] || [];
|
await subscribe(announcementType, interaction.guildId || undefined, channel);
|
||||||
subscriptions[announcementType].push(interaction.channelId);
|
|
||||||
await interaction.followUp({
|
await interaction.followUp({
|
||||||
content: `<#${interaction.channelId}> has been subscribed to \`${announcementType}\``
|
content: `<#${interaction.channelId}> has been subscribed to \`${announcementType}\``
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
saveSubscriptions();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
14
src/index.ts
14
src/index.ts
|
@ -1,12 +1,10 @@
|
||||||
import { Client, GatewayIntentBits, Events, Collection, TextChannel } from 'discord.js';
|
import { Client, GatewayIntentBits, Events, Collection, TextChannel } from 'discord.js';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
const { token, disableDaytimeAnnouncements } = JSON.parse(fs.readFileSync('./config.json', 'utf8'));
|
const { token } = JSON.parse(fs.readFileSync('./config.json', 'utf8'));
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { initializeCounter } from './lib/counter';
|
import { initializeCounter } from './lib/counter';
|
||||||
import { initializeAnnouncements, loadNext, loadSubscriptions } from './lib/subscriptions';
|
import { initializeAnnouncements } from './lib/subscriptions';
|
||||||
|
import { initTables } from './lib/db';
|
||||||
loadNext();
|
|
||||||
loadSubscriptions();
|
|
||||||
|
|
||||||
const bot = new Client({
|
const bot = new Client({
|
||||||
intents: [
|
intents: [
|
||||||
|
@ -24,9 +22,7 @@ bot.on(Events.ClientReady, async () => {
|
||||||
initializeCounter(false);
|
initializeCounter(false);
|
||||||
initializeCounter(true);
|
initializeCounter(true);
|
||||||
|
|
||||||
if (!disableDaytimeAnnouncements) {
|
initializeAnnouncements(bot);
|
||||||
initializeAnnouncements(bot);
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.commands = new Collection();
|
bot.commands = new Collection();
|
||||||
const cmdFiles = fs.readdirSync(path.join(__dirname, './commands')).filter((file) => file.endsWith('.js'));
|
const cmdFiles = fs.readdirSync(path.join(__dirname, './commands')).filter((file) => file.endsWith('.js'));
|
||||||
|
@ -63,4 +59,4 @@ process.on('uncaughtException', err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
bot.login(token);
|
initTables().then(() => bot.login(token));
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import knex from 'knex';
|
||||||
|
|
||||||
|
export const db = knex({
|
||||||
|
client: 'sqlite3',
|
||||||
|
connection: {
|
||||||
|
filename: './jillo.sqlite'
|
||||||
|
},
|
||||||
|
useNullAsDefault: true
|
||||||
|
});
|
||||||
|
|
||||||
|
export interface ScheduledSubscription {
|
||||||
|
name: string;
|
||||||
|
next: number;
|
||||||
|
}
|
||||||
|
export interface Subscription {
|
||||||
|
key: string,
|
||||||
|
channel: string,
|
||||||
|
guild?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function initTables() {
|
||||||
|
await db.schema.createTableIfNotExists('scheduledSubscriptions', table => {
|
||||||
|
table.string('name').primary();
|
||||||
|
table.timestamp('next').defaultTo(db.fn.now());
|
||||||
|
});
|
||||||
|
await db.schema.createTableIfNotExists('subscriptions', table => {
|
||||||
|
table.string('key')
|
||||||
|
.references('name').inTable('scheduledSubscriptions');
|
||||||
|
table.string('channel');
|
||||||
|
table.string('guild').nullable();
|
||||||
|
});
|
||||||
|
/*await db.schema.createTableIfNotExists('counters', table => {
|
||||||
|
table.string('key').primary();
|
||||||
|
table.string('name').notNullable();
|
||||||
|
table.string('emoji').notNullable();
|
||||||
|
table.integer('value').defaultTo(0);
|
||||||
|
table.string('channel').notNullable();
|
||||||
|
table.string('message');
|
||||||
|
table.boolean('allowlist');
|
||||||
|
});
|
||||||
|
await db.schema.createTableIfNotExists('counterUserLink', table => {
|
||||||
|
table.string('key').references('key').inTable('counters');
|
||||||
|
table.string('user').notNullable();
|
||||||
|
});*/
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { Client, TextChannel } from 'discord.js';
|
import { Client, TextChannel } from 'discord.js';
|
||||||
import * as fs from 'fs';
|
import { ScheduledSubscription, Subscription, db } from './db';
|
||||||
|
|
||||||
interface AnnouncementType {
|
interface AnnouncementType {
|
||||||
hour: number;
|
hour: number;
|
||||||
|
@ -159,55 +159,65 @@ function getNextTime(hour: number, randomMinute = true) {
|
||||||
return next.getTime();
|
return next.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
export let next: Record<string, number> = {};
|
export async function subscribe(type: string, guild: string | undefined, channel: string) {
|
||||||
export let subscriptions: Record<string, string[]> = {};
|
await db<Subscription>('subscriptions')
|
||||||
|
.insert({
|
||||||
export function saveNext() {
|
key: type,
|
||||||
fs.writeFileSync('./next.json', JSON.stringify(next));
|
guild: guild,
|
||||||
|
channel: channel
|
||||||
|
});
|
||||||
}
|
}
|
||||||
export function saveSubscriptions() {
|
export async function unsubscribe(type: string, channel: string) {
|
||||||
fs.writeFileSync('./subscriptions.json', JSON.stringify(subscriptions));
|
await db<Subscription>('subscriptions')
|
||||||
|
.delete()
|
||||||
|
.where('type', type).where('channel', channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadNext() {
|
export async function isSubscribed(type: string, channel: string): Promise<boolean> {
|
||||||
if (fs.existsSync('./next.json')) {
|
return await db<Subscription>('subscriptions')
|
||||||
next = JSON.parse(fs.readFileSync('./next.json', 'utf8'));
|
.where('key', type).where('channel', channel)
|
||||||
}
|
.first() !== undefined;
|
||||||
for (const k of Object.keys(timeAnnouncements)) {
|
|
||||||
if (!next[k]) next[k] = getNextAnnouncementTime(timeAnnouncements[k]);
|
|
||||||
}
|
|
||||||
saveNext();
|
|
||||||
}
|
|
||||||
export function loadSubscriptions() {
|
|
||||||
if (fs.existsSync('./subscriptions.json')) {
|
|
||||||
subscriptions = JSON.parse(fs.readFileSync('./subscriptions.json', 'utf8'));
|
|
||||||
}
|
|
||||||
saveSubscriptions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initializeAnnouncements(bot: Client) {
|
export function initializeAnnouncements(bot: Client) {
|
||||||
setInterval(() => {
|
setInterval(async () => {
|
||||||
const current = new Date().getTime();
|
const current = new Date().getTime();
|
||||||
|
|
||||||
// console.log(current, next.morning, next.night);
|
|
||||||
|
|
||||||
for (const k of Object.keys(timeAnnouncements)) {
|
for (const k of Object.keys(timeAnnouncements)) {
|
||||||
if (next[k] && current > next[k]) {
|
const announcement = timeAnnouncements[k];
|
||||||
const announcement = timeAnnouncements[k];
|
|
||||||
next[k] = getNextAnnouncementTime(announcement);
|
|
||||||
saveNext();
|
|
||||||
|
|
||||||
if (subscriptions[k]) {
|
const announcementObj = await db<ScheduledSubscription>('scheduledSubscriptions')
|
||||||
for (const channelID of subscriptions[k]) {
|
.select('*')
|
||||||
bot.channels.fetch(channelID, {allowUnknownGuild: true})
|
.where('name', k)
|
||||||
.then(c =>
|
.first();
|
||||||
(c as TextChannel).send(
|
|
||||||
`${announcement.messagesPrefix ? announcement.messagesPrefix : ''} ${announcement.messages[Math.floor(Math.random() * announcement.messages.length)]}`
|
if (!announcementObj) {
|
||||||
)
|
await db<ScheduledSubscription>('scheduledSubscriptions')
|
||||||
)
|
.insert({
|
||||||
.catch(err => `failed to send ${k} announcement to ${channelID}: ${err}`);
|
name: k,
|
||||||
}
|
next: getNextAnnouncementTime(announcement)
|
||||||
}
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current < announcementObj.next) continue;
|
||||||
|
|
||||||
|
await db<ScheduledSubscription>('scheduledSubscriptions')
|
||||||
|
.where('name', k)
|
||||||
|
.update('next', getNextAnnouncementTime(announcement));
|
||||||
|
|
||||||
|
const subscriptions = await db<Subscription>('subscriptions')
|
||||||
|
.select('*')
|
||||||
|
.where('key', k);
|
||||||
|
|
||||||
|
for (const { channel } of subscriptions) {
|
||||||
|
bot.channels.fetch(channel, {allowUnknownGuild: true})
|
||||||
|
.then(c =>
|
||||||
|
(c as TextChannel).send(
|
||||||
|
`${announcement.messagesPrefix ? announcement.messagesPrefix : ''} ${announcement.messages[Math.floor(Math.random() * announcement.messages.length)]}`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.catch(err => console.error(`failed to send ${k} announcement to ${channel}: ${err}`));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
Loading…
Reference in New Issue