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

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

5 Comments

ah ok, do you know any method (or link) to create a file from a Uint8Array? Thanks
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 asyncCopyin it into the file (.nsIInputStream)
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:
[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 :: <unknown filename> :: <TOP_LEVEL> :: line 0" data: yes]
Ok I solved the other problem using: let whereToSave = OS.Path.join(OS.Constants.Path.profileDir, "tmp.zip"); OS.File.writeAtomic(whereToSave, msg);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.