0

I'm writing a Firefox extension and I'm searching to pass a zipped file with a WebSocket (server here). The code is the following for the client side (that send the file):

var ws = new window.WebSocket("ws://localhost:12345");

function sendLogToOtherClient(file){

   var zippedFileToSend = zipLogFile(file);
   NetUtil.asyncFetch(zippedFileToSend, function(inputStream, status) {
      if (!components.isSuccessCode(status)) {
         return;
   }
   var bstream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
   bstream.setInputStream(inputStream);
   var bytes = bstream.readByteArray(bstream.available());
   bstream.close();
   var encodedData = base64.encode(bytes, "utf-8");
   ws.send(encodedData);
   });
}
function zipLogFile(fileToZip){
   var zippedFile = FileUtils.getFile("ProfD", ["report1.zip"], false);
   var zipWriter = CCIN("@mozilla.org/zipwriter;1", "nsIZipWriter");
   zipWriter.open(zippedFile, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE);
   zipWriter.addEntryFile("logfile.txt", zipWriter.COMPRESSION_BEST, fileToZip, false);
   zipWriter.close();
   return zippedFile;
}

And this for Server side (that receive file and write new zipped file):

server = new WebSocketServer(12345);
server.onclient = function(client) {
   console.log(client + " connected");

   client.onmessage = function(client, msg) {
      client.send("Log Received");
      var zippedTmpFile = FileUtils.getFile("ProfD", ["report2.zip"], false);
      asyncTmpSave(zippedTmpFile, msg, onDone)

   };
};
server.connect();

function asyncTmpSave(file, data, callbackDone){
   var ostream = FileUtils.openFileOutputStream(file, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE);
   var converter = CCIN('@mozilla.org/intl/scriptableunicodeconverter', "nsIScriptableUnicodeConverter");
   converter.charset = 'UTF-8';
   var istream = converter.convertToInputStream(data);

   NetUtil.asyncCopy(istream, ostream, callbackSaved); 
      function callbackSaved (status) {     
         if(callbackDone){
           if(status===0)callbackDone( file.path, file.leafName, status);  //sucess.
           else callbackDone( null, null, status); //failure.
      }; 
  }
}
function onDone(path, leafName, statusCode){
   console.log([statusCode===0?"OK":"error",path,leafName].join("\n"));
}

I've tryed to pass string and the communication works, and in this case data are passed and the file is created, but the .zip file is corrupted. Do you have any ideas? Thanks

hasmet
  • 758
  • 3
  • 13
  • 32

1 Answers1

2

You cannot utf-8 encode random, binary stuff.

WebSockets (and my server) support typed arrays.

So you'll when sending want:

var bytes = new Uint8Array(bstream.available());
bstream.readArrayBuffer(bytes.byteLength, bytes.buffer);
bstream.close();
ws.send(bytes);

And on the receiving end you'll receive an Uint8Array as well.

nmaier
  • 32,336
  • 5
  • 63
  • 78
  • ah ok, do you know any method (or link) to create a file from a Uint8Array? Thanks – hasmet Jul 28 '14 at 16:18
  • [`OS.File.writeAtomic`](https://developer.mozilla.org/en-US/docs/JavaScript_OS.File/OS.File_for_the_main_thread#OS.File.writeAtomic) probably would be easiest (but you might need to wrap your head around promises and `Task.jsm` first). Otherwise, you can just write it to any output stream, either directly to a file stream (but that is bad because sync I/O on the main thread), or by creating e.g. an `nsIPipe`, writing the data there (`.outputStream`) and `asyncCopy`in it into the file (`.nsIInputStream`) – nmaier Jul 28 '14 at 16:26
  • Sorry nmaier but I have another little question.....the problem is the following. When I try to use you code to send data, the server close connection with the following error: – hasmet Jul 29 '14 at 07:57
  • [Exception... "[JavaScript Error: "this.socket is undefined" {file: "resource://jid1-exo2npaaditkqg-at jetpack/client/data/WebSocketServer.jsm" line: 526}]'[JavaScript Error: "this.socket is undefined" {file: "resource://jid1exo2npaaditkqg-at-jetpack/client/data/WebSocketServer.jsm" line: 526}]' when calling method: [nsIInputStreamCallback::onInputStreamReady]" nsresult: "0x80570021 (NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS)" location: "nativeframe :: :: :: line 0" data: yes] – hasmet Jul 29 '14 at 07:57
  • Ok I solved the other problem using: let whereToSave = OS.Path.join(OS.Constants.Path.profileDir, "tmp.zip"); OS.File.writeAtomic(whereToSave, msg); – hasmet Jul 29 '14 at 11:54