How get socket.io Broadcast messages on client side? - node.js

I'm trying send a broadcast message from Server to clients, follow the docs avaiable at https://socket.io/docs/
And doesn't work
I tryed of two forms at server side
io.emit('update_status',{ device: device.id, status: 'Dead'});
or
socket.broadcast.emit({ device: device.id, status: 'Dead'});
At Client Side
socket.on('update_status',function(data) {
console.log('update_status',data);
});
or
socket.on('message',function(data) {
console.log('message ',data);
});
Any message arrives at client side.
I need to understand what I am doing wrong.
UPDATE
I found the solution with the help of #Azka. I do not know why, but using the variable socket soon after initiate the socket on the client side works, started to receiving messages.
var socket = io ();
socket.on ('message', function (data) {
console.log ('message', data);
});
Another thing with helps me is using debug at client side.
Paste at Browser console to read all incoming messages
localStorage.debug = 'socket.io-client:socket';
The Problem is: After the socket was added at room stopped to Receive Broadcast
Any sugestions?

Related

Socket.io emit not called

I am trying to emit two things from disconnection, and one is a redirect.
Server side:
socket.on('disconnect', () => {
socket.broadcast.emit('user-disconnected', users[socket.id]);
socket.emit('redirect', destination);
console.log('disconnect: '+ users[socket.id]);
delete users[socket.id];
});
Client side:
This gets called greatly:
socket.on('user-disconnected', username => {
appendMessage(username+ ' est parti.');
removeUser(username);
});
This does not:
socket.on('redirect', function(destination) { // never gets called…
window.location.href = destination;
});
Do you know why my server-side gets called, user-disconnected does, but not my redirect ?
Thank you so much if you help!
You are sending:
socket.emit('redirect', destination);
to a socket that has just disconnected. You're literally trying to send the message from the disconnect event. That socket isn't able to send more messages. You can do socket.broadcast.emit(...) to send to all the other sockets, but not to this one.

Socket.io + Redis - clients are joining each others' "private" rooms

