Pass Binary Data with WebSocket - javascript

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

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.

Related

How to stop number being converted to string in xmlHttpRequest?

How do I stop a number being converted to a string when adding an element to a JSON file on a server using xmlHttpRequest?
The following code updates my .json file with the element but the number (var importance) is a string by the time it arrives at the server... and I can't work out why.
This is where I format my input data and create the xmlHttpRequest.. (script.js):
btnSubmit.onclick = submitTask;
function submitTask() {
inputTask = document.querySelector('#task');
inputImportance = document.querySelector('#importance');
var task = inputTask.value;
var importance = Number(inputImportance.value);
console.log("User Input: ",task, importance);
//Setup XML HTTP Request
var xhr = new XMLHttpRequest();
xhr.open('POST', api_url_add +'/'+ task +'/'+ importance, true);
xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
//Receive response from server.
xhr.onload = function() {
response = JSON.parse(xhr.response);
console.log(response);
}
xhr.send();
}
And this is the server side code (server.js):
// ADD task to the list (task, importance)
app.post('/add/:task/:importance?', addTask);
function addTask(request, response) {
var data = request.params;
console.log('Submitted to server:','\n', data);
var task = data.task;
var importance = Number(data.importance);
var reply;
if (!importance) {
var reply = {
msg: "Importance value is required."
}
} else {
var element = data;
tasks['taskList'].push(element);
fs.writeFile('tasks.json', JSON.stringify(tasks, null, 2), function(err){
console.log('all done')
})
response.send(reply);
}
}
Thanks for all of your help.

Using MP4box.js and onSegment callback is not called

Base problem: display a H264 live stream in a browser.
Solution: let's just convert it to fragmented mp4 and load chunk-by-chunk via websocket (or XHR) into MSE.
Sounds too easy. But I want to do the fragmentation on client side with pure JS.
So I'm trying to use MP4Box.js. On its readme page it states: it has a demo: "A player that performs on-the-fly fragmentation".
That's the thing I need!
However the onSegment callbacks which should feed MSE are not called at all:
var ws; //for websocket
var mp4box; //for fragmentation
function startVideo() {
mp4box = MP4Box.createFile();
mp4box.onError = function(e) {
console.log("mp4box failed to parse data.");
};
mp4box.onMoovStart = function () {
console.log("Starting to receive File Information");
};
mp4box.onReady = function(info) {
console.log(info.mime);
mp4box.onSegment = function (id, user, buffer, sampleNum) {
console.log("Received segment on track "+id+" for object "+user+" with a length of "+buffer.byteLength+",sampleNum="+sampleNum);
}
var options = { nbSamples: 1000 };
mp4box.setSegmentOptions(info.tracks[0].id, null, options); // I don't need user object this time
var initSegs = mp4box.initializeSegmentation();
mp4box.start();
};
ws = new WebSocket("ws://a_websocket_server_which_serves_h264_file");
ws.binaryType = "arraybuffer";
ws.onmessage = function (event) {
event.data.fileStart = 0; //tried also with event.data.byteOffset, but resulted error.
var nextBufferStart = mp4box.appendBuffer(event.data);
mp4box.flush(); //tried commenting out - unclear documentation!
};
}
window.onload = function() {
startVideo();
}
Now putting this into an HTML file would result this in the JavaScript console:
Starting to receive File Information
video/mp4; codecs="avc1.4d4028"; profiles="isom,iso2,avc1,iso6,mp41"
But nothing happens afterwards. Why is the onSegment not called here? (the h264 file which the websocket-server serves is playable in VLC - however it is not fragmented)
The problem was using the nextBufferStart in a wrong way.
This should be the correct one:
var nextBufferStart = 0;
...
ws.onmessage = function (event) {
event.data.fileStart = nextBufferStart;
nextBufferStart = mp4box.appendBuffer(event.data);
mp4box.flush();
};

Callback a function after a process

