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

Discord Bot Event Listener: gids voor gateway en intents

Het schrijven van een discord bot event listener is de stap die je bot verandert van een statische commandomachine in een applicatie die in realtime reageert. Discord stuurt alles wat er op een server gebeurt — een verzonden bericht, een lid dat zich aansluit, een toegevoegde reactie — als een event naar je bot via een permanente WebSocket-verbinding. In dit artikel leg ik stap voor stap uit hoe de event-stroom werkt, waarom gateway intents verplicht zijn, en hoe je een solide event listener-structuur opbouwt, allemaal met discord.js.

Wat is de gateway en hoe werkt de event-stroom?

Discord-bots praten eigenlijk via twee aparte kanalen. Acties zoals een bericht sturen of een kanaal aanmaken gebeuren via HTTP-verzoeken naar de REST API. Luisteren naar wat er gebeurt op een server verloopt daarentegen via een permanente WebSocket-verbinding die de Gateway heet.

De stroom verloopt als volgt: wanneer je bot start, maakt hij verbinding met de Gateway en authenticeert hij zich met zijn token (IDENTIFY). Discord verwacht regelmatige heartbeats om er zeker van te zijn dat de verbinding nog leeft. Zodra de verbinding tot stand is gekomen, pusht Discord bij elke gebeurtenis op een server een event-pakket (bijvoorbeeld MESSAGE_CREATE) naar je bot. De bibliotheek vangt dit ruwe pakket op, ontleedt het en activeert de listener-functie die je hebt geregistreerd.

Daarom "stelt een event-gebaseerde bot nooit een vraag en wacht op een antwoord"; in plaats daarvan ontvangt hij events volgens een push-model over een continu open lijn. De architectuur van de bot moet rond deze realiteit worden opgebouwd.

Intents: de sleutel die bepaalt waarnaar je kunt luisteren

Sinds 2020 beperkt Discord via Gateway Intents welke event-types bots ontvangen. Een intent is een toestemmingsvlag die zegt "ik wil events in deze categorie ontvangen". Als je geen events aanvraagt die je niet nodig hebt, daalt zowel het netwerkverkeer als het geheugengebruik; belangrijker nog, je krijgt geen toegang tot irrelevante data.

Als je de intents niet expliciet declareert, bereiken de betreffende events je bot nooit. Het antwoord op de meest gestelde vraag "waarom wordt mijn message-event niet geactiveerd?" is meestal een ontbrekende intent. Sommige intents worden als privileged beschouwd en moeten zowel in het Discord Developer Portal worden ingeschakeld als in de code worden gedeclareerd:

  • GuildMembers — lid dat zich aansluit/vertrekt, ledenlijst (privileged).
  • MessageContent — toegang tot de tekstinhoud van berichten (privileged).
  • GuildPresences — online-status en activiteit (privileged).

Voor bots op meer dan 100 servers moet je een verificatie van Discord verkrijgen voor privileged intents. Daarom is je bot beperken tot de intents die hij echt nodig heeft zowel een goede praktijk als een vereiste om te kunnen schalen.

Je eerste event listener opzetten

Een minimaal bot-skelet met discord.js v14 ziet er zo uit. We maken het Client-object met de vereiste intents en koppelen vervolgens listeners aan events:

const { Client, GatewayIntentBits, Events } = require('discord.js');

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

// Wordt eenmaal geactiveerd zodra de verbinding klaar is
client.once(Events.ClientReady, (c) => {
  console.log(`Ingelogd als: ${c.user.tag}`);
});

// Wordt bij elk nieuw bericht geactiveerd
client.on(Events.MessageCreate, (message) => {
  if (message.author.bot) return;            // negeer berichten van bots
  if (message.content === '!ping') {
    message.reply('Pong!');
  }
});

client.login(process.env.DISCORD_TOKEN);

