Sincronizar carregamentos de arquivos entre as janelas do navegador

Para PiCockpitEstou actualmente a desenvolver a aplicação Nariz Digital.

Este aplicativo requer um upload para o arquivo de configuração BSEC - que são dados binários.

Uma vez que o usuário carrega o arquivo, ele é publicado via MQTT, e o picockpit-cliente pode usá-lo para configurar o algoritmo BSEC AI para fazer a detecção de gás.

Aqui está uma pequena amostra de parte da webinterface:

imagem

Vuetify navios com um elemento GUI embutido, v-file-input:

<v-file-input
     v-model="bsecFile"
     label="Arquivo de Configuração BSEC do AI Studio (.config)".
     placeholder="Carregue aqui o seu ficheiro de configuração BSEC".
     prepend-icon="mdi-paperclip"
     delineado
     denso
     tamanho do show-size
     accept=".config"
     @change="doUpload
>
</v-file-input>

Neste caso, bsecFile é o meu modelo.

Nota: Como é um modelo, também pode ser escrito para!

Publicação no MQTT

Esta é a aparência do código doUpload (ainda incluindo informações de debug):

    doUpload(){
         console.log("modelo:");
         console.log(este.bsecFile);
         if (this.bsecFile){
             // o código abaixo não funciona de forma fiável, embora em teoria deva
             // if (this.bsecFile.name.split(".")[1] != "config"){
             // console.log("O nome do arquivo não inclui .config - resetting");
             // this.bsecFile = nulo;
             // }
             // senão {
                 console.log("a variável parece estar OK, tentando publicar");
                 var reader = novo FileReader();
                 reader.addEventListener('load', (event) => {
                     console.log("File read successfully! publishing (agora com Uint8Array)");
                     // fn = nome do arquivo, fs = tamanho do arquivo, fd = dados do arquivo (binário)
                     const msg = {
                           fn: este.bsecFile.name,
                           fs: este.bsecFile.tamanho,
                           fd: novo Uint8Array (event.target.result)
                     }
                     console.log("mensagem é:");
                     console.log(msg);
                     this.$emit("bsec-upload-event", true);
                     myMqtt.sendWBasePath(sensorSetBsecPath, msg, 1, true);                   
                 });
                 reader.readAsArrayBuffer(this.bsecFile);
         }
         senão (
             console.log("o arquivo foi limpo, então devemos removê-lo ... enviando $nofile como verdadeiro");
             const msg = {
                 "$nofile": verdadeiro
             }
             console.log("mensagem é:");
             console.log(msg);
             this.$emit("bsec-upload-event", falso);
             myMqtt.sendWBasePath(sensorSetBsecPath, msg, 1, true);
         }
     }

Note que eu publico uma mensagem que inclui dados binários.

Eu uso um construtor para um novo Uint8Array ao qual passo event.target.result - um ArrayBuffer.

Desta forma, os dados são transmitidos precisamente como estão.

Nós usamos o MsgPack para empacotar o objeto JavaScript em uma mensagem - que suporta dados binários.

Por outro lado, PiCockpit Client pega a mensagem binária e pode reintegrar um objeto Python (nesse caso), incluindo os dados binários.

Fazendo-o funcionar para sincronizar através das janelas do navegador

Uma segunda tarefa é sincronizar o estado em diferentes janelas do navegador e também as sessões do usuário.

Quando o usuário retornar, gostaríamos de apresentar o arquivo como já tendo sido carregado para eles.

O que eu quero fazer é essencialmente construir uma nova instância File Object em JavaScript, a partir do meu Uint8Array para recriar o ficheiro a partir da mensagem MQTT!

Nós subscrevemos e ouvimos a mensagem do MQTT, é claro. E depois monitoramos a variável para alterações, e modificamos o modelo bsecFile da seguinte forma:

globalBsecFileWrapped(val){
     // isto só será atualizado se não formos responsáveis por enviar a mensagem em primeiro lugar.
     console.log("watch > globalBsecFileWrapped > contents:");
     console.log(this.globalBsecFileWrapped);
     console.log("vamos definir isto como um arquivo agora ... ");
     if (this.globalBsecFileWrapped.hasOwnProperty("$nofile")){
         if (this.globalBsecFileWrapped['$nofile']){
             // atualizá-lo para ser nulo - foi reinicializado a partir de um navegador diferente.
             este.bsecFile = nulo;
         }
     }
     senão se (this.globalBsecFileWrapped.hasOwnProperty("fd") && this.globalBsecFileWrapped.hasOwnProperty("fn")) {
         // tentativa 2
         // this.bsecFile = novo arquivo(this.globalBsecFileWrapped.fd, this.globalBsecFileWrapped.fn);
         this.bsecFile = novo Blob([this.globalBsecFileWrapped.fd], {type: "application/octet-stream"});
         this.bsecFile.name = this.globalBsecFileWrapped.fn;
         // debug
             var reader = novo FileReader();
             reader.addEventListener('load', (event) => {
                 console.log("Debug >> Publicação de arquivo lido com sucesso! (agora com Uint8Array)");
                 // fn = nome do arquivo, fs = tamanho do arquivo, fd = dados do arquivo (binário)
                 const msg = {
                       fn: este.bsecFile.name,
                       fs: este.bsecFile.tamanho,
                       fd: novo Uint8Array (event.target.result)
                 }
                 console.log("mensagem é:");
                 console.log(msg);
             });
             reader.readAsArrayBuffer(this.bsecFile);               
     }
}

anote as partes importantes aqui:

this.bsecFile = novo Blob([this.globalBsecFileWrapped.fd], {type: "application/octet-stream"});
this.bsecFile.name = this.globalBsecFileWrapped.fn;

Então, a fim de recriar o arquivo (e ter o vuetify v-file-input atualizado para o arquivo correto (mostrando o tamanho adequadamente, e nome do arquivo) estamos construindo um novo Blob.

Importante: o Blob precisa ter o tipo de "application/octet-stream" - caso contrário ele será interpretado como algo diferente e o tamanho dos arquivos não será mais compatível!

E finalmente, definimos o novo nome - é isso!

Procurando resolver problemas semelhantes?

Estamos disponíveis para aluguer