Der Admin-Bereich bekommt Reiter. Die Discord-Einstellungen liegen unter „Einstellungen“. Meldungen sind als Embeds formatiert, und die Match-Startmeldung enthält den CSTV-Zugang (Passwort und Adresse).
49 lines
2.0 KiB
JavaScript
49 lines
2.0 KiB
JavaScript
// Meldungen an einen Discord-Webhook, z. B. für Streamer. Fehler werden nur protokolliert
|
|
// und bremsen den Matchablauf nie aus.
|
|
|
|
const WEBHOOK_PATTERN = /^https:\/\/(discord\.com|discordapp\.com)\/api\/webhooks\/\d+\/[\w-]+$/;
|
|
const TIMEOUT_MS = 5000;
|
|
const MAX_LENGTH = 1900;
|
|
|
|
/** Ereignisse, die gemeldet werden können. Alle sind standardmäßig aktiv. */
|
|
export const NOTIFY_EVENTS = [
|
|
{ key: 'veto_start', label: 'Veto gestartet' },
|
|
{ key: 'match_start', label: 'Match gestartet (Aufwärmphase beendet)' },
|
|
{ key: 'map_end', label: 'Map beendet (mit Ergebnis)' },
|
|
{ key: 'series_end', label: 'Serie entschieden' },
|
|
{ key: 'match_closed', label: 'Match abgeschlossen oder abgebrochen' },
|
|
{ key: 'server_error', label: 'Serverfehler' },
|
|
];
|
|
|
|
/**
|
|
* @param {string} url Webhook-URL aus DISCORD_WEBHOOK_URL, leer = keine Meldungen
|
|
* @param {object} options fetchImpl und logger, vor allem für Tests
|
|
*/
|
|
export function createDiscordNotifier(url, { fetchImpl = fetch, logger = console } = {}) {
|
|
if (!url) return { enabled: false, send: async () => false };
|
|
// Die URL enthält ein Geheimnis. Sie wird deshalb nie in Fehlermeldungen ausgegeben.
|
|
if (!WEBHOOK_PATTERN.test(url)) throw new Error('DISCORD_WEBHOOK_URL ist keine gültige Discord-Webhook-URL');
|
|
|
|
return {
|
|
enabled: true,
|
|
/** Liefert true, wenn Discord die Nachricht angenommen hat. */
|
|
async send(message) {
|
|
// Text oder vollständige Discord-Payload (z. B. mit embeds)
|
|
const payload = typeof message === 'string' ? { content: message.slice(0, MAX_LENGTH) } : message;
|
|
try {
|
|
const res = await fetchImpl(url, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(payload),
|
|
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
});
|
|
if (res.ok) return true;
|
|
logger.warn(`Discord-Webhook antwortet mit HTTP ${res.status}`);
|
|
} catch (err) {
|
|
logger.warn(`Discord-Meldung fehlgeschlagen: ${err.name}`);
|
|
}
|
|
return false;
|
|
},
|
|
};
|
|
}
|