Reading from and writing to multiple ip's with node.js - javascript

I've been through a tutorial with Node.js, but it seems everything was aimed at what to do with it from the server side. I was playing around with it to see how it would work writing to multiple devices on our network with non-blocking i/o. Here's what I have so far (rough code, sorry):
var net = require('net');
var nodes = [<list of IP addresses>];
function connectToServer(ip) {
conn = net.createConnection(3083, ip);
console.log ("Creating connection to: " + ip + "\n");
conn.on('connect', function() {
conn.write ("act-user::myuser:ex1::mypass;");
});
conn.on('data', function(data) {
var read = data.toString();
if (read.match('ex1'))
{
console.log(ip + ": " + read);
}
});
conn.on('end', function() {
});
}
nodes.forEach(function(node) {
connectToServer(node);
});
I see it go through the list and kicking off a connection to each IP address, but then it seems to write the login line to the same host over and over again. I think somewhere I'm getting my streams crossed (just like Egon said to never do), but I'm not sure how to fix it. The non-blocking node.js world is still kind of difficult for me to think through.

Your issue is a JavaScript kink. In JavaScript, if a variable is defined without var before it, it will be set as global. This is happening to the conn variable in your connectToServer() function. conn is being overwritten and is not reset after the connectToServer scope is exited.
Try adding var in front of the following.
conn = net.createConnection(3083, ip);
Result
var conn = net.createConnection(3083, ip);

Related

Capturing refresh on haskell websockets example server?

The websockets server example works as expected. On browser refresh (e.g. S-F5 with chrome), the websocket disconnects, still working as expected. After refresh, the user has to give name again to connect to the server.
How would you capture the refresh-event and keep the user connected? E.g.
Is this doable only on server side or does the client require modifications as well? Haskell examples or links to such would be nice as well as hints on how to do this!
How would you capture the refresh-event...
There isn't really such a thing as a refresh event to detect (I would love to be proved wrong in this!)
... and keep the user connected...
The refresh, or rather, the leaving of the page before loading it again, causes the websocket to disconnect, and (especially if this is the only page on the site that is open), there isn't really much you can do about it.
So the only thing that can be done, is have some sort of auto-reconnect the next time the page loads. A solution that allows this is one where..
when the name is initially entered, the name is saved somewhere in the browser;
when the page reloads, it checks for a previously saved name;
and if it's found, it connects again using that name.
Local storage is one such place to save this, as in the below example, modified from https://github.com/jaspervdj/websockets/tree/master/example to save/retrieve the name from local storage.
$(document).ready(function () {
var savedUser = sessionStorage.getItem("rejoin-user");
if (savedUser) {
joinChat(savedUser);
}
$('#join-form').submit(function () {
joinChat($('#user').val())
});
function joinChat(user) {
sessionStorage.setItem("rejoin-user", user);
$('#warnings').html('');
var ws = createChatSocket();
ws.onopen = function() {
ws.send('Hi! I am ' + user);
};
ws.onmessage = function(event) {
if(event.data.match('^Welcome! Users: ')) {
/* Calculate the list of initial users */
var str = event.data.replace(/^Welcome! Users: /, '');
if(str != "") {
users = str.split(", ");
refreshUsers();
}
$('#join-section').hide();
$('#chat-section').show();
$('#users-section').show();
ws.onmessage = onMessage;
$('#message-form').submit(function () {
var text = $('#text').val();
ws.send(text);
$('#text').val('');
return false;
});
} else {
$('#warnings').append(event.data);
ws.close();
}
};
$('#join').append('Connecting...');
return false;
};
});
... Is this doable only on server side or does the client require modifications as well?
It definitely needs something done in the client to auto-reconnect. The bare bones version above needs no changes to the server, but if you wanted something fancier, like having the cases of initial connect and auto reconnect handled/shown differently somehow, then the server might need to be modified.

Passing socket between multiple client side javascript files

