How to ensure order of outbound messages - javascript

I'm looking for advice as to the best way to solve a problem I'm having with sending messages over a socket. I need to make sure to preserve the order the messages are sent, i.e. first in first out, even when I can't guarantee that the socket is always open.
I have a network manager in my program, with a send method. This send method takes a message object and then attempts to push it out over the socket.
However, sometimes the socket will be closed, due to lost network connectivity, and I need to stop sending messages and queue up any new messages while I'm waiting for the socket to reopen. When the socket reopens, the queued messages should be sent in order.
I'm working with Javascript and Websockets. I have something like this right now, but it seems flawed:
function send(msg) {
if (msg) {
outbox.push(msg);
}
if (!readyState) {
return setTimeout(send, 100);
}
while (outbox.length) {
socket.send(outbox.shift());
}
}
Has anyone ever tackled a problem like this before? I'm looking for a general approach to structuring the program or perhaps an algorithm that can be used.

Adam. Here's a slightly more complete answer. If I were you, I'd wrap this up in a connection object.
function send(msg) {
if (msg) {
if (socket.readyState === socket.OPEN) {
socket.send(msg);
} else {
outbox.push(msg);
}
}
}
socket.onopen = function() {
while(outbox.length) {
socket.send(outbox.shift());
}
}

Are you just asking in general as far as structuring?
Have you thought of using logic with push() pop() shift() and unshift()?
Essentially on a socket error callback of some sort, push() the messages into a stack. When the socket can be opened or you want to try and push the messages again, you can shift() the correct object out. You could use whatever combination of those to get the right ordering of the messages.

Related

emit to all sockets not working Socket.io

I'm trying to emit a message to all sockets connected to my server using socket.io. So far, the code is as follows:
if(electionExists) {
var connectedClients = io.sockets.adapter.rooms[electionRequested].sockets;
for(client in connectedClients) {
socket.to(client).emit("isVoteValid", {voteToValidate: voteToValidate});
}
}
I made sure that it enters the if(electionExists) condition. Also, I've printed out the array of connected clients, which looks like this:
{ SdiVoIUuGfFL5AJXAAAA: true, 'wLh-EfkAIrWpjx6nAAAC': true }
and just for the sake of it, I printed each client in the loop, which leads to this:
SdiVoIUuGfFL5AJXAAAA
wLh-EfkAIrWpjx6nAAAC
Therefore, I'm led to believe that the problem is not on getting the proper socket id's. However, the emit event doesn't work. On the client side I have this:
socket.on("isVoteValid", function(obj) {
console.log("it enters isVoteValid");
});
which is really, really simple but the console.log never happens. I really can't see why it is not working. Anyone got an idea?
If you wanted to broadcast your message then use following code
if(electionExists) {
socket.broadcast.emit("isVoteValid", {voteToValidate: voteToValidate});
}
or you can also use this
if(electionExists) {
io.sockets.emit("isVoteValid", {voteToValidate: voteToValidate});
}

p2p/NodeJS: Undocumented code does not tell us how to send messages through the network

