aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Discord-bots

Discord-bot cooldown en spambeveiliging-gids

Naarmate een Discord-bot groeit, is een van de meest voorkomende problemen het overspoelen van commando's: een gebruiker triggert hetzelfde commando tientallen keren per seconde, en de bot antwoordt elke keer opnieuw. Een degelijk Discord-bot cooldown-systeem is precies wat dit oplost; het geeft elke gebruiker een korte wachttijd voordat hij een commando opnieuw kan uitvoeren, en beschermt zowel je bot als de API-limieten van Discord. In deze gids bouwen we de cooldown-logica vanaf nul, schrijven we een werkend discord.js-voorbeeld en voegen we extra lagen toe tegen spam.

Waarom je cooldowns en spambeveiliging nodig hebt

Een cooldown is niet alleen een functie om "de gebruiker af te remmen"; het is een verdedigingslinie voor de stabiliteit van je bot. De belangrijkste redenen:

  • API-rate limits: Discord beperkt hoeveel verzoeken een bot mag versturen. Als je te veel berichten/antwoorden stuurt, krijg je een 429 Too Many Requests-antwoord en een tijdelijke blokkade.
  • Resourceverbruik: dure commando's zoals een databasequery, een externe API-aanroep of beeldgeneratie kunnen je server vastzetten onder spam.
  • Misbruik: zonder cooldowns worden economie-, giveaway- of beloningscommando's uitgebuit.
  • Kanaalvervuiling: herhaalde botantwoorden maken kanalen onleesbaar.

De cooldown-logica: een tijdstempel opslaan

Elk cooldown-systeem is gebouwd op één idee: opslaan wanneer een gebruiker het commando voor het laatst uitvoerde en controleren of er genoeg tijd is verstreken. De pseudocode werkt zo:

  • De gebruiker voert het commando uit.
  • Controleer of er een opgeslagen tijdstempel is voor die gebruiker.
  • Als die er is en (nu - opgeslagen) < cooldown: weiger en vermeld de resterende tijd.
  • Anders: voer het commando uit en sla een nieuw tijdstempel op.

Voor opslag is geheugen (een Map) voldoende voor kleine bots. Als je niet wilt dat cooldowns resetten wanneer de bot herstart, gebruik dan Redis of een database.

Een cooldown-systeem per commando met discord.js

In discord.js v14 is de gangbare en officieel aanbevolen aanpak voor slash-commando's om per commando een aparte Collection bij te houden. Collection breidt de Map-klasse van JavaScript uit. Je kunt een optioneel cooldown-veld toevoegen aan je commandobestand:

// commands/ping.js
const { SlashCommandBuilder } = require('discord.js');

module.exports = {
  cooldown: 5, // seconden
  data: new SlashCommandBuilder()
    .setName('ping')
    .setDescription('Toont de latentie van de bot'),
  async execute(interaction) {
    await interaction.reply(`Pong! ${interaction.client.ws.ping}ms`);
  },
};

De eigenlijke controle gebeurt in de interactionCreate-gebeurtenis, voordat het commando draait:

// events/interactionCreate.js
const { Events, Collection } = require('discord.js');

module.exports = {
  name: Events.InteractionCreate,
  async execute(interaction) {
    if (!interaction.isChatInputCommand()) return;

    const command = interaction.client.commands.get(interaction.commandName);
    if (!command) return;

    const { cooldowns } = interaction.client;
    if (!cooldowns.has(command.data.name)) {
      cooldowns.set(command.data.name, new Collection());
    }

    const now = Date.now();
    const timestamps = cooldowns.get(command.data.name);
    const cooldownAmount = (command.cooldown ?? 3) * 1000;

    if (timestamps.has(interaction.user.id)) {
      const expiration = timestamps.get(interaction.user.id) + cooldownAmount;
      if (now < expiration) {
        const expiredTimestamp = Math.round(expiration / 1000);
        return interaction.reply({
          content: `Wacht even voordat je dit commando opnieuw gebruikt. Je kunt het <t:${expiredTimestamp}:R> weer gebruiken.`,
          ephemeral: true,
        });
      }
    }

    timestamps.set(interaction.user.id, now);
    setTimeout(() => timestamps.delete(interaction.user.id), cooldownAmount);

    try {
      await command.execute(interaction);
    } catch (error) {
      console.error(error);
    }
  },
};

