slots.ts
· 2.3 KiB · TypeScript
Bruto
import cron from "node-cron";
import { Client, TextChannel } from "discord.js";
import { cfg } from "./config";
import { TGSlot } from "../types";
import { polls, updatePollMessage } from "@systems/poll";
type PollCallback = (slot: TGSlot) => Promise<void>;
type CloseCallback = (slot: TGSlot) => Promise<void>;
type LockCallback = (slot: TGSlot) => Promise<void>;
let _scheduledTasks: cron.ScheduledTask[] = [];
export function scheduleSlots(
client: Client,
onPollOpen: PollCallback,
onPollLock: LockCallback,
onPollClose: CloseCallback,
): void {
_scheduledTasks.forEach((t) => t.stop());
_scheduledTasks = [];
const tz = process.env.TZ ?? "Etc/GMT-2";
const slots = cfg("slots").filter((s) => s.active);
for (const slot of slots) {
// Poll open
const [openHour, openMin] = slot.pollOpens.split(":").map(Number);
_scheduledTasks.push(cron.schedule(
`${openMin} ${openHour} * * *`,
() => onPollOpen(slot),
{ timezone: tz }
));
// Poll lock — exactly at tgHour (TG start, voting closes, lockedYesKeys snapshotted)
_scheduledTasks.push(cron.schedule(
`0 ${slot.tgHour} * * *`,
() => onPollLock(slot),
{ timezone: tz }
));
// Poll close — tgHour + closesAfter minutes (TG end, Submit Score button appears)
const closeMinTotal = slot.tgHour * 60 + slot.closesAfter;
const closeHour = Math.floor(closeMinTotal / 60) % 24;
const closeMin = closeMinTotal % 60;
_scheduledTasks.push(cron.schedule(
`${closeMin} ${closeHour} * * *`,
() => onPollClose(slot),
{ timezone: tz }
));
_scheduledTasks.push(cron.schedule("0 0 * * *", async () => {
const state = polls.get(slot.tgHour);
if (!state?.locked) return; // only if poll has been locked (TG happened)
const channel = await (client as any).channels.fetch(cfg("pollChannelId")) as TextChannel;
await updatePollMessage(channel, slot.tgHour, undefined, false);
console.log(`[${new Date().toISOString()}] Submit Score button removed.`);
}, { timezone: tz }));
}
// Weekly reset — Monday 00:00
_scheduledTasks.push(cron.schedule("0 0 * * 1", () => {
const { resetWeek } = require("./wrank");
resetWeek();
console.log("W.Rank weekly reset complete.");
}, { timezone: tz }));
console.log(`Scheduled ${slots.length} slot(s).`);
}
| 1 | import cron from "node-cron"; |
| 2 | import { Client, TextChannel } from "discord.js"; |
| 3 | import { cfg } from "./config"; |
| 4 | import { TGSlot } from "../types"; |
| 5 | import { polls, updatePollMessage } from "@systems/poll"; |
| 6 | |
| 7 | type PollCallback = (slot: TGSlot) => Promise<void>; |
| 8 | type CloseCallback = (slot: TGSlot) => Promise<void>; |
| 9 | type LockCallback = (slot: TGSlot) => Promise<void>; |
| 10 | |
| 11 | let _scheduledTasks: cron.ScheduledTask[] = []; |
| 12 | |
| 13 | export function scheduleSlots( |
| 14 | client: Client, |
| 15 | onPollOpen: PollCallback, |
| 16 | onPollLock: LockCallback, |
| 17 | onPollClose: CloseCallback, |
| 18 | ): void { |
| 19 | _scheduledTasks.forEach((t) => t.stop()); |
| 20 | _scheduledTasks = []; |
| 21 | |
| 22 | const tz = process.env.TZ ?? "Etc/GMT-2"; |
| 23 | const slots = cfg("slots").filter((s) => s.active); |
| 24 | |
| 25 | for (const slot of slots) { |
| 26 | // Poll open |
| 27 | const [openHour, openMin] = slot.pollOpens.split(":").map(Number); |
| 28 | _scheduledTasks.push(cron.schedule( |
| 29 | `${openMin} ${openHour} * * *`, |
| 30 | () => onPollOpen(slot), |
| 31 | { timezone: tz } |
| 32 | )); |
| 33 | |
| 34 | // Poll lock — exactly at tgHour (TG start, voting closes, lockedYesKeys snapshotted) |
| 35 | _scheduledTasks.push(cron.schedule( |
| 36 | `0 ${slot.tgHour} * * *`, |
| 37 | () => onPollLock(slot), |
| 38 | { timezone: tz } |
| 39 | )); |
| 40 | |
| 41 | // Poll close — tgHour + closesAfter minutes (TG end, Submit Score button appears) |
| 42 | const closeMinTotal = slot.tgHour * 60 + slot.closesAfter; |
| 43 | const closeHour = Math.floor(closeMinTotal / 60) % 24; |
| 44 | const closeMin = closeMinTotal % 60; |
| 45 | _scheduledTasks.push(cron.schedule( |
| 46 | `${closeMin} ${closeHour} * * *`, |
| 47 | () => onPollClose(slot), |
| 48 | { timezone: tz } |
| 49 | )); |
| 50 | |
| 51 | _scheduledTasks.push(cron.schedule("0 0 * * *", async () => { |
| 52 | const state = polls.get(slot.tgHour); |
| 53 | if (!state?.locked) return; // only if poll has been locked (TG happened) |
| 54 | const channel = await (client as any).channels.fetch(cfg("pollChannelId")) as TextChannel; |
| 55 | await updatePollMessage(channel, slot.tgHour, undefined, false); |
| 56 | console.log(`[${new Date().toISOString()}] Submit Score button removed.`); |
| 57 | }, { timezone: tz })); |
| 58 | } |
| 59 | |
| 60 | // Weekly reset — Monday 00:00 |
| 61 | _scheduledTasks.push(cron.schedule("0 0 * * 1", () => { |
| 62 | const { resetWeek } = require("./wrank"); |
| 63 | resetWeek(); |
| 64 | console.log("W.Rank weekly reset complete."); |
| 65 | }, { timezone: tz })); |
| 66 | |
| 67 | console.log(`Scheduled ${slots.length} slot(s).`); |
| 68 | } |