All posts
engineeringfrontend

Alle unsere Discord-Aktivitäten auf einmal zeigen: die Live-Präsenz fixen

Unsere Team-Seite zeigt in Echtzeit genau, was wir alle gerade auf Discord machen. Egal ob wir in VSCode grinden, zocken oder zu Spotify jammen. Sie läuft über Lanyard auf einer WebSocket-Verbindung. Aber ehrlich gesagt waren drei Dinge komplett kaputt, und sie zu fixen war am Ende viel spannender, als wir erwartet hatten.

1. Es zeigte immer nur eine Aktivität

Discord erlaubt mehrere gleichzeitig laufende Aktivitäten, zum Beispiel VSCode offen und nebenbei Spotify. Vorher hat unsere Seite einfach die erste genommen, die sie fand, und den Rest ignoriert.

Um das zu beheben, haben wir aufgehört, nach einer "primären" Aktivität zu suchen. Stattdessen rendern wir einfach die ganze Liste. Spotify bekam eine eigene Zeile (mit Albumcover, Titel und Künstler), und alle anderen Spiele und Apps stapeln wir direkt darunter.

2. Es brach komplett, wenn man wegklickte und zurückkam

Das war der lustige Teil. Unser Präsenz-Client ist ein Singleton mit einem einzigen WebSocket. Wenn man die /team-Seite verließ und wieder zurückklickte, hat React die Komponente neu gemountet und die Socket-Verbindung restlos zerstört, um eine neue zu öffnen.

Der Haken? Der onclose-Handler des alten Sockets feuerte im Hintergrund immer noch und setzte den neuen Socket, den wir gerade gebaut hatten, auf null.

So haben wir es gefixt: wir haben jeden Handler an die konkrete Socket-Instanz gebunden, zu der er gehört, und ihm gesagt, abzubrechen, wenn es nicht der aktuelle ist.

ws.onclose = () => {
  if (ws !== this.ws) return; // veralteter Socket - ignorieren
  this.reconnect();
};

Außerdem holen wir bei jeder frischen Verbindung die Anfangsdaten vom REST-Endpoint, damit die Seite nicht einfach ein paar Sekunden völlig leer dasteht, während das Gateway seinen Handshake macht.

3. Das Spotify-Albumcover wollte einfach nicht laden

Discord-Präsenz-Assets kommen in drei verschiedenen URL-Formaten, und man muss Code schreiben, der erkennt, welches welches ist:

Asset-PräfixWohin es tatsächlich zeigt
mp:...media.discordapp.net/...
spotify:...i.scdn.co/image/...
rohe Snowflake-IDcdn.discordapp.com/app-assets/{appId}/{id}

Die Bild-URLs selbst waren völlig in Ordnung. Es stellte sich heraus, dass uns unsere Content-Security-Policy (CSP) einfach geröstet hat. Unsere img-src-Regeln erlaubten i.scdn.co nicht, also blockierte der Browser Spotifys CDN still und leise, ohne uns etwas zu sagen. Wir haben es auf die Allow-List gesetzt, und das Albumcover lud endlich überall.

Das Fazit

Echtzeit-UI hat zwei riesige Fallen: Komponenten-Lebenszyklen (Sockets, die länger leben als die eigentliche Seite) und Vertrauensgrenzen (CSP, die willkürlich Drittanbieter-Assets verschluckt).

Das Schlimmste ist, dass keine von beiden einen lauten Fehler in deiner Konsole wirft. Deine UI wird einfach zum Geist und zeigt eine leere Karte. Prüfe definitiv zuerst diese beiden, wenn deine Sockets sich komisch verhalten!