3
0
Fork 0
mirror of https://github.com/ZeppelinBot/Zeppelin.git synced 2025-06-15 10:45:01 +00:00
zeppelin/backend/src/data/loops/expiringMutesLoop.ts

112 lines
3.8 KiB
TypeScript

// tslint:disable:no-console
import moment from "moment-timezone";
import { lazyMemoize, MINUTES, SECONDS } from "../../utils.js";
import { Mute } from "../entities/Mute.js";
import { emitGuildEvent, hasGuildEventListener } from "../GuildEvents.js";
import { Mutes, TIMEOUT_RENEWAL_THRESHOLD } from "../Mutes.js";
import Timeout = NodeJS.Timeout;
const LOOP_INTERVAL = 15 * MINUTES;
const MAX_TRIES_PER_SERVER = 3;
const getMutesRepository = lazyMemoize(() => new Mutes());
const timeouts = new Map<string, Timeout>();
function muteToKey(mute: Mute) {
return `${mute.guild_id}/${mute.user_id}`;
}
async function broadcastExpiredMute(guildId: string, userId: string, tries = 0): Promise<void> {
const mute = await getMutesRepository().findMute(guildId, userId);
if (!mute) {
// Mute was already cleared
return;
}
if (!mute.expires_at || moment(mute.expires_at).diff(moment()) > 10 * SECONDS) {
// Mute duration was changed and it's no longer expiring now
return;
}
// console.log(`[EXPIRING MUTES LOOP] Broadcasting expired mute: ${mute.guild_id}/${mute.user_id}`);
if (!hasGuildEventListener(mute.guild_id, "expiredMute")) {
// If there are no listeners registered for the server yet, try again in a bit
if (tries < MAX_TRIES_PER_SERVER) {
timeouts.set(
muteToKey(mute),
setTimeout(() => broadcastExpiredMute(guildId, userId, tries + 1), 1 * MINUTES),
);
}
return;
}
emitGuildEvent(mute.guild_id, "expiredMute", [mute]);
}
function broadcastTimeoutMuteToRenew(mute: Mute, tries = 0) {
// console.log(`[EXPIRING MUTES LOOP] Broadcasting timeout mute to renew: ${mute.guild_id}/${mute.user_id}`);
if (!hasGuildEventListener(mute.guild_id, "timeoutMuteToRenew")) {
// If there are no listeners registered for the server yet, try again in a bit
if (tries < MAX_TRIES_PER_SERVER) {
timeouts.set(
muteToKey(mute),
setTimeout(() => broadcastTimeoutMuteToRenew(mute, tries + 1), 1 * MINUTES),
);
}
return;
}
emitGuildEvent(mute.guild_id, "timeoutMuteToRenew", [mute]);
}
export async function runExpiringMutesLoop() {
console.log("[EXPIRING MUTES LOOP] Clearing old timeouts");
for (const timeout of timeouts.values()) {
clearTimeout(timeout);
}
console.log("[EXPIRING MUTES LOOP] Clearing old expired mutes");
await getMutesRepository().clearOldExpiredMutes();
console.log("[EXPIRING MUTES LOOP] Setting timeouts for expiring mutes");
const expiringMutes = await getMutesRepository().getSoonExpiringMutes(LOOP_INTERVAL);
for (const mute of expiringMutes) {
const remaining = Math.max(0, moment.utc(mute.expires_at!).diff(moment.utc()));
timeouts.set(
muteToKey(mute),
setTimeout(() => broadcastExpiredMute(mute.guild_id, mute.user_id), remaining),
);
}
console.log("[EXPIRING MUTES LOOP] Broadcasting timeout mutes to renew");
const timeoutMutesToRenew = await getMutesRepository().getTimeoutMutesToRenew(TIMEOUT_RENEWAL_THRESHOLD);
for (const mute of timeoutMutesToRenew) {
broadcastTimeoutMuteToRenew(mute);
}
console.log("[EXPIRING MUTES LOOP] Scheduling next loop");
setTimeout(() => runExpiringMutesLoop(), LOOP_INTERVAL);
}
export function registerExpiringMute(mute: Mute) {
clearExpiringMute(mute);
if (mute.expires_at === null) {
return;
}
console.log("[EXPIRING MUTES LOOP] Registering new expiring mute");
const remaining = Math.max(0, moment.utc(mute.expires_at).diff(moment.utc()));
if (remaining > LOOP_INTERVAL) {
return;
}
timeouts.set(
muteToKey(mute),
setTimeout(() => broadcastExpiredMute(mute.guild_id, mute.user_id), remaining),
);
}
export function clearExpiringMute(mute: Mute) {
console.log("[EXPIRING MUTES LOOP] Clearing expiring mute");
if (timeouts.has(muteToKey(mute))) {
clearTimeout(timeouts.get(muteToKey(mute))!);
}
}