Gateway
Das Gateway ist ein WebSocket, der Ereignisse an deinen Bot schickt. Halte pro Bot-Prozess eine Verbindung offen.
Das brauchst du
Node 22 oder neuer hat WebSocket eingebaut. Jeder WebSocket-Client geht. Du brauchst dein Bot-Token (YOUR_BOT_TOKEN).
Verbinden
wss://events.zrzur.com/?version=1&format=json| Query-Parameter | Werte | Standard |
|---|---|---|
version | 1 | 1 |
format | json, msgpack | json |
token | dein Bot-Token, statt Authenticate | keiner |
intents | die Summe deiner Intents, statt des Felds in Authenticate | siehe unten |
ready | Felder für Ready, z. B. ready=servers&ready=channels | alles |
Mit format=msgpack senden beide Seiten binäre Frames.
Nimm lieber Authenticate als ?token=: Adressen landen in Logs. Sende es innerhalb von 15 Sekunden:
{ "type": "Authenticate", "token": "YOUR_BOT_TOKEN", "intents": 33 }Der Server antwortet in dieser Reihenfolge:
Authenticated: Das Token ist gut.Ready: deine Startdaten. Erst danach fließen Ereignisse.
Alles, was du sonst sendest, ist auf 1 MiB pro Nachricht begrenzt.
Wenn das Gateway dich abweist
| Was du bekommst | Ursache | Was zu tun ist |
|---|---|---|
{ "type": "Error", "data": { "type": "InvalidSession" } }, schließt | Falsches oder zurückgesetztes Token, gesperrter Bot, oder kein Authenticate in 15 Sekunden | Stoppe. Verbinde nicht in einer Schleife neu |
{ "type": "Error", "data": { "type": "MissingIntent", "intent": "SERVER_MEMBERS" } }, schließt mit Code 4014 | Ein privilegierter Intent ist aus. Der Schließgrund nennt ihn, zum Beispiel Disallowed intents: MESSAGE_CONTENT (switched on: none) | Schalte ihn im Entwicklerportal ein und verbinde dich neu, oder verbinde dich ohne ihn |
{ "type": "Error", "data": { "type": "InternalError" } }, schließt mit Code 1013 | Der Server konnte die Einstellungen des Bots in dem Moment nicht lesen | Verbinde dich neu, mit der Wartezeit aus Neu verbinden |
Verbunden bleiben
Sende alle 20 Sekunden ein Ping:
{ "type": "Ping", "data": 1730000000000 }Der Server antwortet Pong mit denselben data. data ist eine Zahl oder eine Liste von Bytes.
Das Zrzur-Gateway selbst schließt eine stille Bot-Verbindung nie, aber Proxys und Heimrouter tun es, und eine tote Leitung meldet sich nicht. Der Ping ist also, wie du es merkst: Kam 60 Sekunden kein Pong, schließe den Socket und verbinde neu.
Neu verbinden
Eine Verbindung kann jederzeit enden: ein Update bei uns, ein Netzproblem, dein Laptop schläft ein. Plane dafür.
- Wenn der Socket schließt, warte 1 Sekunde und verdopple die Wartezeit nach jedem Fehlschlag bis 30 Sekunden. Füge etwas Zufall hinzu, damit nicht viele Bots gleichzeitig zurückkommen.
- Verbinde dich und sende
Resume, wenn die Sitzung fortsetzbar war (siehe Fortsetzen nach einem Abbruch), sonstAuthenticate. NachAuthenticatebekommst du ein neuesReady. - Setze die Wartezeit nach
ReadyoderResumedzurück. - Wiederhole nicht nach einem
Error-Ereignis vom TypInvalidSessionund nicht nach Code4014: Dieselbe Anfrage scheitert wieder. Stoppe und sage einem Menschen Bescheid. Nach Code1013wiederhole: Der Server konnte die Einstellungen des Bots in dem Moment nicht lesen.
Fortsetzen nach einem Abbruch
Eine Sitzung kann dort weitermachen, wo sie aufgehört hat. Bei einem kurzen Abbruch geht so nichts verloren. Fordere das beim Authentifizieren an:
{
"type": "Authenticate",
"token": "YOUR_BOT_TOKEN",
"intents": 33,
"resumable": true
}Ready enthält dann session_id. Jedes Paket nach Ready trägt seq, pro Sitzung ab 1 gezählt: Merke dir die letzte Nummer, die du verarbeitet hast. Ein Bulk-Paket hat ein seq, seine Einträge haben keins. Authenticated, Ready, Pong, Error, InvalidSession und Resumed haben kein seq.
Nach einem Abbruch behält das Gateway die Sitzung 2 Minuten, mit höchstens ihren letzten 1000 Ereignissen und 4 MiB davon. Öffne einen neuen Socket und sende das als erste Nachricht, statt Authenticate:
{
"type": "Resume",
"token": "YOUR_BOT_TOKEN",
"session_id": "YOUR_SESSION_ID",
"seq": 41
}| Was du bekommst | Bedeutung | Was zu tun ist |
|---|---|---|
Die verpassten Ereignisse der Reihe nach, dann Resumed | Die Sitzung läuft weiter. Es kommt kein neues Ready | Mach weiter und zähle seq weiter |
{ "type": "InvalidSession", "resumable": false } | Die Sitzung ist weg, oder das Verpasste passt nicht mehr in das Aufbewahrte | Sende Authenticate auf demselben Socket und hole dann per REST nach |
Eine Wiedergabe kann Lücken in seq haben: Tipp-Ereignisse werden nicht aufbewahrt, und Ereignisse aus Orten, die der Bot nicht mehr sieht, fehlen. Das Gateway behält höchstens 3 abgebrochene Sitzungen pro Bot. Ein zweites abgelehntes Resume auf demselben Socket schließt ihn.
Ohne "resumable": true wird nichts aufbewahrt, und Ereignisse während deiner Abwesenheit sind weg. Hole nach einem neuen Ready per REST, was dein Bot nicht verpassen darf, etwa die neuesten Nachrichten eines Kanals (GET /channels/{target}/messages mit after und sort=Oldest, siehe Nachrichten). Ein Befehl während deiner Abwesenheit scheitert für die Person, und sie kann es erneut versuchen.
Sharding wird nicht unterstützt
Eine Verbindung empfängt alles, was deine Intents abdecken. Server lassen sich nicht auf Verbindungen verteilen. Einen zu groß gewordenen Bot-Prozess kannst du noch nicht teilen; halte die Arbeit pro Ereignis klein und lagere langsame Arbeit in eine Warteschlange aus. Siehe Betrieb in Produktion.
Zwei Verbindungen mit demselben Token funktionieren, und beide empfangen alles. Ein InteractionCreate erreicht dann beide, also betreibe zwei nur während eines Neustarts.
Bulk-Pakete
Mehrere Ereignisse können in einem Paket kommen:
{
"type": "Bulk",
"v": [{ "type": "ServerMemberUpdate" }, { "type": "InteractionCreate" }]
}Packe Bulk immer aus und behandle jedes Ereignis. Ein Bot, der es ignoriert, verpasst Ereignisse, auch Befehle.
Was du senden kannst
| Message | Fields | |
|---|---|---|
Authenticate | token, intents, resumable | Deine erste Nachricht. token ist das Bot-Token, intents die Summe der gewünschten Intents. Mit resumable: true lässt sich die Sitzung nach einem Abbruch fortsetzen, und Ready enthält session_id. |
Resume | token, session_id, seq | Die erste Nachricht auf einem neuen Socket nach einem Abbruch, statt Authenticate. Die Ereignisse nach seq, die du noch sehen darfst, kommen der Reihe nach, dann Resumed. Ist die Sitzung weg, erhältst du InvalidSession. |
BeginTyping | channel | Zeigt den Bot als tippend in channel. Sende es alle paar Sekunden neu, damit die Anzeige bleibt. |
EndTyping | channel | Beendet die Tipp-Anzeige in channel. |
Subscribe | server_id | Fordert Präsenz- und Mitgliederupdates von server_id an. Bots brauchen dafür SERVER_MEMBERS oder PRESENCE. |
Ping | data, responded | Prüft die Leitung. data ist eine Zahl deiner Wahl und kommt in Pong zurück. |
Intents
Intents legen fest, was eine Verbindung empfängt. Das Gateway wendet sie an, also bekommt ein Bot nie, was er nicht angefordert hat. Addiere die Zahlen der gewünschten und sende die Summe. Ohne intents bekommt der Bot alle freien Intents, 63.
| Intent | Wert | Empfängt |
|---|---|---|
SERVERS | 1 | Server-, Kanal-, Rollen-, Emoji- und Webhook-Ereignisse; Server und ihre Kanäle in Ready. Direktnachrichten und Gruppen kommen so oder so, in Ready und als ChannelCreate |
SERVER_MESSAGES | 2 | Nachrichten und Tippen in Serverkanälen |
DIRECT_MESSAGES | 4 | Nachrichten und Tippen in Direktnachrichten und Gruppen |
REACTIONS | 8 | Reaktionen, die hinzukommen oder wegfallen |
VOICE_STATES | 16 | Beitritte und Austritte in Sprachkanälen, Anrufe, Änderungen einer Bühne, abgespielte Soundboard-Sounds, Sprachstatus in Ready |
INTERACTIONS | 32 | InteractionCreate |
MESSAGE_CONTENT | 1024 | Privilegiert. Text, Embeds, Dateien und Komponenten von Nachrichten |
SERVER_MEMBERS | 2048 | Privilegiert. Beitritte, Austritte und Änderungen von Mitgliedern; die Mitgliederliste |
PRESENCE | 4096 | Privilegiert. Wer online ist, und der Status |
Ein Bot, der nur auf Befehle antwortet, braucht SERVERS + INTERACTIONS = 33. Ohne INTERACTIONS hört dein Bot keine Befehle.
Privilegierte Intents werden im Entwicklerportal für den Bot eingeschaltet. Fordert er einen an, der aus ist, schließt die Verbindung mit Code 4014. Über 100 Servern bleiben nur die privilegierten Intents an, die Zrzur genehmigt hat: Die anderen fallen weg, ohne dass die Verbindung schließt, und die REST-Regeln unten gelten.
Dieselben Regeln gelten über REST:
- Ohne
MESSAGE_CONTENThat eine Nachricht weder Text noch Embeds, Dateien oder Komponenten, außer der Bot hat sie geschrieben, wird erwähnt, oder es ist eine Direktnachricht mit ihm. - Ohne
SERVER_MEMBERSantworten Mitgliederliste und -sucheMissingIntent. Ein einzelnes Mitglied (GET /servers/{target}/members/{member}) geht weiterhin. - Ohne
PRESENCEerscheint jeder Benutzer offline und ohne Status. Sich selbst sieht der Bot weiterhin.
Eine Änderung der Intents gilt ab der nächsten Verbindung.
Wenn ein privilegierter Intent aus ist
Ein Schalter im Entwicklerportal ist gespeichert, sobald du ihn umlegst, und das Portal bestätigt es. Das Gateway liest die Schalter, wenn eine Verbindung beginnt; eine offene Verbindung behält also die Intents, mit denen sie begann: Schließe den Socket und verbinde dich neu. Das Token bleibt dasselbe. REST liest sie bei jeder Anfrage, REST-Antworten folgen einem Schalter also sofort.
MissingIntent nennt die Intents, die aus sind. Kommt dein Bot ohne einen aus, verbinde dich ohne ihn neu, statt anzuhalten:
const MESSAGE_CONTENT = 1024;
// SERVERS + SERVER_MESSAGES + DIRECT_MESSAGES + INTERACTIONS + MESSAGE_CONTENT
let intents = 1 + 2 + 4 + 32 + MESSAGE_CONTENT;
function connect() {
const socket = new WebSocket("wss://events.zrzur.com/?version=1&format=json");
socket.addEventListener("open", () =>
socket.send(
JSON.stringify({
type: "Authenticate",
token: process.env.ZRZUR_BOT_TOKEN,
intents,
}),
),
);
socket.addEventListener("message", ({ data }) => {
const event = JSON.parse(data);
if (event.type === "Error" && event.data.type === "MissingIntent")
console.warn(`Switched off in the Developer Portal: ${event.data.intent}`);
});
socket.addEventListener("close", ({ code }) => {
if (code === 4014 && intents & MESSAGE_CONTENT) {
// go on without message text: mentions and direct messages keep theirs
intents &= ~MESSAGE_CONTENT;
connect();
}
});
}
connect();Ohne MESSAGE_CONTENT liest dein Bot weiterhin Nachrichten, die ihn erwähnen, seine eigenen Nachrichten und Direktnachrichten mit ihm. Ergänze für jedes andere Schließen die Schleife aus Neu verbinden.
Maschinenlesbares Schema
GET /gateway/schema auf der API liefert jedes Ereignis (server) und alles, was ein Client senden kann (client), als JSON Schema, zusammen mit den Intents. Es entsteht aus den Typen, die das Gateway nutzt.
Vollständiges Beispiel
Der vollständige Bot hat all das: Intents, Ping, Überwachung, Bulk, wachsende Wartezeit und die zwei Fälle, in denen er stoppt.