I recently started coding a small web game in javascript. Even more recently, I started refactoring the code to use node.js with socket.io to make the game multiplayer.
My issue, which I cannot find a solution for, is that I would like to pass the client side socket variable to multiple client side javascript files.
In client/app.js:
var app = (function() {
...
var socket = io.connect('http://localhost:8080');
socket.on('connect', function() {
dice.setSocket(socket);
});
...
})();
In client/dice.js:
var dice = (function() {
...
var gameSocket;
if (gameSocket) {
gameSocket.on('dice rolling', function(data) {
playDiceAnim(data);
});
}
function setSocket(socket) {
gameSocket = socket;
}
})();
Unfortunately, when the 'dice rolling' event is emitted from the server side, playDiceAnim(data) is never executed. But, I know that the 'dice rolling' event is being received by app.js. For example, if in app.js I put:
var app = (function() {
...
var socket = io.connect('http://localhost:8080');
socket.on('dice rolling', function() {
console.log('event received');
});
...
})();
Then, the result in the developer tools console is:
'event received'
The examples that I can find online either put all client side javascript into a script tag in a .html file, or in a single .js file. But, I would like to be more modular than that.
How can I appropriately pass and use the client side socket to other client side files?
Here is the full code. Beware of bugs, it is in the process of being refactored. Also, any aside advice would be greatly appreciated as I am still fairly new to javascript and node.js.
Here's what I would suggest:
Load the app script first and have it make the socket available to other callers via a method:
var app = (function() {
...
var socket = io.connect('http://localhost:8080');
return {
getSocket: function() { return socket;}
}
...
})();
var dice = (function() {
...
var gameSocket = app.getSocket();
if (gameSocket) {
gameSocket.on('dice rolling', function(data) {
playDiceAnim(data);
});
}
})();
In this case, I think it makes more sense for the app to be a provider of services such as a connected webSocket and for other modules to request that information from the app. But, it really depends upon which module you want to be more generic and not depend upon the other. It could go either way.

Streaming images with Nodejs on embedded device

