Mudar de JSON para MsgPack de forma retrocompatível com Paho MQTT (JavaScript)

picockpit.com faz uso pesado do MQTT. Para a próxima versão 2.0 eu decidi mudá-la para MsgPack.

Porquê MsgPack?

MsgPack (na verdade chamado MessagePack - pacotes tendem a usar o MsgPack) é um formato binário, visando a compatibilidade com o JSON, mas diminuindo o tamanho do arquivo (o que é bom para economizar largura de banda & recursos do servidor).

Outra vantagem: MessagePack permite a incorporação de dados binários (há alguns casos de uso emocionantes planejados para PiCockpit v2.1+).

Em comparação com outros formatos de serialização binária (por exemplo, BSON) o MsgPack visa uma maior compatibilidade com o JSON, é mais compacto, e pode ser descodificado como um fluxo!

Mensagens retidas do passado

Devido às mensagens retidas ainda estarem no JSON (e também clientes antigos que ainda enviam mensagens JSON), no entanto, a compatibilidade retroativa precisa ser fornecida, especialmente no lado JavaScript.

A falta de compatibilidade retroativa levará aos seguintes problemas com o Paho:

onConnectFailure;A conexão MQTT falhou (5): AMQJS0005E Erro interno. Mensagem de erro: AMQJS0009E dados malformados UTF:ad -4f ., Stack trace: Sem pilha de erro disponível

onConnectFailure;A conexão MQTT falhou (5): AMQJS0005E Erro interno. Mensagem de erro: Extra 231 byte(s) encontrado(s) no buffer[1], Stack trace: Sem pilha de erro disponível

Codificação de retorno para o JSON

Paho não nos dá acesso aos dados da mensagem em si (ver Código Paho aqui).

Portanto, podemos voltar à captura de exceções, assumindo que a mensagem provavelmente estará no formato MsgPack, e se a decodificação falhar, mudará para o JSON.

E se a descodificação do JSON falhar, nós damos uma resposta contra o fuzzing:

extractMessage(mensagem){
     // 20.7.2020: mudar para msgPack; tem de ser payloadBytes, não payloadString
     var descodificadoMensagem = {};
     tente {
         decodedMessage = decode(message.payloadBytes);
     }
     catch (e){
         console.log("erro de decodificação detectado");
         console.log(e);
         tente {
             decodedMessage = JSON.parse(message.payloadString);
         }
         catch (e){
             console.log("mensagem mal-formada (nem JSON nem MsgPack) - interpretando como objeto vazio {}");
         }
     }
     devolverMensagem descodificada;
     // devolver JSON.parse(message.payloadString);
}

imagem

  • note que usamos payloadBytes para acessar a mensagem para msgPack, e payloadString para a decodificação do JSON
  • Note que a descodificação (e codificação) está incluída assim: importar { codificar, descodificar } de "@msgpack/msgpack"; no meu Webpack Workflow

Referências