I've just started working with Socket.io and Redis for pub/sub messaging and it's pretty great. One important feature of my application is that the server needs to be able to broadcast messages to all subscribers of a room, and also choose 1 subscriber in that room and narrowcast a message just to them. For now, that subscriber is chosen at random. Based on reading socket.io's documentation, I think I can accomplish this.
However, I've come across something I don't understand. In Socket.io's Default Room documentation (https://socket.io/docs/rooms-and-namespaces/#default-room), they say that each socket automatically joins a room named after its socket ID. This looks like it would solve my narrowcast requirement -- look at the list of client IDs connected to my "big" room, choose one at random, and then send a message to the room with the same name as the chosen ID.
However, it doesn't work because for some reason all clients are joining each others' default rooms. I'm not seeing any exceptions in my code, but my "narrowcast" messages are going to all clients.
Here's my server-side code:
var io = require('socket.io');
var redisAdapter = require('socket.io-redis');
var server = io();
server.adapter(redisAdapter({ host: 'localhost', port: 6379 }))
server.on('connect', (socket) => {
console.log(`${socket.id} connected!`);
socket.join('new');
server.emit('welcome', `Please give a warm welcome to ${socket.id}!`);
server.to(socket.id).emit('private', 'Just between you and me, I think you are going to like it here');
});
server.listen(3000);
setInterval(whisperAtRandom, 2000);
function whisperAtRandom() {
server.in('new').adapter.clients((err, clients) => {
if (err) throw err;
console.log('Clients on channel "new": ', clients);
chosenOne = clients[Math.floor(Math.random()*clients.length)];
console.log(`Whispering to ${chosenOne}`);
server.to(chosenOne).emit('private', { message: `Psssst... hey there ${chosenOne}`});
server.in(chosenOne).adapter.clients((err, clients) => {
console.log(`Clients in ${chosenOne}: ${clients}`)
})
});
}
It stands up the server, listens on port 3000, and then every 2 seconds sends a message to a random client in the "new" room. It also logs out the list of clients who are connected to the "new" room and the "" room.
Here's the client-side code:
var sock = require('socket.io-client')('http://localhost:3000');
sock.connect();
sock.on('update', (data) => {
console.log('Updating...');
console.log(data);
});
sock.on('new', (data) => {
console.log(`${sock.id} accepting request for new`);
console.log(data.message);
});
sock.on('welcome', (data) => {
console.log('A new challenger enters the ring');
console.log(data);
});
sock.on('private', (data) => {
console.log(`A private message for me, ${sock.id}???`);
console.log(data);
});
My problem is that all my clients are connected to each others' "" room. Here's a sample from my logs:
0|socket-s | Clients on channel "new": [ 'dJaoZd6amTfdQy5NAAAA', 'bwG1yTT46dr5R_G6AAAB' ]
0|socket-s | Whispering to bwG1yTT46dr5R_G6AAAB
2|socket-c | A private message for me, dJaoZd6amTfdQy5NAAAA???
2|socket-c | Psssst... hey there bwG1yTT46dr5R_G6AAAB
1|socket-c | A private message for me, bwG1yTT46dr5R_G6AAAB???
1|socket-c | Psssst... hey there bwG1yTT46dr5R_G6AAAB
0|socket-s | Clients in bwG1yTT46dr5R_G6AAAB: dJaoZd6amTfdQy5NAAAA,bwG1yTT46dr5R_G6AAAB
You can see that the "private" message is received by both clients, dJaoZ... and bwG1y..., and that both clients are connected to the default room for bwG1y....
Why is this? Does it have something to do with the fact that both of my clients are running on the same machine (with different Node processes)? Am I missing something in Socket.io's documentation? Any help is appreciated!
PS -- to add even more confusion, the private messaging that occurs in server.on('connect', ... works! Each clients receives the "Just between you and me ..." message exactly once, right after they connect to the server.
Your main problem could caused by server.to in whisperAtRandom function, use socket instead of server for the private message:
socket.to(chosenOne).emit('private', { message: `Psssst... hey there ${chosenOne}`});
To answer your other problems, try to change these:
server.emit('welcome', `Please give a warm welcome to ${socket.id}!`);
server.to(socket.id).emit('private', 'Just between you and me, I think you are going to like it here');
To:
socket.broadcast.emit('welcome', `Please give a warm welcome to ${socket.id}!`);
socket.emit('private', 'Just between you and me, I think you are going to like it here');
Check out my Socket.IO Cheatsheet:
// Socket.IO Cheatsheet
// Add socket to room
socket.join('some room');
// Remove socket from room
socket.leave('some room');
// Send to current client
socket.emit('message', 'this is a test');
// Send to all clients include sender
io.sockets.emit('message', 'this is a test');
// Send to all clients except sender
socket.broadcast.emit('message', 'this is a test');
// Send to all clients in 'game' room(channel) except sender
socket.broadcast.to('game').emit('message', 'this is a test');
// Send to all clients in 'game' room(channel) include sender
io.sockets.in('game').emit('message', 'this is a test');
// sending to individual socket id
socket.to(socketId).emit('hey', 'I just met you');

Node.js Express rendering multiple subsequent views

I want to do something like:
//client -> notifies server that client is connected.
//server -> begins fetching information from DB (series of both async and synchronous requests).
//as sets of data become available on server -> server pushes updates to client via res.render()
Basically I have a menu item on the client, and I want to update that menu as the data that the server fetches gets ready. is there any way to do this? I notice I can't do
res.render('something');
// again
res.render('somethingElse');
Because once render is called, then the response is sent, and render cannot be called again
"Error: Can't set headers after they are sent."
Any suggestions?
You might benefit from using WebSockets:
http://en.wikipedia.org/wiki/WebSocket
This post has a little bit of info:
Which websocket library to use with Node.js?
HTTP works via request/response. Typically once the response is sent, the connection is terminated.
To stream data from the server to client, you can use websockets. There is a very popular node.js module called socket.io, which simplifies using websockets.
Using socket.io, the client code would look like this:
var socket = io.connect('http://yourserver.com');
socket.on('data', function (data) {
updateMenu(data);
});
And the server code:
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
socket.emit('data', data);
getMoreDataFromDb(function(data){
socket.emit('data', data);
});
// etc..
});
Alternatively, if you want a simpler solution, you can just make multiple small ajax requests to the server, until you get all your data:
(function getData(dataId){
$.ajax({
url:"yourserver.com/getdata",
data: dataId || {},
success:function(data){
updateMenu(data);
if(data) getData({ lastDataReceived: data.lastId }); // server is still returning data, request more
}
});
})();