I use the bittorent-tracker package for get numbers of seeders and leechers for a given torrent but there is no way to know if the torrent scraping procedure is terminated client.on('scrape_terminated') for exemple ... Is there a way to detects the scraping is terminated ?
var Tracker = require('bittorrent-tracker')
var magnet = require('magnet-uri')
var magnetURI = "magnet:?xt=urn:btih:7a0e02e22744ddb807480f580cc328925d5810d4&dn=Terminator+2%3A+Judgment+Day+DC+%281991%29+1080p+BrRip+x264+-+YIFY&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Fzer0day.ch%3A1337&tr=udp%3A%2F%2Fopen.demonii.com%3A1337&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Fexodus.desync.com%3A6969"
var parsedTorrent = magnet(magnetURI)
var opts = {
infoHash: parsedTorrent.infoHash,
announce: parsedTorrent.announce,
peerId: new Buffer('01234567890123456789'), // hex string or Buffer
port: 6881 // torrent client port
}
var client = new Tracker(opts)
client.scrape();
client.on('scrape', function (data) {
console.log('number of seeders in the swarm: ' + data.complete)
console.log('number of leechers in the swarm: ' + data.incomplete)
});
client.on('error',function(data) {
console.log('erreur');
})

HTTP Error 405.0 - Method Not Allowed with Put when attempting to upload a file

My previously working update function now returns a 405 error when it is run. This is after I added the fileReader functionality to facilitate file uploading for a pictures. How could I now have a HTTP verb error (which is what 405 is to my understanding) if my ajaxCall is untouched from it's working form?
function update()
{
//picture specific upload stuff
var reader = new FileReader();
var file = $('#fileUpload')[0].files[0];
reader.readAsBinaryString(file);
//What is readerEvt?
reader.onload = function (readerEvt)
{
//get binary data then convert to encoded string
var binaryString = reader.result;
var encodedString = btoa(binaryString);
//normal update fields
emp = new Object();
emp.Title = $("#TextBoxTitle").val();
emp.Firstname = $("#TextBoxFirstname").val();
emp.Lastname = $("#TextBoxLastname").val();
emp.Phoneno = $("#TextBoxPhone").val();
emp.Email = $("#TextBoxEmail").val();
emp.StaffPicture64 = encodedString;
emp.Id = localStorage.getItem("Id");
emp.DepartmentId = localStorage.getItem("DepartmentId");
emp.Version = localStorage.getItem("Version");
}
ajaxCall("Put", "api/employees", emp)
.done(function (data) {
$("#myModal").modal("hide");
getAll(data);
})
.fail(function (jqXHR, textStatus, errorThrown) {
errorRoutine(jqXHR);
});
return false;
}

Firefox Extension/Addon : Reading a text file from remote server(URL)

