Kord/src/services/WebhookService.ts

62 lines
2.2 KiB
TypeScript

import { TextChannel, WebhookClient } from 'discord.js';
import { logger } from '../utils/logger';
export class WebhookService {
private static readonly MAX_WEBHOOKS = 10;
private static readonly WEBHOOK_NAME = 'Kord Mimic Webhook';
private static readonly WEBHOOK_CACHE_TTL_MS = 86400 * 1000;
private static readonly webhookCache = new Map<
string,
{ id: string; token: string; expiresAt: number }
>();
public static async getWebhookClient(channel: TextChannel): Promise<WebhookClient | null> {
try {
const now = Date.now();
const cached = this.webhookCache.get(channel.id);
if (cached && now < cached.expiresAt) {
return new WebhookClient({ id: cached.id, token: cached.token });
}
// 2. Fetch from Discord API
const webhooks = await channel.fetchWebhooks();
let kordWebhook = webhooks.find(wh => wh.name === this.WEBHOOK_NAME && wh.token !== null);
if (!kordWebhook) {
if (webhooks.size >= this.MAX_WEBHOOKS) {
// If we hit limits, delete the oldest webhook
const oldestWebhook = webhooks.last();
if (oldestWebhook) {
await oldestWebhook.delete('Hit max webhook limit for Kord');
logger.warn(`Deleted oldest webhook in channel ${channel.id}`);
} else {
logger.error(`Webhook limits reached in ${channel.id} but no webhook could be deleted.`);
return null;
}
}
kordWebhook = await channel.createWebhook({
name: this.WEBHOOK_NAME,
avatar: channel.client.user?.displayAvatarURL(),
reason: 'Webhook needed for Kord Mimic & Prank feature',
});
logger.info(`Created new webhook for channel ${channel.id}`);
}
if (kordWebhook.token) {
this.webhookCache.set(channel.id, {
id: kordWebhook.id,
token: kordWebhook.token,
expiresAt: Date.now() + this.WEBHOOK_CACHE_TTL_MS,
});
return new WebhookClient({ id: kordWebhook.id, token: kordWebhook.token });
}
return null;
} catch (error) {
logger.error(`WebhookService Error on channel ${channel.id}:`, error);
return null;
}
}
}