node.js only one client is receiving the messages

As far as I know, unless told otherwise, if the server sends a message, all clients should receive it. But in my case only one client is getting the messages.
client :
(function () {
window.Network = {
socket : null,
initialize : function(socketURL) {
this.socket = io.connect(socketURL);
this.socket.on('new move', this.add);
},
add : function(data) {
var msg = $('<div class="msg"></div>')
.append('<span class="text">' + data.x+'/'+data.y + '</span>');
$('#messages')
.append(msg)
.animate({scrollTop: $('#messages').prop('scrollHeight')}, 0);
},
send : function(data) {
this.socket.emit("move",data);
return false;
}
};
}());
server:
io.sockets.on('connection', function (socket) {
socket.on('move', function (data) {
console.log(data);
socket.emit("new move",data);
});
});
If I open several clients and use "send" function, only the client that sent it receives the emit from the server.
Any idea what I am doing wrong?
Thanks
To emit globally on the server side use this :
io.sockets.emit('new move', 'data1');
To emit to the current socket :
socket.emit('function', 'data1', 'data2');
To broadcast to everyone but the client :
socket.broadcast.emit('function', 'data1', 'data2');
Source
When you are using socket, you are talking directly to the connected client.
You can use rooms however, un this snippet i add the socket to room1
// Add the player socket, to the room.
socket.join('room1');
Then you can emit to all client in a room by
io.sockets.in('room1').emit('startGame', true);
The code is working just as it is supposed to. You are doing socket.emit("new move",data);, which will emit a new move event back to that specific socket, which in your case is the same socket that connected.
If you also want it to be sent to other clients that are connected, then you need to explicitly emit the event to other clients.
socket.emit("new move",data);
socket.broadcast.emit("new move",data);

twitter-node detecting connection end

I'm using the twitter-node library for node.js and it works well, however I'm having some minor difficulty handling disconnects.
When twitter disconnects me (I'm connecting a second time from the same server to force a disconnect so I can make sure I'm handling these sorts of issues) it doesn't produce an error or an end event.I thought the following would handle it:
var twitter = new TwitterNode({
user : opts.account,
password : opts.password,
track : opts.hashtags,
follow : opts.follow
});
// omitted handlers for receiving tweets/deletes/limit info, but its there
twitter.addListener('error', function(error) {
console.log('error occoured:' + error.message);
}).addListener('end', function(resp) {
sys.puts("wave goodbye... " + resp.statusCode);
}).stream();
However, I don't get either the message from 'end' or 'error' when I'm disconnected. Anyone familiar with this issue?
For anyone having this same issue:
There's no notification from twitter-node because it doesn't handle the https libraries close event - by going into the source and adding:
response.on('close', function() { twit.emit('close',this); }
The library now emits a close event when the connection is closed by the remote server (twitter) and you can handle it with a listener in your code like this:
twitterStreamReader = new TwitterNode({...});
twitterStreamReader.addListener('close', function(resp) {
sys.puts('The server connection has been closed. You may want to do something about that.');
});

Resources