emit to all sockets not working Socket.io - javascript

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});
}

Related

Node.js, Socket.io emit not working

I am making a website in Socket.io. But emit method not working in my code. I can't see any errors in my code. Here is my server code.
var io = require("socket.io").listen(server);
//Some external codes for running server in Node.js
io.on("connection", function(socket) {
//This line is working.
console.log("Socket connected.");
io.on("requestNewMap", function(data) {
//Create new map object in here.
io.emit("responseNewMap", { mapData: map });
});
});
And this is my client side javascript code.
var socket = io();
socket.on("responseNewMap", function(data) {
var map = data.mapData;
//Draw map in canvas's context.
});
//setInterval runs this method every 2 seconds.
function requestNewMap() {
socket.emit("requestNewMap");
}
This part could be wrong:
io.on("requestNewMap", function(data) {
//Create new map object in here.
io.emit("responseNewMap", { mapData: map });
});
I would use socket there as in:
socket.on("requestNewMap", function(data) {
//Create new map object in here.
socket.emit("responseNewMap", { mapData: map });
});
I think io.emit should work fine, it would just send the response to every connected client, but io.on('requestNewMap',...) won't work since requestNewMap is not an io standard event.
change this
io.on("requestNewMap", function(data) {
//Create new map object in here.
io.emit("responseNewMap", { mapData: map });
});
into this
socket.on("requestNewMap", function(data) {
//Create new map object in here.
socket.emit("responseNewMap", { mapData: map });
});
you are adding an event listener to the server object not the client socket.
I'm not certain, but I believe your problem is that your function on the client side is written like you are expective 'requestNewMap' to be passing along data.
Instead of:
io.on("requestNewMap", function(data){
Try:
io.on("requestNewMap", function(){
OR pass an empty object or some other kind of junk data along with the emit from client side like this:
function requestNewMap() {
socket.emit("requestNewMap", {});
}
function requestNewMap() {
socket.emit("requestNewMap", undefined);
}
function requestNewMap() {
socket.emit("requestNewMap", -1);
}
Hopefully this is helpful and correct!
Edit: This turned out to not be the answer to your question, but still something worth considering. If you're not passing data along you should avoid writing the event handler as if it expects data.
This works fine only you want to send the "responseNewMap" event back to the sender only.
socket.on("requestNewMap", function(data) {
//Create new map object in here.
socket.emit("responseNewMap", { mapData: map });
});
Implement this if you want to send the event back to all connected users
socket.on("requestNewMap", function(data) {
//Create new map object in here.
io.emit("responseNewMap", { mapData: map });
});
If you use a namespace like this:
io.of('/api/v1/chat').on('connection', function (socket) {
//Your code here
});
Then include a namespace like this:
io.of('/api/v1/chat').emit("responseNewMap", { mapData: map })
I'm going to respond to this as a note to myself and others on the whole socket.emit is not working situation...
So I had issues with socket.emit not firing to the socket that made the initial request out. The issue was not an issue, more so the way client works. I was indeed emitting to the originator only when using socket.emit (which is what I wanted, only the requested got the response) but the issue was that I had more than one socket on in my app.
I use ES6 and imports (import 'path to socket io client js') which is also an issue without webpack unless you do it like that, as i have my own web component framework.
I had 3 components all creating a socket from io(), expecting them to use the same manager and they where not.
socket.io will not use the same manager over many mjs files all creating this.socket = io(); they are indeed all new isolated sockets! So take this in mind, you may be returning the message to the socket that sent the request out but if your listener is in another component than thats got a different socket.id and in essence is a whole new socket connection.
There is an option to pass in to io called forceNew which is true by default so it appears, but changing this still gave me the same issues albeit the ID's where all now the same, however I still could not seem to get a listening component to get responses from an action in an action component even though both had the same ID now. A bug maybe or something else, not sure.
So short answer is importing via ES6 without webpack needs to be just import 'fsdfsd.js'; and to save issues, only generate one socket and share between components, which you may want to do anyway as sockets are not cheap and you dont want to use many for one app!
This is my first time playing with sockets, they are great, but use sparingly and do not hold them open if you want authenticated people only, drop if not authed!
Hope this helps someone, had me lost for a day or too.
In my case, setting homepage to "." in package.json fixed the problem.

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!");

Streaming data from the Server to Client with Meteor:

I'm developing a text based adventure game with Meteor and I'm running into an issue with how to handle certain elements. Namely, how to emit data from the Server to the Client without any input from the Client.
The idea is that when a player is engaged in combat with a monster, the combat damage and updating the Player and Monster objects will be occurring in a loop on the server. When the player takes damage it should accordingly update the client UI. Is something like this possible with Publish / Subscribe?
I basically want something that sits and listens for events from the server to update the combat log accordingly.
In pseudo-code, this is something along the lines of what I'm looking for:
// Client Side:
Meteor.call("runCommand", "attack monster");
// Server Side
Meteor.methods({
runCommand: function(input) {
// Take input, run the loop to begin combat,
// whenever the user takes damage update the
// client UI and output a line saying how much
// damage the player just received and by who
}
});
I understand that you can publish a collection to the client, but that's not really as specific of a function I'm looking for, I don't want to publish the entire Player object to the client, I just want to tell the client to write a line to a textbox saying something like "You were hit for 12 damage by a monster!".
I was hoping there was a function similar to SocketIO where I could, if I wanted to, just emit an event to the client telling it to update the UI. I think I can use SocketIO for this if I need to, but people seemed to be adamant that something like this was doable with Meteor entirely without SocketIO, I just don't really understand how.
The only outs I see to this scenario are: writing all of the game logic client-side which feels like a bad idea, writing all of the combat logs to a collection which seems extremely excessive (but maybe it's not?), or using some sort of SocketIO type-tool to just emit messages to the client to tell it to write a new line to the text box.
Using Meteor, create a combat log collection seem to be the simplest option you have.
You can only listen on added event and then clear the collection when the combat is over.
It should be something like this :
var cursor = Combat_Log.find();
var handleCombatLog = cursor.observe({
added: function (tmp)
{
// do your stuff
}
});
I ask a similar question here, hope this will help ^^
Here's how I did it without a collection. I think you are right to be concerned about creating one. That would not be a good idea. First install Streamy.
https://atmospherejs.com/yuukan/streamy
Then on the server
//find active sockets for the user by id
var sockets = Streamy.socketsForUsers(USER_ID_HERE)._sockets
if (!Array.isArray(sockets) || !sockets.length) {
//user is not logged in
} else {
//send event to all open browser windows for the user
sockets.forEach((socket) => {
Streamy.emit('ddpEvent', { yourKey:yourValue }, socket);
})
}
Then in the client, respond to it like this:
Streamy.on('ddpEvent', function(data) {
console.log("data is ", data); //prints out {yourKey:yourValue}
});

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 ensure order of outbound messages

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.

Categories

Resources