Zrzur Entwickler

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-ParameterWerteStandard
version11
formatjson, msgpackjson
tokendein Bot-Token, statt Authenticatekeiner
intentsdie Summe deiner Intents, statt des Felds in Authenticatesiehe unten
readyFelder für Ready, z. B. ready=servers&ready=channelsalles

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:

  1. Authenticated: Das Token ist gut.
  2. 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 bekommstUrsacheWas zu tun ist
{ "type": "Error", "data": { "type": "InvalidSession" } }, schließtFalsches oder zurückgesetztes Token, gesperrter Bot, oder kein Authenticate in 15 SekundenStoppe. Verbinde nicht in einer Schleife neu
{ "type": "Error", "data": { "type": "MissingIntent", "intent": "SERVER_MEMBERS" } }, schließt mit Code 4014Ein 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 1013Der Server konnte die Einstellungen des Bots in dem Moment nicht lesenVerbinde 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.

  1. 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.
  2. Verbinde dich und sende Resume, wenn die Sitzung fortsetzbar war (siehe Fortsetzen nach einem Abbruch), sonst Authenticate. Nach Authenticate bekommst du ein neues Ready.
  3. Setze die Wartezeit nach Ready oder Resumed zurück.
  4. Wiederhole nicht nach einem Error-Ereignis vom Typ InvalidSession und nicht nach Code 4014: Dieselbe Anfrage scheitert wieder. Stoppe und sage einem Menschen Bescheid. Nach Code 1013 wiederhole: 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 bekommstBedeutungWas zu tun ist
Die verpassten Ereignisse der Reihe nach, dann ResumedDie Sitzung läuft weiter. Es kommt kein neues ReadyMach weiter und zähle seq weiter
{ "type": "InvalidSession", "resumable": false }Die Sitzung ist weg, oder das Verpasste passt nicht mehr in das AufbewahrteSende 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

MessageFields
Authenticatetoken, intents, resumableDeine 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.
Resumetoken, session_id, seqDie 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.
BeginTypingchannelZeigt den Bot als tippend in channel. Sende es alle paar Sekunden neu, damit die Anzeige bleibt.
EndTypingchannelBeendet die Tipp-Anzeige in channel.
Subscribeserver_idFordert Präsenz- und Mitgliederupdates von server_id an. Bots brauchen dafür SERVER_MEMBERS oder PRESENCE.
Pingdata, respondedPrü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.

IntentWertEmpfängt
SERVERS1Server-, 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_MESSAGES2Nachrichten und Tippen in Serverkanälen
DIRECT_MESSAGES4Nachrichten und Tippen in Direktnachrichten und Gruppen
REACTIONS8Reaktionen, die hinzukommen oder wegfallen
VOICE_STATES16Beitritte und Austritte in Sprachkanälen, Anrufe, Änderungen einer Bühne, abgespielte Soundboard-Sounds, Sprachstatus in Ready
INTERACTIONS32InteractionCreate
MESSAGE_CONTENT1024Privilegiert. Text, Embeds, Dateien und Komponenten von Nachrichten
SERVER_MEMBERS2048Privilegiert. Beitritte, Austritte und Änderungen von Mitgliedern; die Mitgliederliste
PRESENCE4096Privilegiert. 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:

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.

Weiter