Er zijn hier twee belangrijke verschillen. client.once voert de listener slechts één keer uit — ideaal voor levenscyclus-events die maar één keer plaatsvinden, zoals ClientReady. client.on daarentegen wordt bij elke gebeurtenis opnieuw geactiveerd. De controle message.author.bot voorkomt ook dat bots elkaar in een oneindige lus activeren; dat is een makkelijk over het hoofd geziene maar cruciale beveiliging.

Veelgebruikte events en het juiste gebruik

Een echte bot reageert niet op één event, maar op meerdere tegelijk. De events waarmee je het vaakst werkt zijn:

  • GuildMemberAdd — voor een welkomstbericht of automatische rol wanneer een nieuw lid binnenkomt (vereist de GuildMembers-intent).
  • InteractionCreate — de moderne, aanbevolen route voor slash commands, knoppen en menu's.
  • MessageReactionAdd — voor reaction-role-systemen.
  • GuildCreate — wanneer de bot aan een nieuwe server wordt toegevoegd, voor de installatie.

In moderne bots bouw je de commandologica beter op InteractionCreate en slash commands dan op MessageCreate, omdat MessageContent een privileged intent is en Discord op lange termijn geen commando's op basis van berichtinhoud aanmoedigt.

Je event-structuur schaalbaar houden

Alle listeners in één bestand proppen wordt onbeheersbaar naarmate de bot groeit. Een solide aanpak is het bouwen van een event handler die elk event in een eigen bestand plaatst. Elk bestand exporteert de naam van het event en de uit te voeren functie:

// events/messageCreate.js
const { Events } = require('discord.js');

module.exports = {
  name: Events.MessageCreate,
  once: false,
  execute(message) {
    if (message.author.bot) return;
    // ... logica
  },
};
// het deel dat de listeners automatisch laadt
const fs = require('node:fs');
const path = require('node:path');

const eventsPath = path.join(__dirname, 'events');
const files = fs.readdirSync(eventsPath).filter((f) => f.endsWith('.js'));

for (const file of files) {
  const event = require(path.join(eventsPath, file));
  if (event.once) {
    client.once(event.name, (...args) => event.execute(...args));
  } else {
    client.on(event.name, (...args) => event.execute(...args));
  }
}

Dankzij deze structuur is een nieuw event toevoegen zo simpel als een bestand in de map events/ droppen. De code blijft leesbaar, de verantwoordelijkheid van elk event is gescheiden, en debuggen wordt veel eenvoudiger.

Veelgemaakte fouten

De meest voorkomende valkuilen bij event listeners zijn: (1) Ontbrekende intents — de nummer-één reden dat een event niet wordt geactiveerd. (2) Alleen de events kiezen die je echt nodig hebt in plaats van naar te veel te luisteren. (3) Fouten niet opvangen bij het await-en van netwerkverzoeken binnen een listener; één enkele niet-afgehandelde fout kan de bot laten crashen. Listeners in een try/catch wikkelen en de bot onder een process manager (zoals PM2) draaien verbetert de stabiliteit in productie merkbaar.

Veelgestelde vragen

Is de intent in de code toevoegen op zichzelf voldoende?

Voor privileged intents niet. Je moet MessageContent, GuildMembers en GuildPresences in de code declareren én ze inschakelen in de botinstellingen op het Discord Developer Portal. Als er één ontbreekt, komen de events niet aan.

Wat is het verschil tussen client.on en client.once?

client.on voert de listener uit bij elke herhaling van het event; client.once voert hem alleen de eerste keer uit en verwijdert daarna automatisch de listener. Voor een eenmalig event zoals ClientReady is once de juiste keuze.

De berichtinhoud komt leeg terug — waarom?

Hoogstwaarschijnlijk ontbreekt de MessageContent-intent. Zonder deze privileged intent komt message.content leeg binnen; de inhoud is alleen gevuld voor berichten waarin de bot wordt vermeld of die DM's zijn.

Wil je een solide event-architectuur voor je bot? Van gateway intents tot een schaalbare handler-structuur, ik ontwikkel Discord-bots van begin tot eind. Om je project te bespreken, neem contact met me op.

Bu kategorideki tüm yazılar →

Devamı için