feat(lstv2 move): moved lstv2 into this app to keep them combined and easier to maintain
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
import { db } from "../../../../database/dbclient.js";
|
||||
import { notifications } from "../../../../database/schema/notifications.js";
|
||||
import { settings } from "../../../../database/schema/settings.js";
|
||||
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||
import type { JobInfo } from "../../../types/JobInfo.js";
|
||||
import { createLog } from "../../logger/logger.js";
|
||||
import { Cron } from "croner";
|
||||
|
||||
// Store active timeouts by notification ID
|
||||
export let runningCrons: Record<string, Cron> = {};
|
||||
|
||||
export const startNotificationMonitor = async () => {
|
||||
// if restarted or crashed we need to make sure the running notifications is cleared
|
||||
createLog("info", "notify", "notify", `Notification system is now active.`);
|
||||
|
||||
setInterval(async () => {
|
||||
const { data: notes, error } = (await tryCatch(
|
||||
db.select().from(notifications)
|
||||
)) as any;
|
||||
|
||||
if (error) {
|
||||
createLog(
|
||||
"error",
|
||||
"notify",
|
||||
"notify",
|
||||
`There was an error getting the notifications: ${JSON.stringify(
|
||||
error
|
||||
)}`
|
||||
);
|
||||
}
|
||||
|
||||
for (const note of notes) {
|
||||
//if we get deactivated remove it.
|
||||
if (runningCrons[note.name] && !note.active) {
|
||||
createLog(
|
||||
"info",
|
||||
"notify",
|
||||
"notify",
|
||||
`${note.name} was just deactivated`
|
||||
);
|
||||
removeNotification(note.name);
|
||||
}
|
||||
|
||||
// if we are not active, no emails, and already in place just stop.
|
||||
|
||||
if (
|
||||
!note.active ||
|
||||
// note.emails === "" ||
|
||||
runningCrons[note.name]
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!runningCrons[note.name] && note.active) {
|
||||
createLog(
|
||||
"info",
|
||||
"notify",
|
||||
"notify",
|
||||
`${note.name} Is active and not already running.`
|
||||
);
|
||||
}
|
||||
|
||||
let time = `*/30 * * * *`; // default to be every 30 min
|
||||
|
||||
if (note.timeType === "min") {
|
||||
//console.log(`Creating the min mark here`);
|
||||
const totalMinutes = note.checkInterval;
|
||||
if (note.checkInterval > 60) {
|
||||
const hours = Math.floor(totalMinutes / 60); // 1 hour
|
||||
const minutes = totalMinutes % 60; // 45 minutes
|
||||
time = `*/${minutes} */${hours} * * *`;
|
||||
} else {
|
||||
time = `*/${note.checkInterval} * * * *`;
|
||||
}
|
||||
}
|
||||
if (note.timeType === "hour") {
|
||||
const totalHours = note.checkInterval;
|
||||
if (note.checkInterval > 60) {
|
||||
const days = Math.floor(totalHours / 24); // 1 hour
|
||||
const hours = totalHours % 24; // 45 minutes
|
||||
time = `* */${hours} */${days} * *`;
|
||||
} else {
|
||||
time = `* */${note.checkInterval} * * *`;
|
||||
}
|
||||
}
|
||||
|
||||
createJob(note.name, time, async () => {
|
||||
try {
|
||||
const { default: runFun } = await import(
|
||||
`../controller/notifications/${note.name}.js`
|
||||
);
|
||||
await runFun(note);
|
||||
} catch (error: any) {
|
||||
createLog(
|
||||
"error",
|
||||
"notify",
|
||||
note.name,
|
||||
`Error running notification: ${error.message}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
//testParse(runningNotifcations[note.name]);
|
||||
}
|
||||
}, 5 * 1000);
|
||||
};
|
||||
|
||||
export const createJob = async (
|
||||
id: string,
|
||||
schedule: string,
|
||||
task: () => Promise<void>
|
||||
) => {
|
||||
const { data, error } = (await tryCatch(db.select().from(settings))) as any;
|
||||
|
||||
const timeZone = data.filter((n: any) => n.name === "timezone");
|
||||
// Destroy existing job if it exists
|
||||
if (runningCrons[id]) {
|
||||
runningCrons[id].stop(); // Croner uses .stop() instead of .destroy()
|
||||
}
|
||||
|
||||
// Create new job with Croner
|
||||
runningCrons[id] = new Cron(
|
||||
schedule,
|
||||
{
|
||||
timezone: timeZone[0].timezone,
|
||||
catch: true, // Prevents unhandled rejections
|
||||
},
|
||||
task
|
||||
);
|
||||
|
||||
// Optional: Add error handling (Croner emits 'error' events)
|
||||
// runningNotifications[id].on("error", (err) => {
|
||||
// console.error(`Job ${id} failed:`, err);
|
||||
// });
|
||||
};
|
||||
|
||||
export const getAllJobs = (): JobInfo[] => {
|
||||
return Object.entries(runningCrons).map(([id, job]) => ({
|
||||
id,
|
||||
schedule: job.getPattern() || "invalid",
|
||||
nextRun: job.nextRun() || null,
|
||||
lastRun: job.previousRun() || null,
|
||||
isRunning: job ? !job.isStopped() : false,
|
||||
}));
|
||||
};
|
||||
|
||||
const removeNotification = (id: any) => {
|
||||
if (runningCrons[id]) {
|
||||
runningCrons[id].stop();
|
||||
delete runningCrons[id];
|
||||
}
|
||||
};
|
||||
|
||||
export const stopAllJobs = () => {
|
||||
Object.values(runningCrons).forEach((job: any) => job.stop());
|
||||
runningCrons = {}; // Clear the object
|
||||
};
|
||||
|
||||
/*
|
||||
// Pause a job
|
||||
app.post("/api/jobs/:id/pause", (req, res) => {
|
||||
runningNotifications[req.params.id]?.pause();
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
// Resume a job
|
||||
app.post("/api/jobs/:id/resume", (req, res) => {
|
||||
runningNotifications[req.params.id]?.resume();
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
// Delete a job
|
||||
app.delete("/api/jobs/:id", (req, res) => {
|
||||
runningNotifications[req.params.id]?.stop();
|
||||
delete runningNotifications[req.params.id];
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
|
||||
*/
|
||||
Reference in New Issue
Block a user