mirror of
https://github.com/JonnyBro/JaBa.git
synced 2025-01-19 17:03:47 +05:00
feat: added cron manager
This commit is contained in:
parent
e8606e4977
commit
ea9b52cc4a
7 changed files with 250 additions and 130 deletions
|
@ -1,4 +1,7 @@
|
||||||
import logger from "../helpers/logger.js";
|
import logger from "../helpers/logger.js";
|
||||||
|
import { resolve } from "node:path";
|
||||||
|
import loadCronTasks from "../utils/loadCronTasks.js";
|
||||||
|
import { CronManager } from "../services/cron/index.js";
|
||||||
|
|
||||||
export const data = {
|
export const data = {
|
||||||
name: "ready",
|
name: "ready",
|
||||||
|
@ -11,4 +14,11 @@ export const data = {
|
||||||
*/
|
*/
|
||||||
export async function run(client) {
|
export async function run(client) {
|
||||||
logger.ready(client.user.tag + " is online!");
|
logger.ready(client.user.tag + " is online!");
|
||||||
|
|
||||||
|
const taskPath = resolve(client.configService.get("paths.tasks"));
|
||||||
|
|
||||||
|
const cronTasks = await loadCronTasks(taskPath);
|
||||||
|
|
||||||
|
const cronManager = new CronManager(cronTasks);
|
||||||
|
await cronManager.init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
import { CronJob } from "cron";
|
|
||||||
import useClient from "../utils/use-client.js";
|
|
||||||
import UserModel from "../models/UserModel.js";
|
|
||||||
import { createEmbed } from "../utils/create-embed.js";
|
|
||||||
import logger from "./logger.js";
|
|
||||||
import { getNoun } from "./functions.js";
|
|
||||||
|
|
||||||
const checkBirthdays = async () => {
|
|
||||||
const client = useClient();
|
|
||||||
|
|
||||||
const guilds = client.guilds.cache.values();
|
|
||||||
const users = await client.adapter.find(UserModel, { birthdate: { $gt: 1 } });
|
|
||||||
|
|
||||||
const currentData = new Date();
|
|
||||||
const currentYear = currentData.getFullYear();
|
|
||||||
const currentMonth = currentData.getMonth();
|
|
||||||
const currentDate = currentData.getDate();
|
|
||||||
|
|
||||||
for (const guild of guilds) {
|
|
||||||
try {
|
|
||||||
const data = await client.getGuildData(guild.id);
|
|
||||||
const channel = data.plugins.birthdays ? await client.channels.fetch(data.plugins.birthdays) : null;
|
|
||||||
|
|
||||||
if (!channel) return;
|
|
||||||
|
|
||||||
const userIDs = users.filter(u => guild.members.cache.has(u.id)).map(u => u.id);
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
userIDs.map(async userID => {
|
|
||||||
const user = users.find(u => u.id === userID);
|
|
||||||
const userData = new Date(user.birthdate).getFullYear() <= 1970 ? new Date(user.birthdate * 1000) : new Date(user.birthdate);
|
|
||||||
const userYear = userData.getFullYear();
|
|
||||||
const userMonth = userData.getMonth();
|
|
||||||
const userDate = userData.getDate();
|
|
||||||
|
|
||||||
const age = currentYear - userYear;
|
|
||||||
|
|
||||||
if (userDate === currentDate && userMonth === currentMonth) {
|
|
||||||
const embed = createEmbed({
|
|
||||||
author: client.user.username,
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: client.translate("economy/birthdate:HAPPY_BIRTHDAY", {
|
|
||||||
lng: data.language,
|
|
||||||
}),
|
|
||||||
value: client.translate("economy/birthdate:HAPPY_BIRTHDAY_MESSAGE", {
|
|
||||||
lng: data.language,
|
|
||||||
user: user.id,
|
|
||||||
age: `**${age}** ${getNoun(age, [
|
|
||||||
client.translate("misc:NOUNS:AGE:1", null, data.language),
|
|
||||||
client.translate("misc:NOUNS:AGE:2", null, data.language),
|
|
||||||
client.translate("misc:NOUNS:AGE:5", null, data.language),
|
|
||||||
])}`,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
await channel.send({ embeds: [embed] }).then(m => m.react(" "));
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function init() {
|
|
||||||
new CronJob("0 5 * * *", checkBirthdays(), null, true, "Europe/Moscow");
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
import UserModel from "../models/UserModel";
|
|
||||||
import useClient from "../utils/use-client";
|
|
||||||
|
|
||||||
const checkReminds = async () => {
|
|
||||||
const client = useClient();
|
|
||||||
|
|
||||||
client.adapter.find(UserModel, { reminds: { $gt: [] } }).then(users => {
|
|
||||||
for (const user of users) {
|
|
||||||
if (!client.users.cache.has(user.id)) client.users.fetch(user.id);
|
|
||||||
|
|
||||||
client.cacheReminds.set(user.id, user);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
client.cacheReminds.forEach(async user => {
|
|
||||||
const cachedUser = client.users.cache.get(user.id);
|
|
||||||
|
|
||||||
if (!cachedUser) return;
|
|
||||||
|
|
||||||
const reminds = user.reminds,
|
|
||||||
mustSent = reminds.filter(r => r.sendAt < Math.floor(Date.now() / 1000));
|
|
||||||
|
|
||||||
if (!mustSent.length) return;
|
|
||||||
|
|
||||||
mustSent.forEach(r => {
|
|
||||||
const embed = client.embed({
|
|
||||||
author: client.translate("general/remindme:EMBED_TITLE"),
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: client.translate("general/remindme:EMBED_CREATED"),
|
|
||||||
value: `<t:${r.createdAt}:f>`,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: client.translate("general/remindme:EMBED_TIME"),
|
|
||||||
value: `<t:${r.sendAt}:f>`,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: client.translate("common:MESSAGE"),
|
|
||||||
value: r.message,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
cachedUser.send({ embeds: [embed] }).then(() => {
|
|
||||||
client.adapter.updateOne(UserModel, { id: user.id }, { $pull: { reminds: { _id: r._id } } });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!user.reminds.length) client.cacheReminds.delete(user.id);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const init = async () => {
|
|
||||||
setInterval(async () => {
|
|
||||||
await checkReminds();
|
|
||||||
}, 1000);
|
|
||||||
};
|
|
70
src/helpers/tasks/birthdays.js
Normal file
70
src/helpers/tasks/birthdays.js
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import useClient from "../../utils/use-client.js";
|
||||||
|
import UserModel from "../../models/UserModel.js";
|
||||||
|
import { createEmbed } from "../../utils/create-embed.js";
|
||||||
|
import logger from "../logger.js";
|
||||||
|
import { getNoun } from "../functions.js";
|
||||||
|
|
||||||
|
export const data = {
|
||||||
|
name: "birthdays",
|
||||||
|
task: async () => {
|
||||||
|
const client = useClient();
|
||||||
|
|
||||||
|
const guilds = client.guilds.cache.values();
|
||||||
|
const users = await client.adapter.find(UserModel, { birthdate: { $gt: 1 } });
|
||||||
|
|
||||||
|
const currentData = new Date();
|
||||||
|
const currentYear = currentData.getFullYear();
|
||||||
|
const currentMonth = currentData.getMonth();
|
||||||
|
const currentDate = currentData.getDate();
|
||||||
|
|
||||||
|
for (const guild of guilds) {
|
||||||
|
try {
|
||||||
|
const data = await client.getGuildData(guild.id);
|
||||||
|
const channel = data.plugins.birthdays ? await client.channels.fetch(data.plugins.birthdays) : null;
|
||||||
|
|
||||||
|
if (!channel) return;
|
||||||
|
|
||||||
|
const userIDs = users.filter(u => guild.members.cache.has(u.id)).map(u => u.id);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
userIDs.map(async userID => {
|
||||||
|
const user = users.find(u => u.id === userID);
|
||||||
|
const userData = new Date(user.birthdate).getFullYear() <= 1970 ? new Date(user.birthdate * 1000) : new Date(user.birthdate);
|
||||||
|
const userYear = userData.getFullYear();
|
||||||
|
const userMonth = userData.getMonth();
|
||||||
|
const userDate = userData.getDate();
|
||||||
|
|
||||||
|
const age = currentYear - userYear;
|
||||||
|
|
||||||
|
if (userDate === currentDate && userMonth === currentMonth) {
|
||||||
|
const embed = createEmbed({
|
||||||
|
author: client.user.username,
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: client.translate("economy/birthdate:HAPPY_BIRTHDAY", {
|
||||||
|
lng: data.language,
|
||||||
|
}),
|
||||||
|
value: client.translate("economy/birthdate:HAPPY_BIRTHDAY_MESSAGE", {
|
||||||
|
lng: data.language,
|
||||||
|
user: user.id,
|
||||||
|
age: `**${age}** ${getNoun(age, [
|
||||||
|
client.translate("misc:NOUNS:AGE:1", null, data.language),
|
||||||
|
client.translate("misc:NOUNS:AGE:2", null, data.language),
|
||||||
|
client.translate("misc:NOUNS:AGE:5", null, data.language),
|
||||||
|
])}`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await channel.send({ embeds: [embed] }).then(m => m.react(" "));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
schedule: "0 5 * * *",
|
||||||
|
};
|
68
src/helpers/tasks/checkReminds.js
Normal file
68
src/helpers/tasks/checkReminds.js
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import UserModel from "../../models/UserModel.js";
|
||||||
|
import useClient from "../../utils/use-client.js";
|
||||||
|
import { createEmbed } from "../../utils/index.js";
|
||||||
|
|
||||||
|
export const data = {
|
||||||
|
name: "checkReminds",
|
||||||
|
task: async () => {
|
||||||
|
const client = useClient();
|
||||||
|
|
||||||
|
client.adapter.find(UserModel, { reminds: { $gt: [] } }).then(users => {
|
||||||
|
for (const user of users) {
|
||||||
|
if (!client.users.cache.has(user.id)) client.users.fetch(user.id);
|
||||||
|
|
||||||
|
client.cacheReminds.set(user.id, user);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
client.cacheReminds.forEach(async user => {
|
||||||
|
const cachedUser = client.users.cache.get(user.id);
|
||||||
|
|
||||||
|
if (!cachedUser) return;
|
||||||
|
|
||||||
|
const reminds = user.reminds,
|
||||||
|
mustSent = reminds.filter(r => r.sendAt < Math.floor(Date.now() / 1000));
|
||||||
|
|
||||||
|
if (!mustSent.length) return;
|
||||||
|
|
||||||
|
mustSent.forEach(r => {
|
||||||
|
const embed = createEmbed({
|
||||||
|
author: {
|
||||||
|
name: client.translate("general/remindme:EMBED_TITLE"),
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: client.translate("general/remindme:EMBED_CREATED"),
|
||||||
|
value: `<t:${r.createdAt}:f>`,
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: client.translate("general/remindme:EMBED_TIME"),
|
||||||
|
value: `<t:${r.sendAt}:f>`,
|
||||||
|
inline: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: client.translate("common:MESSAGE"),
|
||||||
|
value: r.message,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
cachedUser
|
||||||
|
.send({
|
||||||
|
embeds: [embed],
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
client.adapter.updateOne(UserModel, { id: user.id }, { $pull: { reminds: { _id: r._id } } });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
user.reminds = user.reminds.filter(r => r.sendAt >= Math.floor(Date.now() / 1000));
|
||||||
|
|
||||||
|
await user.save();
|
||||||
|
|
||||||
|
if (!user.reminds.length) client.cacheReminds.delete(user.id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
schedule: "* * * * * *",
|
||||||
|
};
|
61
src/services/cron/index.js
Normal file
61
src/services/cron/index.js
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import { CronJob } from "cron";
|
||||||
|
import logger from "../../helpers/logger.js";
|
||||||
|
|
||||||
|
export class CronManager {
|
||||||
|
constructor(tasks) {
|
||||||
|
this.tasks = tasks;
|
||||||
|
this.jobs = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
if (!this.tasks.length) {
|
||||||
|
logger.warn("No cron tasks to schedule.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const task of this.tasks) {
|
||||||
|
const taskJob = this.jobs.get(task.name);
|
||||||
|
if (taskJob?.isRunning) {
|
||||||
|
logger.warn(`Cron task "${task.name}" is already running.`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const job = new CronJob(
|
||||||
|
task.schedule,
|
||||||
|
async () => {
|
||||||
|
if (this.jobs.get(task.name)?.isError) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await task.task();
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`Error executing cron task "${task.name}":`, error);
|
||||||
|
this.jobs.get(task.name).isError = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
"Europe/Moscow",
|
||||||
|
);
|
||||||
|
|
||||||
|
job.start();
|
||||||
|
this.jobs.set(task.name, {
|
||||||
|
job,
|
||||||
|
isRunning: true,
|
||||||
|
isError: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
logger.log(`Cron tasks scheduled: ${this.jobs.size}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
stopAll() {
|
||||||
|
if (!this.jobs.length) return;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
for (const [_, jobInfo] of this.jobs.entries()) {
|
||||||
|
jobInfo.job.stop();
|
||||||
|
}
|
||||||
|
logger.log("All cron jobs stopped.");
|
||||||
|
}
|
||||||
|
}
|
41
src/utils/loadCronTasks.js
Normal file
41
src/utils/loadCronTasks.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import logger from "../helpers/logger.js";
|
||||||
|
import { getFilePaths } from "./get-path.js";
|
||||||
|
import { toFileURL } from "./resolve-file.js";
|
||||||
|
|
||||||
|
const loadCronTasks = async taskPath => {
|
||||||
|
try {
|
||||||
|
const filePaths = (await getFilePaths(taskPath, true)).filter(file => file.endsWith(".js"));
|
||||||
|
|
||||||
|
const tasks = [];
|
||||||
|
|
||||||
|
for (const filePath of filePaths) {
|
||||||
|
const { data } = await import(toFileURL(filePath));
|
||||||
|
|
||||||
|
if (!data) continue;
|
||||||
|
|
||||||
|
if (!data.name) {
|
||||||
|
logger.warn("No name found in task:", filePath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.schedule) {
|
||||||
|
logger.warn("No schedule found in task:", filePath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof data.task !== "function") {
|
||||||
|
logger.warn("Task is not a function:", filePath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.push(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tasks;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error("Error loading cron tasks:", error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default loadCronTasks;
|
Loading…
Reference in a new issue