WIP: Working, however /remind is missing features
This commit is contained in:
@@ -16,6 +16,7 @@ import * as chrono from "chrono-node";
|
||||
interface Settings {
|
||||
client: Client; // Main Discord client object
|
||||
db: Sequelize; // Database access object
|
||||
responseMode: string;
|
||||
publicChannel: string; // Channel to use if a reminder is public
|
||||
loopIntervalSec?: number; // Loop interval in seconds
|
||||
}
|
||||
@@ -48,43 +49,67 @@ class Reminder extends Model {
|
||||
|
||||
class Plugin {
|
||||
settings: Settings;
|
||||
publicChannel: TextChannel;
|
||||
interval: NodeJS.Timeout;
|
||||
|
||||
constructor(settings: Settings) {
|
||||
this.settings = settings;
|
||||
this.publicChannel = getSendableTextChannel(
|
||||
settings.client,
|
||||
settings.publicChannel,
|
||||
);
|
||||
}
|
||||
|
||||
getChannel(reminder: Reminder) {
|
||||
let channel: TextChannel | null = null;
|
||||
const client = this.settings.client;
|
||||
const publicChannel = this.settings.publicChannel;
|
||||
// if (this.settings.responseMode === "private") {
|
||||
// channel = getSendableTextChannel(client, reminder.requestChannel);
|
||||
// }
|
||||
if (this.settings.responseMode === "public" || !channel) {
|
||||
channel = getSendableTextChannel(client, publicChannel);
|
||||
}
|
||||
if (!channel) {
|
||||
throw Error("Cannot find valid channel to send reminder on");
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
async loop() {
|
||||
console.debug("remind.js main loop");
|
||||
const results = await Reminder.findAll({
|
||||
// NOTE: 'trigger' is the time when the reminder should go off. If trigger -
|
||||
// now is positive, trigger is in the future. If trigger - now <=
|
||||
// 1.0, then we have less than one minute before the timer should go
|
||||
// off.
|
||||
where: sequelize.literal(
|
||||
"(julianday(trigger) - julianday('now')) <= 1.0",
|
||||
"isValid AND (julianday(trigger) - julianday('now')) <= 1.0",
|
||||
),
|
||||
});
|
||||
for (const reminder of results) {
|
||||
try {
|
||||
const now = new Date(Date.now());
|
||||
const wait = reminder.trigger.getTime() - now.getTime();
|
||||
const delay = reminder.trigger.getTime() - now.getTime();
|
||||
console.log(
|
||||
`Callback for Reminder ${reminder.get("id")} triggering in ${wait}ms`,
|
||||
);
|
||||
setTimeout(
|
||||
async () => await triggerReminder(this.publicChannel, reminder),
|
||||
wait,
|
||||
`Callback for Reminder ${reminder.get("id")} triggering in ${delay}ms`,
|
||||
);
|
||||
const channel = this.getChannel(reminder);
|
||||
setTimeout(async () => await triggerReminder(channel, reminder), delay);
|
||||
} catch (error) {
|
||||
console.error(`Unrecoverable error: ${error}`);
|
||||
console.error(
|
||||
`Error while processing Reminder ${reminder.id}: ${error}`,
|
||||
);
|
||||
console.trace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
this.interval = setInterval(
|
||||
this.loop.bind(this),
|
||||
1000 * (this.settings.loopIntervalSec ?? 60),
|
||||
);
|
||||
}
|
||||
|
||||
stop() {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
}
|
||||
|
||||
async function initialize(settings: Settings) {
|
||||
@@ -115,23 +140,25 @@ async function initialize(settings: Settings) {
|
||||
);
|
||||
await Reminder.sync();
|
||||
|
||||
if (
|
||||
!(await getSendableTextChannel(settings.client, settings.publicChannel))
|
||||
) {
|
||||
// Try and determine how the bot will send reminders
|
||||
console.debug(`Accessing channel ${settings.publicChannel}`);
|
||||
if (!getSendableTextChannel(settings.client, settings.publicChannel)) {
|
||||
throw Error(
|
||||
"Invalid value for publicChannel; specify a channel the bot can access.",
|
||||
);
|
||||
}
|
||||
const plugin = new Plugin(settings);
|
||||
|
||||
// Initialize the 'plugin' object which will store all state required to control the mainloop.
|
||||
if (settings.loopIntervalSec == null || settings.loopIntervalSec <= 0) {
|
||||
console.log("Setting plugin loop interval to default of 60 seconds");
|
||||
settings.loopIntervalSec = 60;
|
||||
}
|
||||
setInterval(plugin.loop, 1000 * settings.loopIntervalSec);
|
||||
const plugin = new Plugin(settings);
|
||||
plugin.start();
|
||||
}
|
||||
|
||||
function getSendableTextChannel(client: Client, chanId: string) {
|
||||
console.log(`getSendableTextChannel(${client}, ${chanId})`);
|
||||
// console.log(`getSendableTextChannel(${client}, ${chanId})`);
|
||||
const channel = client.channels.cache.get(chanId);
|
||||
if (!client.user) {
|
||||
throw Error("Can't check non-existent client");
|
||||
@@ -146,27 +173,32 @@ function getSendableTextChannel(client: Client, chanId: string) {
|
||||
throw Error("Channel is not a guild channel");
|
||||
}
|
||||
const permissions = channel?.permissionsFor(client.user);
|
||||
if (
|
||||
!permissions?.has([
|
||||
PermissionsBitField.Flags.SendMessages,
|
||||
PermissionsBitField.Flags.ViewChannel,
|
||||
])
|
||||
) {
|
||||
const requiredPerms = new PermissionsBitField([
|
||||
PermissionsBitField.Flags.SendMessages,
|
||||
PermissionsBitField.Flags.ViewChannel,
|
||||
]);
|
||||
if (!permissions?.has(requiredPerms)) {
|
||||
throw Error("Missing required permissions: SendMessages, ViewChannel");
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
async function triggerReminder(channel: TextChannel, reminder: Reminder) {
|
||||
await channel.send({
|
||||
content: `Reminder for <@${reminder.userId}>: ${reminder.text}`,
|
||||
});
|
||||
reminder.isValid = false;
|
||||
await reminder.save();
|
||||
try {
|
||||
await channel.send({
|
||||
content: `Reminder for <@${reminder.userId}>: ${reminder.text}`,
|
||||
});
|
||||
reminder.isValid = false;
|
||||
} catch (error) {
|
||||
console.log(`Error trigggering Reminder ${reminder.id}: ${error}`);
|
||||
} finally {
|
||||
await reminder.save();
|
||||
}
|
||||
}
|
||||
|
||||
async function execute(interaction: ChatInputCommandInteraction) {
|
||||
const when = chrono.parseDate(interaction.options.getString("when") ?? "now");
|
||||
const whenString = interaction.options.getString("when") ?? "now";
|
||||
const when = chrono.parseDate(whenString);
|
||||
if (!when) {
|
||||
await interaction.reply(`Sorry, I don't understand '${when}' as a date`);
|
||||
return;
|
||||
@@ -190,7 +222,7 @@ export default function (settings: Settings) {
|
||||
return {
|
||||
data,
|
||||
execute,
|
||||
initialize,
|
||||
initialize: async () => await initialize(settings),
|
||||
Reminder,
|
||||
settings,
|
||||
};
|
||||
|
||||
11
index.ts
11
index.ts
@@ -89,12 +89,21 @@ const commands = new Collection<string, Command>();
|
||||
|
||||
import PingCommand from "./commands/calendar/ping";
|
||||
import RemindCommand from "./commands/calendar/remind";
|
||||
import QuoteCommand from "./commands/quotes/quote";
|
||||
|
||||
console.debug(`${remindersChannelId}`);
|
||||
|
||||
commands.set("ping", PingCommand({ client: client, db: sql }));
|
||||
commands.set(
|
||||
"remind",
|
||||
RemindCommand({ client: client, db: sql, publicChannel: remindersChannelId }),
|
||||
RemindCommand({
|
||||
client: client,
|
||||
db: sql,
|
||||
publicChannel: remindersChannelId,
|
||||
responseMode: "public",
|
||||
}),
|
||||
);
|
||||
commands.set("quote", QuoteCommand({}));
|
||||
|
||||
async function syncCommands() {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user