After wasting my two days to find out what's going wrong with this script, finally I decide to ask it.
What I am trying to do
I am trying to read a text file from remote server. Then storing all text file updates to an SQLITE database at the time of my Firefox Extension/Addon get loaded.
What I tried
var updatereader = {
start: function () {
//alert('reading update');
var fURL = null;
var ioService = null;
var fURI = null;
var httpChannel = null;
fURL = "http://www.example.com/addon/mlist.txt";
ioService = Components.classes["#mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
fURI = ioService.newURI(fURL, null, null);
httpChannel = ioService.newChannelFromURI(fURI).QueryInterface(Components.interfaces.nsIHttpChannel);
httpChannel.asyncOpen(updatereader.StreamReader, null);
},
onUpdateCompleted: function () {
},
StreamReader:
{
fOutputStream: null,
fPointer: null,
tempFile: "mlist.txt",
onStartRequest: function (aRequest, aContext) {
//alert('onStart');
updatereader.StreamReader.fOutputStream = Components.classes["#mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
updatereader.StreamReader.fPointer = Components.classes["#mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get("ProfD", Components.interfaces.nsIFile);
updatereader.StreamReader.fPointer.append(updatereader.StreamReader.tempFile);
updatereader.StreamReader.fOutputStream.init(updatereader.StreamReader.fPointer, 0x02 | 0x20 | 0x08, 0644, 0);
},
onDataAvailable: function (aRequest, aContext, aInputStream, aOffset, aCount) {
//control flow is not entering here - may be here is somehting missing
var sStream = null;
var tempBuffer = null;
sStream = Components.classes["#mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
sStream.init(aInputStream);
tempBuffer = sStream.read(aCount);
updatereader.StreamReader.fOutputStream.write(tempBuffer, aCount);
},
onStopRequest: function (aRequest, aContext, aStatusCode) {
//alert('onStop');
var currentDate = new Date();
if (aStatusCode == 0) {
fileInputStream = Components.classes["#mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
updatereader.StreamReader.fOutputStream.close();
fileInputStream.init(updatereader.StreamReader.fPointer, 0x01, 0, 0);
lineInputStream = fileInputStream.QueryInterface(Components.interfaces.nsILineInputStream);
//pass data to somewhere
var dbH = new dbstore();
dbH.updateData(lineInputStream);
lineInputStream.close();
updatereader.StreamReader.fPointer.remove(false);
updatereader.onUpdateCompleted();
} else {
}
}
}
}
Problem:
Getting nothing in lineInputStream which passes the read data to somewhere else for storing it.
Area of problem:
Program control flow is not entring to this section
onDataAvailable:
Not getting any error.
First of all, there doesn't really seem to be any need to read the file to the disk first (unless it is really, really big).
I'd just use XMLHttpRequest to get the file, which when run from a privileged context (e.g. add-on code, but not a website) can access any and every valid URI.
XMLHttpRequest will simplify almost everything, e.g. no more onDataAvailable, (usually) no more manual text converting, etc.
Also, no need to ever hit the disk during the transfer.
Code would look something like this:
var req = new XMLHttpRequest();
req.open("GET", "http://www.example.com/addon/mlist.txt"); // file:/// would work too, BTW
req.overrideMimeType("text/plain");
req.addEventListener("load", function() {
// Do something with req.responseText
}, false);
req.addEventListener("error", function() {
// Handle error
}, false);
req.send();
If you want to use XMLHttpRequest in a non-window, e.g. js code module or js components, then you need to first initialize a constructor. This is not required for windows, including XUL windows and by that XUL overlays.
// Add XMLHttpRequest constructor, if not already present
if (!('XMLHttpRequest' in this)) {
this.XMLHttpRequest = Components.Constructor("#mozilla.org/xmlextras/xmlhttprequest;1", "nsIXMLHttpRequest");
}
SDK users should use the request module, or net/xhr if a lower-level API is required.
PS: If you're still interested in using raw channels, here is a minimal example I coded up in a Scratchpad (to run, open a Scratchpad for a privileged location, e.g. about:newtab).
You shouldn't alert from your own implementation: alert() will spin the event loop and causes reentrant code, which is not supported in this context.
var {
classes: Cc,
interfaces: Ci,
results: Cr,
utils: Cu
} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm")
Cu.import("resource://gre/modules/Services.jsm");
var ConverterStream = Components.Constructor(
"#mozilla.org/intl/converter-input-stream;1",
"nsIConverterInputStream",
"init");
var RC = Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER;
function Listener() {
this.content = "";
}
Listener.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener]),
onStartRequest: function(req, ctx) {
console.log("start");
},
onDataAvailable: function(req, ctx, stream, offset, count) {
console.log("data", count);
try {
var cs = new ConverterStream(stream, null /* utf-8 */, 4096, RC);
try {
var str = {};
while (cs.readString(4096, str)) {
this.content += str.value;
}
}
finally {
cs.close();
}
}
catch (ex) {
console.error("data", ex.message, ex);
}
},
onStopRequest: function(req, ctx, status) {
console.log("stop", status,
this.content.substr(0, 20), this.content.length);
}
};
var uri = Services.io.newURI("http://example.org", null, null);
Services.io.newChannelFromURI(uri).asyncOpen(new Listener(), null);

Categories

Resources