We are at a standstill with a dead repository and would like to bring it back to life. Our only problem is, it's lacks so much documentation, it's almost unusable.
We are able to make a connection to the network, show when people connect, disconnect, and who all is online.
Here is the repo in question. The file to keep an eye on is /lib/node.js (not to be confused with NodeJS itself).
Here is what we have to show for it:
var Node = require('n2n').Node;
var node = new Node(5146);
console.log("Connecting to the network...\n\n\n");
node.connect([{ host: 'bradleypl.us', port: 5146 }]);
node.on('online', function () {
console.log('Your ID:', this.id);
console.log('Online ids:', node.sortedIds);
});
//just for testing, this will spam the terminal if repeated every time.
node.on('node::online', function (newNode) {
console.log('Someone is online:', newNode.id);
});
//just for testing, this will spam the terminal if repeated every time.
node.on('node::offline', function () {
console.log('Someone just left!');
});
This is where we have no idea what to so. Now how does one send messages? We can see something like:
node.broadcast("node::test","message");
Being used to send a "node::test" event to everyone on the network. That is then received with:
node.on("node::test", function (message) {
console.log("New message:",message);
}
But that doesn't work... Any idea?
It appears from a brief look at the code that you should be doing this:
node.send("test", "message")
Also there's not much there...you may be better off just rewriting what you need instead of trying to make sense of an undocumented small lib. Just my 2 cents.
Someone helped me find the solution, it appears that it emits 2 arguments when sending messages.
//node::eventName, function handles senderID and data
node.on("node::test", function (sentFrom, message) {
console.log("New message:",message);
}
Also, to send a message, you must use:
// userID, eventName, data (in this case, a string)
node.send("userid-342trw-tq34t3w-44q3t","test","Hello, World!");

Strange issue with socket.on method

I am facing a strange issue with calling socket.on methods from the Javascript client. Consider below code:
for(var i=0;i<2;i++) {
var socket = io.connect('http://localhost:5000/');
socket.emit('getLoad');
socket.on('cpuUsage',function(data) {
document.write(data);
});
}
Here basically I am calling a cpuUsage event which is emitted by socket server, but for each iteration I am getting the same value. This is the output:
0.03549148310035006
0.03549148310035006
0.03549148310035006
0.03549148310035006
Edit: Server side code, basically I am using node-usage library to calculate CPU usage:
socket.on('getLoad', function (data) {
usage.lookup(pid, function(err, result) {
cpuUsage = result.cpu;
memUsage = result.memory;
console.log("Cpu Usage1: " + cpuUsage);
console.log("Cpu Usage2: " + memUsage);
/*socket.emit('cpuUsage',result.cpu);
socket.emit('memUsage',result.memory);*/
socket.emit('cpuUsage',cpuUsage);
socket.emit('memUsage',memUsage);
});
});
Where as in the server side, I am getting different values for each emit and socket.on. I am very much feeling strange why this is happening. I tried setting data = null after each socket.on call, but still it prints the same value. I don't know what phrase to search, so I posted. Can anyone please guide me?
Please note: I am basically Java developer and have a less experience in Javascript side.
You are making the assumption that when you use .emit(), a subsequent .on() will wait for a reply, but that's not how socket.io works.
Your code basically does this:
it emits two getLoad messages directly after each other (which is probably why the returning value is the same);
it installs two handlers for a returning cpuUsage message being sent by the server;
This also means that each time you run your loop, you're installing more and more handlers for the same message.
Now I'm not sure what exactly it is you want. If you want to periodically request the CPU load, use setInterval or setTimeout. If you want to send a message to the server and want to 'wait' for a response, you may want to use acknowledgement functions (not very well documented, but see this blog post).
But you should assume that for each type of message, you should only call socket.on('MESSAGETYPE', ) once during the runtime of your code.
EDIT: here's an example client-side setup for a periodic poll of the data:
var socket = io.connect(...);
socket.on('connect', function() {
// Handle the server response:
socket.on('cpuUsage', function(data) {
document.write(data);
});
// Start an interval to query the server for the load every 30 seconds:
setInterval(function() {
socket.emit('getLoad');
}, 30 * 1000); // milliseconds
});
Use this line instead:
var socket = io.connect('iptoserver', {'force new connection': true});
Replace iptoserver with the actual ip to the server of course, in this case localhost.
Edit.
That is, if you want to create multiple clients.
Else you have to place your initiation of the socket variable before the for loop.
I suspected the call returns average CPU usage at the time of startup, which seems to be the case here. Checking the node-usage documentation page (average-cpu-usage-vs-current-cpu-usage) I found:
By default CPU Percentage provided is an average from the starting
time of the process. It does not correctly reflect the current CPU
usage. (this is also a problem with linux ps utility)
But If you call usage.lookup() continuously for a given pid, you can
turn on keepHistory flag and you'll get the CPU usage since last time
you track the usage. This reflects the current CPU usage.
Also given the example how to use it.
var pid = process.pid;
var options = { keepHistory: true }
usage.lookup(pid, options, function(err, result) {
});

How to wait for client response with socket.io?

I'm working on an online, turned based game in order to teach myself Node.js and Socket.IO. Some aspects of the game are resolved serverside. At one point during one of these functions, the server may require input from the clients. Is there a way I can "pause" the resolution of the server's function in order to wait for the clients to respond (via a var x = window.prompt)?
Here's an idea of the code I'm working with:
Server:
for (some loop){
if (some condition){
request input via io.sockets.socket(userSocket[i]).emit('requestInput', data)
}
}
Client:
socket.on('requestInput', function (data) {
var input = window.prompt('What is your input regarding ' + data + '?');
//send input back to the server
socket.emit('refresh', input)
});
Any thoughts?
I don't think that is possible.
for (some loop){
if (some condition){
request input via io.sockets.socket(userSocket[i]).emit('requestInput', data)
/* Even if you were able to pause the execution here, there is no way to resume it when client emits the 'refresh' event with user input */
}
}
What you can do instead is emit all 'requestInput' events without pausing and save all responses you will get in socket.on('refresh',function(){}) event in an array, then you can process this array later. I don't know what your exact requirement is but let me know if that works.
Since you are emitting socket.emit('refresh', input) on the client side, you just need to set up a socket event listener on the server side as well. For example:
io.sockets.on('connection', function (socket) {
socket.on('refresh', function (data) {
console.log(data) //input
});
})
I will also point out, so that you don't run into trouble down the line, that indefinite loops are a big nono in node. Nodejs runs on a single thread so you are actually blocking ALL clients as long as your loop is running.

How to synchronise multiple RESTFul requests when using NodeJS and saving to MongoDB?

I have been trying to implement a RESTFul API with NodeJS and I use Mongoose (MongoDB) as the database backend.
The following example code registers multiple users with the same username when requests are sent at the same time, which is not what I desire. Although I tried to add a check!
I know this happens because of the asynchronous nature of NodeJS, but I could not find a method to do this properly. It looks like "findOne" method immediately returns, causing registerUser to return and then another request is processed.
By the way, I don't want to check for existing users with a separate API function, I need to check at the registration stage. Is there any way to do this?
Controller.prototype.registerUser = function (req, res) {
Users.findOne({'user_name': req.body.user_name}, function(err, user) {
if(!user) {
new User({user_name: req.body.user_name}).save(function(err) {
if(!err) {
res.send("User saved");
} else {
res.send("DB Error: Could not save user!");
}
});
} else {
res.send("User exists");
}
});
}
You should consider setting the user_name to be unique in the Schema. That would ensure that the user_name stays unique even if simultaneous requests are made to set an identical user name.
Yes, the reason this is happening is as you suspected because multiple requests can execute the code simultaneously and therefore the User.fineOne can return false multiple times. Incidentally this can happen with other stacks as well, even ones that use one thread per request.
To solve this, you need a way to somehow either control that just one user is being worked on at the time, you can accomplish this by adding all registerUser requests to a queue and then pulling them off the queue one by one and calling res.Send only after it's processed form the queue.
Alternatively, maybe you can keep a local array of user names, and each time a new request comes in and check the array if it's already there. If it isn't add it to the array and work on it. If it is in the array, send the response "User exists". Then, once the user has been successfully created, you can remove it from that array. (I haven't thought this one through 100% but I think it should work as well.)

Categories

Resources