Umstellung von JSON auf MsgPack in einer rückwärtskompatiblen Weise mit Paho MQTT (JavaScript)

picockpit.de macht viel Gebrauch von MQTT. Für die kommende Version 2.0 habe ich beschlossen, auf MsgPack umzustellen.

Warum MsgPack?

MsgPack (eigentlich genannt MessagePack - Pakete neigen dazu, MsgPack zu verwenden) ist ein binäres Format, das auf Kompatibilität mit JSON abzielt, aber die Dateigröße verringert (was gut für die Einsparung von Bandbreite und Serverressourcen ist).

Ein weiterer Vorteil: MessagePack ermöglicht die Einbettung von Binärdaten (es sind einige spannende Anwendungsfälle für PiCockpit v2.1+ geplant).

Im Vergleich zu anderen binären Serialisierungsformaten (z.B. BSON) zielt MsgPack auf mehr Kompatibilität mit JSON ab und ist kompakter, und kann als Strom dekodiert werden!

Zurückgehaltene Nachrichten aus der Vergangenheit

Da die aufbewahrten Nachrichten immer noch in JSON vorliegen (und auch ältere Clients immer noch JSON-Nachrichten senden), muss jedoch Abwärtskompatibilität gewährleistet sein, insbesondere auf der JavaScript-Seite.

Wird die Abwärtskompatibilität nicht gewährleistet, führt dies zu folgenden Problemen mit Paho

onConnectFailure;MQTT-Verbindung fehlgeschlagen (5): AMQJS0005E Interner Fehler. Fehlermeldung: AMQJS0009E Missgebildete UTF-Daten:ad -4f ., Stack trace: Kein Fehlerstapel verfügbar

onConnectFailure;MQTT-Verbindung fehlgeschlagen (5): AMQJS0005E Interner Fehler. Fehlermeldung: Extra 231 Byte(s) bei buffer[1] gefunden, Stack trace: Kein Fehlerstapel verfügbar

Kodierung für Fallback zu JSON

Paho gibt uns keinen Zugang zu den Nachrichtendaten selbst, die es in seinen Strukturen hat (siehe Paho-Code hier).

Daher können wir auf das Abfangen von Ausnahmen zurückgreifen, wobei wir davon ausgehen, dass die Nachricht höchstwahrscheinlich im MsgPack-Format vorliegt, und wenn die Dekodierung fehlschlägt, zu JSON wechseln.

Und wenn die Dekodierung von JSON fehlschlägt, bieten wir einen {} Fallback gegen Fuzzing:

extractMessage(message){
     // 20.7.2020: Wechsel zu msgPack; muss payloadBytes sein, nicht payloadString
     var decodedMessage = {};
     versuchen {
         decodedMessage = decode(message.payloadBytes);
     }
     catch (e){
         console.log("Dekodierfehler aufgetreten");
         console.log(e);
         versuchen {
             decodedMessage = JSON.parse(message.payloadString);
         }
         catch (e){
             console.log("missgebildete Nachricht (weder JSON noch MsgPack) - Interpretation als leeres Objekt {}");
         }
     }
     return decodedMessage;
     // return JSON.parse(message.payloadString);
}

Bild

  • Beachten Sie, dass wir payloadBytes verwenden, um auf die Nachricht für msgPack zuzugreifen, und payloadString für die JSON-Dekodierung
  • beachten Sie, dass decode (und encode) wie folgt enthalten sind: importiere { encode, decode } von "@msgpack/msgpack"; in meinem Webpack-Workflow

Referenzen