Vergeet niet de client.cooldowns-collectie één keer te definiëren bij het opstarten: voeg client.cooldowns = new Collection(); toe wanneer je je client instelt. <t:...:R> is Discords relatieve tijdstempelformaat en toont de gebruiker een automatisch bijgewerkte tekst zoals "over 3 seconden".

Cooldown-typen: gebruiker, server en globaal

Het bovenstaande voorbeeld past een cooldown per gebruiker toe, wat de meest voorkomende behoefte is. Maar verschillende scenario's vereisen verschillende sleutels:

  • Per gebruiker: gebruik interaction.user.id als sleutel. Ideaal voor persoonlijke commando's (profiel, saldo).
  • Per server: gebruik interaction.guildId als sleutel. Zinvol voor commando's die de hele server raken (aankondigingen, bulkbewerkingen).
  • Per kanaal: beperk specifieke kanalen met interaction.channelId.
  • Globaal: gebruik een vaste sleutel (bijv. de commandonaam) voor commando's die een dure externe API beschermen.

Je kunt dezelfde logica hergebruiken door alleen te wijzigen welk veld je als sleutel opslaat. Om meerdere typen te combineren, bouw je een samengestelde sleutel: `${interaction.guildId}-${interaction.user.id}`.

Discords eigen rate limits (429) en discord.js

Je eigen cooldown voorkomt dat gebruikers de bot spammen; maar de bot zelf is ook onderworpen aan limieten tegenover de Discord-API. Het goede nieuws: de @discordjs/rest-laag onder discord.js beheert globale en route-gebaseerde rate limits automatisch, plaatst verzoeken in de wachtrij en wacht bij een 429. Toch zijn er punten die je moet weten:

  • Stuur geen honderden berichten in een lus; batch de bewerkingen of voeg een vertraging in.
  • Het gebruik van ephemeral: true bij tijdelijke antwoorden (alleen zichtbaar voor degene die het commando uitvoerde) vermindert kanaalvervuiling en onnodig berichtenverkeer.
  • Roep voor langlopend werk eerst interaction.deferReply() aan; anders loop je tegen de interactie-time-out van 3 seconden aan.
  • Als je toch een globale rate limit raakt, luister dan naar de rateLimited-gebeurtenis om het te loggen en je verzoekvolume te verlagen.

Extra maatregelen tegen spam

Een cooldown is de eerste verdedigingslinie; tegen agressief misbruik voeg je deze lagen toe:

  • Oplopende straf: verhoog tijdelijk de wachttijd voor een gebruiker die herhaaldelijk tegen de cooldown aanloopt.
  • Volglijst: negeer een gebruiker korte tijd zodra hij een drempel aan commandopogingen overschrijdt (een eenvoudige rate limiter).
  • Permissiecontrole: voeg een interaction.memberPermissions-controle toe om beheerders vrij te stellen van cooldowns.
  • Persistente opslag: bewaar cooldowns in Redis of een database voor belonings-/economiecommando's zodat ze na een herstart niet misbruikt kunnen worden.

Veelgestelde vragen

Is het veilig om cooldown-gegevens in het geheugen te bewaren?

Voor kleine en middelgrote bots is geheugen (een Collection/Map) snel en voldoende. Het reset echter elke keer dat de bot herstart. Voor misbruikgevoelige commando's zoals giveaways, beloningen of economie raad ik aan cooldowns persistent op te slaan in Redis of een database.

Als discord.js de rate limits voor mij afhandelt, waarom dan toch een cooldown schrijven?

Ze dienen verschillende doelen. De REST-laag van discord.js reguleert de verzoeken die de bot naar Discord stuurt. Jouw cooldown bepaalt hoe vaak gebruikers de bot kunnen triggeren; die logica voorkomt spam, resourceverbruik en misbruik van spelmechanieken.

Geldt dezelfde logica voor discord.py?

Ja, het principe is identiek: sla het laatste gebruiksmoment op en controleer het verschil. discord.py heeft daarnaast een ingebouwde @commands.cooldown-decorator en BucketType-opties, waarmee je een cooldown per gebruiker/server/kanaal in één regel kunt definiëren.

Bezwijkt je bot onder spam? Ik kan je helpen hem te verstevigen met commando-cooldowns, rate-limitbeheer en een misbruikbestendige architectuur. Neem contact op en laten we over je project praten.

Bu kategorideki tüm yazılar →

Devamı için