Files
var-monorepo/apps/core-server/modules/chron.ts
2026-01-06 03:08:16 +01:00

203 lines
5.4 KiB
TypeScript

import { DISCORD_ROLES, MissionLog, NotificationPayload, prisma } from "@repo/db";
import { io } from "index";
import cron from "node-cron";
import { changeMemberRoles } from "routes/member";
const removeMission = async (id: number, reason: string) => {
const log: MissionLog = {
type: "completed-log",
auto: true,
timeStamp: new Date().toISOString(),
data: {},
};
const updatedMission = await prisma.mission.update({
where: {
id: id,
},
data: {
state: "finished",
missionLog: {
push: log as any,
},
},
});
io.to("dispatchers").emit("new-mission", { updatedMission });
io.to("dispatchers").emit("notification", {
type: "mission-auto-close",
status: "chron",
message: `Einsatz ${updatedMission.publicId} wurde aufgrund ${reason} geschlossen.`,
data: {
missionId: updatedMission.id,
publicMissionId: updatedMission.publicId,
},
} as NotificationPayload);
console.log(`Mission ${updatedMission.id} closed due to inactivity.`);
};
const removeClosedMissions = async () => {
const oldMissions = await prisma.mission.findMany({
where: {
state: "running",
},
});
oldMissions.forEach(async (mission) => {
const lastAlert = (mission.missionLog as unknown as MissionLog[]).find((l) => {
return l.type === "alert-log";
});
const lastAlertTime = lastAlert ? new Date(lastAlert.timeStamp) : null;
const allStationsInMissionChangedFromStatus4to1Or8to1 = mission.missionStationIds.every(
(stationId) => {
const status4Log = (mission.missionLog as unknown as MissionLog[]).findIndex((l) => {
return (
l.type === "station-log" &&
l.data?.stationId === stationId &&
l.data?.newFMSstatus === "4"
);
});
const status8Log = (mission.missionLog as unknown as MissionLog[]).findIndex((l) => {
return (
l.type === "station-log" &&
l.data?.stationId === stationId &&
l.data?.newFMSstatus === "8"
);
});
const status1Log = (mission.missionLog as unknown as MissionLog[]).findIndex((l) => {
return (
l.type === "station-log" &&
l.data?.stationId === stationId &&
l.data?.newFMSstatus === "1"
);
});
const status6Log = (mission.missionLog as unknown as MissionLog[]).findIndex((l) => {
return (
l.type === "station-log" &&
l.data?.stationId === stationId &&
l.data?.newFMSstatus === "6"
);
});
return (
(status4Log !== -1 || status8Log !== -1) &&
(status1Log !== -1 || status6Log !== -1) &&
(status4Log < status1Log ||
status8Log < status1Log ||
status8Log < status6Log ||
status1Log < status6Log)
);
},
);
const missionHasManualReactivation = (mission.missionLog as unknown as MissionLog[]).some(
(l) => l.type === "reopened-log",
);
if (missionHasManualReactivation) return;
if (!lastAlertTime) return;
const lastStatus1or6Log = (mission.missionLog as unknown as MissionLog[])
.filter((l) => {
return (
l.type === "station-log" && (l.data?.newFMSstatus === "1" || l.data?.newFMSstatus === "6")
);
})
.sort((a, b) => new Date(b.timeStamp).getTime() - new Date(a.timeStamp).getTime())[0];
// Case 1: Forgotten Mission, last alert more than 3 Hours ago
const now = new Date();
if (now.getTime() - lastAlertTime.getTime() > 1000 * 60 * 180)
return removeMission(mission.id, "inaktivität");
// Case 2: All stations in mission changed from status 4 to 1/6 or from status 8 to 1/6, Status 1/6 change less more 5 minutes ago
if (
allStationsInMissionChangedFromStatus4to1Or8to1 &&
lastStatus1or6Log &&
now.getTime() - new Date(lastStatus1or6Log.timeStamp).getTime() > 1000 * 60 * 5
)
return removeMission(mission.id, "dem freimelden aller Stationen");
});
};
const removeConnectedAircrafts = async () => {
const connectedAircrafts = await prisma.connectedAircraft.findMany({
where: {
logoutTime: null,
},
});
connectedAircrafts.forEach(async (aircraft) => {
const lastUpdate = new Date(aircraft.lastHeartbeat);
const now = new Date();
if (now.getTime() - lastUpdate.getTime() > 12 * 60 * 60 * 1000) {
await prisma.connectedAircraft.update({
where: { id: aircraft.id },
data: { logoutTime: now },
});
console.log(`Aircraft ${aircraft.id} disconnected due to inactivity.`);
}
});
};
const removePermissionsForBannedUsers = async () => {
const activePenalties = await prisma.penalty.findMany({
where: {
OR: [
{
type: "BAN",
suspended: false,
},
{
type: "TIME_BAN",
suspended: false,
until: {
gt: new Date().toISOString(),
},
},
],
},
include: {
User: {
include: {
DiscordAccount: true,
FormerDiscordAccounts: true,
},
},
},
});
for (const penalty of activePenalties) {
const user = penalty.User;
if (user.DiscordAccount) {
await changeMemberRoles(
user.DiscordAccount.discordId,
[DISCORD_ROLES.PILOT, DISCORD_ROLES.DISPATCHER],
"remove",
);
}
for (const formerAccount of user.FormerDiscordAccounts) {
await changeMemberRoles(
formerAccount.discordId,
[DISCORD_ROLES.PILOT, DISCORD_ROLES.DISPATCHER],
"remove",
);
}
}
};
cron.schedule("*/5 * * * *", async () => {
await removePermissionsForBannedUsers();
});
cron.schedule("*/1 * * * *", async () => {
try {
await removeClosedMissions();
await removeConnectedAircrafts();
} catch (error) {
console.error("Error on cron job:", error);
}
});