I'm trying to stream images from a Node.js server to a client site. I've started with socket.io, but my implementation is fairly memory intensive (and possibly leaking as I'm not fluent in JavaScript). I'm just prototyping at this point with 10 sample images:
Server Side
Responds to a socket.io trigger with the following function that "streams" 10 images to the client at roughly 100ms intervals.
socket.on('img_trigger', function(data) {
var img_num = 0;
var timeoutHandle = null;
function startTimeout() {
stopTimeout();
if (img_num < 10) {
timeoutHandle = setTimeout(updateStream, 100);
}
}
function stopTimeout() {
clearTimeout(timeoutHandle);
}
function updateStream() {
var file = './sampleframes/sample-' + img_num + '.png';
fs.readFile(file , function(err, file_buff) {
if (err !== null) {
console.log('readFile error: ' + err);
} else {
socket.emit('img_stream', { buffer: file_buff });
}
file_buff = null;
++img_num;
});
startTimeout();
}
// kicks off first image
startTimeout();
});
Client Side
Capture the raw buffer data and generate a PNG with an <img> element.
socket.on('img_stream', function(data) {
var img_data = arrayBufferToBase64(data.buffer);
var panel = $('#frame-panel');
$('#frame').html('<img src="data:image/png;base64,' +
img_data + '" width="' + panel.width() + '" height="' +
panel.height() + '" />');
});
If I trigger the server once, it works fine but not great. I notice the memory usage go up significantly, and it crashes after several triggers. Can I improve my code here to be efficient or should I try a new approach?
I've looked into using Node's File Streams, socket.io-streams, and even Binary.js (though I hesitate to require our clients to have too-modern of browsers) and they look promising, but I don't quite know which would be best for my use-case. Any help or guidance would be greatly appreciated.
The web interface I'm developing is for an FPGA (Zynq-7000) based camera running PetaLinux with Node.js cross-compiled for the ARM processor, so I don't have a lot of server-side resources to work with. As such, I'd like to have the client-side do as much of the processing as possible. Eventually, streaming video would be incredible, but I'd be satisfied with reading and displaying successive frames at a reasonable rate.
This may be due to a memory leak within the socket.io library (see here for a description, and here for a proposed fix).
To fix this, download and use the latest version of socket.io from here.

indexedDB correct usage

I'm experimenting with indexedDB. Now everything is like asynchronous and that hurts my brain a lot.
I created an object like this:
var application = {};
application.indexedDB = {};
application.indexedDB.db = null;
application.indexedDB.open = function() {
var dbName = "application";
var dbVersion = 1;
var openRequest = indexedDB.open(dbName, dbVersion);
openRequest.onupgradeneeded = function(e) {
console.log("Upgrading your DB (" + dbName + ", v" + dbVersion + ")...");
var thisDB = e.target.result;
if (!thisDB.objectStoreNames.contains("journal")) {
thisDB.createObjectStore(
"journal",
{keyPath: "id"}
);
}
}
openRequest.onsuccess = function(e) {
console.log("Opened DB (" + dbName + ", v" + dbVersion + ")");
application.indexedDB.db = e.target.result;
}
openRequest.onerror = function(e) {
console.log("Error");
console.dir(e);
}
};
Now I am able to open the dbconnection with application.indexedDB.open(). Now I added another function to my Object:
application.indexedDB.addItemToTable = function(item, table) {
var transaction = application.indexedDB.db.transaction([table], "readwrite");
var store = transaction.objectStore(table);
//Perform the add
var request = store.add(item);
request.onerror = function(e) {
console.log("Error", e.target.error.name);
//some type of error handler
}
request.onsuccess = function(e) {
console.log("Woot! Did it");
}
};
My instruction-sequence extended like this:
application.indexedDB.open()
application.indexedDB.addItemToTable(item, "journal")
But this doesn't work. Because the open-Instruction is asynchronous the application.indexedDB.dbis not yet available when i call it in the addItemToTable-Function.
How does a Javascript-Developer solve this?
I was following this tutorial here: http://code.tutsplus.com/tutorials/working-with-indexeddb--net-34673 and now I have some problems with those examples.
For example he creates the HTML-Output directly in the "onsuccess"-Part (in the "Read More Data" Section) . In my eyes this is bad coding because the view has nothing to do with the db-reading part.. isn't it? but then comes my question. how the heck can you return something in the "onsuccess"-Part?
Adding callbackfunctions is somewhat complicated. Especially when i want to read some data and with that resultset get some more data. It's very complicated to describe what i mean.
I made a little fiddle - maybe it clarifies things.. -- http://jsfiddle.net/kb8nuby6/
Thank you
You don't need to use someone else's extra program. You will need to learn about asynchronous javascript (AJAX) before using indexedDB. There is no way to avoid it. You can learn about AJAX without learning about indexedDB. For example, look at how XMLHttpRequest works. Learn about setTimeout and setInterval. Maybe learn about requestAnimationFrame. If you know nodejs stuff, review process.nextTick. Learn about how functions are first class. Learn about the idea of using a callback function. Learn about continuation passing style.
You will probably not get the answer you are looking for to this question. If anything, this is a duplicate of the several thousand other questions on stack overflow about asynchronous programming in javascript. It is not even that related to indexedDB. Take a look at some of the numerous other questions about asynchronous js.
Maybe this gets you started:
var a;
setTimeout(function() { a = 1; }, 10);
console.log('The value of a is %s', a);
Figure out why that did not work. If you do, you will be much closer to finding the answer to this question.
The pattern I commonly adopted is wait all database operations until connected. It is similar concept to $.ready in jQuery.
You will find that as the app get age, you have many schema versions and need to upgrade data as well. A lot of logic in database connection itself.
You can use callback queue, if you need to use database before ready. Here is snippet from Google analytics on commend queue:
// Creates an initial ga() function. The queued commands will be executed once analytics.js loads.
i[r] = i[r] || function() {
(i[r].q = i[r].q || []).push(arguments)
},
Basically, you will execute these callbacks once database is connected.
I highly recommend to check out my own library, ydn-db. It has all these concepts.

Messages between Firefox plugins

I'm trying to implement a client-server communications between two or more plugins where each plugin is concurrently both server and client. I use nsIServerSocket for server part and websockets for client part. This is the code:
function startServer(port) {
var listener = {
onSocketAccepted: function(serverSocket, transport) {
console.log("Accepted connection on " + transport.host + ":" + transport.port);
var input = transport.openInputStream(Ci.nsITransport.OPEN_BLOCKING, 0, 0);//.QueryInterface(Ci.nsIAsyncInputStream);
var output = transport.openOutputStream(Ci.nsITransport.OPEN_BLOCKING, 0, 0);
var sin = Cc["#mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
try{
sin.init(input);
var readBytes = sin.available();
var request = '';
request = sin.read(readBytes);
console.log('Received: ' + request);
//getUrl(request);
output.write("yes", "yes".length);
output.flush();
}
finally{
sin.close();
input.close();
output.close();
}
}
}
try{
var serverSocket = Cc["#mozilla.org/network/server-socket;1"].createInstance(Ci.nsIServerSocket);
serverSocket.init(port, true, 5);
console.log("Opened socket on " + serverSocket.port);
serverSocket.asyncListen(listener);
}catch(e){
console.log(e);
}
}
For server part, and the following for client part:
var address="ws://otherAddress:1234";// + port;
var window = Cc["#mozilla.org/appshell/appShellService;1"]
.getService(Ci.nsIAppShellService)
.hiddenDOMWindow;
ws = new window.WebSocket(address);
try{
ws.onmessage = function () {
};
ws.onopen = function(){
console.log("connection opened");
// Web Socket is connected. You can send data by send() method
ws.send("lol ");
};
ws.onclose = function() {
// websocket is closed. };
console.log("websocket is closed");
}
}catch(evt){
console.log(evt.data);
}
The client code start when user click on a button....This code is partly working, because from console I see that when user click button, server receive the connection-open, but I can't receive the message......Anyone can help me? Thanks
UPDATE 1
the message that I see in console is like this:
"Received: GET / HTTP/1.1
Host: localhost:1234
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: it-IT,it;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: resource://gre-resources
Sec-WebSocket-Key: zh/EpJRRsOAgLfPIbI1EDg==
Connection: keep-alive, Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
UPDATE 2
After nmaier and IvyLynx answers (thanks a lot!!), I modified my code inserting a full "ServerSocket" implementation (mainly because in future I will also be passing binary data). This is the code for a localhost case:
var {Cc, Ci, Cu, Cr, components} = require("chrome");
// the thread manager can be important when using asynchronous mode
var thread_manager = Cc["#mozilla.org/thread-manager;1"].getService();
var socket_service = Cc["#mozilla.org/network/socket-transportservice;1"].getService(Ci.nsISocketTransportService);
// make some constructors so we don't have to worry about this later
var socket = Cc["#mozilla.org/network/serversocket;1"].createInstance(Ci.nsIServerSocket);
// set the second argument to false if you want it to listen
// to connections beyond the computer the extension runs on
socket.init(-1, true, -1);
var output_stream_bin = Cc["#mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
var input_stream_bin = Cc["#mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
// this is so we can easily instantiate nsIInputStreamPump, which allows us to read input streams properly
var input_stream_pump_c = Cc["#mozilla.org/network/input-stream-pump;1"];
var input_stream_base, input_stream_async_c, input_stream_async, recieved_bytes, recieved_total, input_stream_pump;
var output_stream_base, output_stream_async_c, output_stream_async, generalStream;
var client, client_input_stream, client_output_stream, client_input_stream_pump;
var data_to_send = "hi hi"; // this holds what we want to send
var socket_transport = socket_service.createTransport(null, 0, "localhost", socket.port, null);
var socket_listener = {
onSocketAccepted: function(socket, transport){
client = transport;
client_input_stream = client.openInputStream(0, 0, 0);
client_output_stream = client.openOutputStream(0, 0, 0);
client_output_stream.QueryInterface(Ci.nsIAsyncOutputStream);
generalStream = client_output_stream;
client_input_stream_pump[this_transport] = input_stream_pump_c.createInstance(Ci.nsIInputStreamPump);
client_input_stream_pump[this_transport].init(client_input_stream, -1, -1, 0, 0, false);
client_input_stream_pump[this_transport].asyncRead(socket_reader, socket);
},
onStopListening: function(socket, status){
}
};
socket.asyncListen(socket_listener);
// this guy will get called when we're ready to send data
var output_stream_callback = {
onOutputStreamReady: function(stream){
output_stream_bin.setOutputStream(stream);
output_stream_bin.writeBytes(data_to_send, data_to_send.length);
data_to_send = "";
}
};
var socket_reader = {
onDataAvailable: function(request, context, stream, offset, count){
input_stream_bin.setInputStream(stream);
if(input_stream_bin.available() > 0){
recieved_bytes = input_stream_bin.readByteArray(count);
recieved_total = "";
// this loop converts bytes to characters
// if you don't need to pass binary data around
// you can just use nsIScriptableInputStream instead of
// nsIBinaryInputStream and skip this
for (var i = 0; i < recieved_bytes.length; i++){
recieved_total += String.fromCharCode(recieved_bytes[i]);
}
console.log("Received " + recieved_total)
}else{
stream.close();
}
},
onStartRequest: function(request, context){
},
onStopRequest: function(request, context, status){
}
};
require("sdk/widget").Widget({
id: "mozilla-link",
label: "Mozilla website",
contentURL: data.url("icon.png"),
onClick: listTabs
});
function listTabs() {
//console.log(client_output_stream);
generalStream.asyncWait(output_stream_callback,0,0,thread_manager.mainThread);
};
The problem is the generalStream variable. I call asyncWait method when user click on extension icon, but I also insert the call in other methods. Each generalStream.asyncWait provocate the follow problem (where are ... in reality there are the path of the profile in wich the extension is executed):
console.error: client:
Message: TypeError: generalStream is undefined
Stack:
listTabs#resource://gre/modules/XPIProvider.jsm -> jar:file:///.../extensions/jid1-exo2NP
aadiTkqg#jetpack.xpi!/bootstrap.js -> resource://gre/modules/commonjs/toolkit/lo
ader.js -> resource://jid1-exo2npaaditkqg-at-jetpack/client/lib/main.js:742
_emitOnObject#resource://gre/modules/XPIProvider.jsm -> jar:file:///.../extensions/jid1-exo2N PaadiTkqg#jetpack.xpi!/bootstrap.js -> resource://gre/modules/commonjs/toolkit/l
oader.js -> resource://gre/modules/commonjs/sdk/deprecated/events.js:153
_emit#resource://gre/modules/XPIProvider.jsm -> jar:file:///.../extensions/jid1-exo2NPaadiTkqg#jetpack.xpi!/bootstrap.js -> resource://gre/modules/commonjs/toolkit/loader.js -> resource://gre/modules/commonjs/sdk/deprecated/events.js:123 _onEvent#resource://gre/modules/XPIProvider.jsm -> jar:file:///.../extensions/jid1-exo2NPaadi
Tkqg#jetpack.xpi!/bootstrap.js -> resource://gre/modules/commonjs/toolkit/loader.js -> resource://gre/modules/commonjs/sdk/widget.js:278
WidgetView__onEvent#resource://gre/modules/XPIProvider.jsm -> jar:file:///.../extensions/jid1-exo2NPaadiTkqg#jetpack.xpi!/bootstrap.js -> resource://gre/modules/commonjs/toolkit/loader.js -> resource://gre/modules/commonjs/sdk/widget.js:426
WC_addEventHandlers/listener/<#resource://gre/modules/XPIProvider.jsm -> jar:file:///.../extensions/jid1-exo2NPaadiTkqg#jetpack.xpi!/bootstrap.js -> resource://gre/modules/commonjs/toolkit/loader.js -> resource://gre/modules/commonjs/sdk/widget.js:884
notify#resource://gre/modules/XPIProvider.jsm -> jar:file:///.../extensions/jid1-exo2NPaadiTkqg#jetpack.xpi!/bootstrap.js -> resource://gre/modules/commonjs/toolkit/loader.js -> resource://gre/modules/commonjs/sdk/timers.js:40
nmaier is most probably correct on why your code doesn't work but I'll still post this answer as supplementary information
First of all, you don't need to use both WebSockets and XPCOM Sockets to create extensions that are both server and client. Either one of these technologies will suffice and work fine for this purpose. Personally, having done this myself, I'd recommend using XPCOM Sockets unless you really want to create portable code between browsers (seeing as you don't mention anything like that, I recommend dropping the WebSockets implementation and sticking to XPCOM Sockets - but WebSockets are easier to handle, so you might prefer them - it doesn't matter, just pick one). I'm mentioning this since you have both the WebSocket and the XPCOM Socket listening for connections and I think it's because you want this:
ServerSocket recieves client connection -> Only recieves from client connection
WebSocket connects to server connection -> Only sends to server connection
Instead, you can just have an nsIServerSocket that both reads and sends data to another server socket. Also, as nmaier says, blocking streams are a bad idea, unless you really need them and in this case, you don't. It'll probably help things work better too, if you use asynchronous mode.
Below is a sample implementation of what you want using nsIServerSocket, which I'm including because understanding how this works took me a lot of pain and time. If you don't want the power of native-application level tcp sockets (in other words, you don't need to read binary streams or do complex handling or write your own communication protocol), WebSockets are probably adequate for you and preferrable, as they'll handle a simple messaging system fine. Simply put, if the below is not your cup of tea, just stick to WebSockets until they're not capable of serving your needs.
Note: the following code makes no attempt at namespacing and promptly thrashes the global namespace - it isn't intended to be production code, so normally, you'd want all of these variables and objects wrapped up into your extension's namespacing object.
Here is the sample implementation with nsIServerSocket and binary streams:
Preparation code
// these aliases will shorten the code
var {
utils: Cu,
interfaces: Ci,
classes: Cc,
results: Cr,
stack: Cs,
manager: Cm,
Exception: Ce,
Constructor: CC,
} = Components;
// get related services
// the thread manager can be important when using asynchronous mode
var thread_manager = Cc["#mozilla.org/thread-manager;1"].getService();
var socket_service = Cc["#mozilla.org/network/socket-transport-service;1"].getService(Ci.nsISocketTransportService);
// make some constructors so we don't have to worry about this later
var socket_c = CC("#mozilla.org/network/server-socket;1", "nsIServerSocket", "init");
var output_stream_bin_c = CC("#mozilla.org/binaryoutputstream;1", "nsIBinaryOutputStream", "setOutputStream");
var input_stream_bin_c = CC("#mozilla.org/binaryinputstream;1", "nsIBinaryInputStream", "setInputStream");
// this is so we can easily instantiate nsIInputStreamPump, which allows us to read
// input streams properly
var input_stream_pump_c = Cc["#mozilla.org/network/input-stream-pump;1"];
// normally all these would be placed in a global object. they're declared here
// so we can instantiate them later, but this is just a sample, not production code!
var input_stream_base, input_stream_async_c, input_stream_async, input_stream_bin, recieved_bytes, recieved_total, input_stream_pump;
var output_stream_base, output_stream_async_c, output_stream_async, output_stream_bin;
var client, client_input_stream, client_output_stream, client_input_stream_pump;
var data_to_send = ""; // this holds what we want to send
Make a socket
// this socket will only listen on localhost
// set the second argument to false if you want it to listen
// to connections beyond the computer the extension runs on
var socket = new socket_c(-1, true, -1);
var socket_transport = socket_service.createTransport(null, 0, "localhost", socket.port, null);
Define callbacks and listeners
// this guy will get called when we're ready to send data
var output_stream_callback = {
onOutputStreamReady: function(stream){
output_stream_bin = new output_stream_bin_c(stream);
output_stream_bin.writeBytes(data_to_send, data_to_send.length);
data_to_send = "";
}
};
var socket_reader = {
onDataAvailable: function(request, context, stream, offset, count){
input_stream_bin = new input_stream_bin_c(stream);
if(input_stream_bin.available() > 0){
recieved_bytes = input_stream_bin.readByteArray(count);
recieved_total = ""; // this holds the stuff we get
// this loop converts bytes to characters
// if you don't need to pass binary data around
// you can just use nsIScriptableInputStream instead of
// nsIBinaryInputStream and skip this
for (var i = 0; i < recieved_bytes.length; i++){
recieved_total += String.fromCharCode(recieved_bytes[i]);
}
}else{
stream.close();
// Nothing there, closing stream.
}
},
onStartRequest: function(request, context){
},
onStopRequest: function(request, context, status){
}
};
var socket_listener = {
onSocketAccepted: function(socket, transport){
client = transport;
client_input_stream = client.openInputStream(0, 0, 0);
client_output_stream = client.openOutputStream(0, 0, 0);
client_output_stream.QueryInterface(Ci.nsIAsyncOutputStream);
client_input_stream_pump[this_transport] = input_stream_pump_c.createInstance(Ci.nsIInputStreamPump);
client_input_stream_pump[this_transport].init(client_input_stream, -1, -1, 0, 0, false);
client_input_stream_pump[this_transport].asyncRead(socket_reader, socket);
},
onStopListening: function(socket, status){
}
};
Start listening on the socket
socket.asyncListen(socket_listener);
When you want to send data
(edit- this part should be placed in a function, to be called only after a connection is made and only when you want to send data)
var stream = client_output_stream; // what stream you want to send the data to
// this is the only place where the thread_manager is required
stream.asyncWait(output_stream_callback,0,0,thread_manager.mainThread);
This implementation is fully asynchronous, so it should never have a performance impact or cause problems unless there's too much data (I guess, I don't really think there would be a problem with performance before your connection caps out) or something goes wrong (such as calling .asyncWait from the output stream callback).
Your input is in recieved_total and what you want to send is placed in data_to_send before you call .asyncWait on the connected client's output stream. Remember, this is a sample implementation, so if you want to use this, you'll need to change it so that it uses namespacing and you'll need to add handling functions for whatever data you want to get or send. Also, if you expect more than 1 client connection, you'll need to handle that separately as well (by an object array or something).
If you need information on the components used, the MDN is obviously the place to go to for that. However, nsIInputStreamPump for some reason doesn't have a page. For that you'll need to go to its idl implementation in the source (nsIInputStreamPump.idl). The mozilla lxr is also a great place to check out test implementations of sockets in javascript, as there are some .js files in there that are used to test the implementations.
edit -
for the addon-sdk, this might work better:
try replacing var {Cc, Ci, Cu, Cr, components} = require("chrome"); with
var Components = require("chrome"); and then add
var {
utils: Cu,
interfaces: Ci,
classes: Cc,
results: Cr,
stack: Cs,
manager: Cm,
Exception: Ce,
Constructor: CC,
} = Components;
as was in the original code. Also, add a console.log(Components); after the require line so you can see if you're actually getting the components object.
nsISocketServer implements a simple TCP/bind server, but does not implement the websocket protocol.
You either need to implement the websocket protocol yourself in the server socket (incl. HTTP/1.1 Upgrade)
or use raw TCP sockets (nsISocketTransports via nsISocketTransportService).
Given that raw TCP sockets are usually a mess to deal with and that you'll need to implement some simple exchange protocol on top of that anyway, I'd guess the first option of implementing the websocket protocol in the server socket would be easier (at the very least, you get the client implementation for free).
PS: Blocking mode is a bad idea as it blocks the UI thread for potentially long periods of time.
PS: Apparantly, somebody implemented the websocket protocol already in coffee script and somebody else (from the Add-on SDK team) implemented it in (what appears to be some form of :p) Javascript as well (although the latter is pretty much not self-contained and hard to read/gasp).
Edit I got curious and wrote a stand-alone JS code module WebSocket server, that seems to mostly work. :p

Categories

Resources