76 lines
1.9 KiB
TypeScript
76 lines
1.9 KiB
TypeScript
/**
|
|
* Task scheduler using node-cron.
|
|
* Loads enabled tasks from the DB on startup and registers them.
|
|
*/
|
|
|
|
import cron, { ScheduledTask } from "node-cron";
|
|
import { db } from "@/lib/db";
|
|
import { scheduledTasks } from "@/lib/db/schema";
|
|
import { eq } from "drizzle-orm";
|
|
import { rconClient } from "@/lib/minecraft/rcon";
|
|
import { sanitizeRconCommand } from "@/lib/security/sanitize";
|
|
|
|
const activeJobs = new Map<string, ScheduledTask>();
|
|
|
|
/** Load all enabled tasks from DB and schedule them. */
|
|
export async function initScheduler(): Promise<void> {
|
|
const tasks = await db
|
|
.select()
|
|
.from(scheduledTasks)
|
|
.where(eq(scheduledTasks.isEnabled, true));
|
|
|
|
for (const task of tasks) {
|
|
scheduleTask(task.id, task.cronExpression, task.command);
|
|
}
|
|
}
|
|
|
|
/** Schedule a single task. Returns false if cron expression is invalid. */
|
|
export function scheduleTask(
|
|
id: string,
|
|
expression: string,
|
|
command: string,
|
|
): boolean {
|
|
if (!cron.validate(expression)) return false;
|
|
|
|
// Stop existing job if any
|
|
stopTask(id);
|
|
|
|
const job = cron.schedule(expression, async () => {
|
|
try {
|
|
const safeCmd = sanitizeRconCommand(command);
|
|
await rconClient.sendCommand(safeCmd);
|
|
await db
|
|
.update(scheduledTasks)
|
|
.set({ lastRun: Date.now() })
|
|
.where(eq(scheduledTasks.id, id));
|
|
} catch (err) {
|
|
console.error(`[Scheduler] Task ${id} failed:`, err);
|
|
}
|
|
});
|
|
|
|
activeJobs.set(id, job);
|
|
return true;
|
|
}
|
|
|
|
/** Stop and remove a scheduled task. */
|
|
export function stopTask(id: string): void {
|
|
const existing = activeJobs.get(id);
|
|
if (existing) {
|
|
existing.stop();
|
|
activeJobs.delete(id);
|
|
}
|
|
}
|
|
|
|
/** Stop all active jobs. */
|
|
export function stopAllTasks(): void {
|
|
for (const [id, job] of activeJobs.entries()) {
|
|
job.stop();
|
|
activeJobs.delete(id);
|
|
}
|
|
}
|
|
|
|
/** List active job IDs. */
|
|
export function getActiveTaskIds(): string[] {
|
|
return Array.from(activeJobs.keys());
|
|
}
|