socket.io Detect what room a user has disconnected from - node.js

I have found a few solutions but they seem dates and are not working.
How can I detect what room a user was disconnected from?

I don't know what do you mean about room , but if it is a chat app or something like that
you can create a variable on socket object like roomID when first connection.
io.sockets.on("connection",function(socket){
socket.on("new:user",function(userDATA){
// create variable as roomID on socket.
socket.roomID = userDATA.roomID
});
// other events
socket.on("disconnect",function(data){
var roomID = socket.roomID;
// do what you want to do
});
});

With socket.io 1.0 you can do this with following code:
socket.on('disconnect', function() {
console.log(socket.rooms);
});
It will output an array of rooms the user was joined to.
Note that each socket automatically joins a room named with this socket's ID. So you might see something like
[ 'hIP6r4z8Ym1n5SQUAAAA', 'my_room_name' ]
in your console.

Related

socket.io switching namespaces

I am currently working on a simple chat with socket.io. The basics are already working , but now I am trying to implement 2 different namespaces. I want the client to be able to toggle from one namespace (support-chat) to the other (friends-chat) by a buttonclick.
Serverside
//default namespace
io.on('connection', function(socket){
console.log('a user connected to the chat');
socket.on('disconnect', function(){
console.log('user disconnected');
});
socket.on('client message', function(msg){
io.emit('server_message', msg);
});
});
//namespace /support
var sup = io.of('/support');
sup.on('connection', function(socket){
console.log('someone entered the support-chat');
socket.on('disconnect', function(){
console.log('user disconnected from support-chat');
});
//recieving and emitting message to all clients in namespace /support
socket.on('client message', function(msg){
console.log('message received: ' + msg);
io.of('/support').emit('server_message', msg);
});
});
//namespace /friends
var frnd = io.of('/friends');
frnd.on('connection', function(socket){
console.log('someone entered the friends-chat');
socket.on('disconnect', function(){
console.log('user disconnected from friends-chat');
});
//recieving and emitting message to all clients in namespace /friends
socket.on('client message', function(msg){
console.log('message received: ' + msg);
io.of('/friends').emit('server_message', msg);
});
});
Clientside
var socket = io.connect();
//toggle namespace
$("#support_button").click(function(){
socket.disconnect();
socket = io('/support');
$('#messages').append($('<li>').text("You entered the Support-Chat"));
});
//toggle namespace
$("#friends_button").click(function(){
socket.disconnect();
socket = io('/friends');
$('#messages').append($('<li>').text("You entered the Friends-Chat"));
});
//sending message on submit
$('form').submit(function(){
socket.emit('client message', $('#m').val());
$('#m').val('');
return false;
});
//recieving message and display
socket.on('server_message', function(msg){
$('#messages').append($('<li>').text(msg));
});
});
I think the switch itself is working, because the connection- and disconnect-events are triggering like they should. But when it comes to emitting the message (the server already recieved from the client) to everyone in the same namespace, it is not working.
Isnt this the serversided call for emitting in a specific namespace?:
io.of('namespace').emit();
Do I misunderstand the usage of namespaces? I wanted to implement rooms right after the namespace-"split" of the 2 mainchats for support and friends.
Or did I implement the namespaces wrong on the serverside? I thought io.on(..), io.of('/support').on(..) and io.of('/friends').on(..) are all working the same way and catch the events of their own namespaces-clients.
Any help is highly appreciated! I feel like namespaces have been kind of neglected in there "basic-usage" documentations.
You can't "switch" namespaces on an existing connection. You connect to a specific namespace when the connection is made and once made, it can't be changed.
You could drop the current connection and connect to a new namespace with a new connection. But, given your application, you're misusing the concept of namespaces if you want to switch namespaces and should be using rooms instead.
For rooms, the client can send the server a request to switch rooms and the server can then remove the user from an existing room and add them to a new room. Then, from the server, you can easily broadcast to all connections in a given room.
In fact, rooms were invented around the concept of chat (though they have many other uses) so they are perfectly suited for the chat rooms that you wish to implement.
Namespaces are a heavier weight division than rooms. A connection must connect to a specific namespace when the connection is made and that cannot be changed during the connection.
Rooms on the other hand are a lot more flexible. The server can put a given connection add or remove a connection from a room at any time and a connection can even be in more than one room.
Both rooms and namespaces support broadcasting to all users in that collection.
I think of namespaces more like channels of functionality. So, I'd like to connect to the "price" change namespace in order to get notifications of price changes or I'd connect to the "system" namespace in order to get alerts about things happening in the system or to send messages to manage things in the system.
Whereas rooms are arbitrary collections of users interested in sharing information and I may be in more than one room.

Nodejs socket.io socket property becomes null

So I am trying to retrieve all the sockets connected to a room. However what i noticed was that adding properties to the sockets such as socket.username become undefined when accessed later on in my server script. Therefore I get an error like so TypeError: Cannot read property 'username' of undefined. I am using version 1.3.3 of the module.
here is the code that triggers the error
function clientsInRoom(room){
var clients = [];
console.log(io.sockets.adapter.rooms[room].length); // This prints out the correct number
for(var cliSocket in io.sockets.adapter.rooms[room] ){
clients.push(io.sockets.connected[cliSocket].username); // Causes exception
}
return clients;
}
io.on('connection', function(socket){
socket.on('adduser', function(username,room){
// store the room name in the socket session for this client
socket.room = room;
// store the username in the socket session for this client
socket.username = username;
// Check if they already exist in room
if(clientExists(username,room) == false){
//Tell user they have joined new room
socket.emit('updatechat','you have connected to '+ room);
//echo to room that a person has connected to their room
socket.broadcast.to(socket.room).emit('updatechat', username + ' has joined this room','con');
}
// send client to the room
socket.join(socket.room);
//Update online lists client side
io.sockets.in(socket.room).emit('updatePeople', clientsInRoom(socket.room));
});
});
If anyone could shed some light on this issue as it has been driving me insane, would be greatly appreciatd.
You're iterating over keys of io.sockets.adapter.rooms. Then using those keys to access io.sockets.connected. What you get out of io.sockets.connected is undefined, not your saved username.
Check this iteration code, this is where the problem is.
There were discrepancies between my node modules that caused this problem. Manually copying the modules from an older release resolved the issue

Reconnect socket in disconnect event

I am trying to reconnecct the socket after the disconnect event is fired with same socket.id here is my socket config
var http = require('http').Server(app);
var io = require('socket.io')(http);
var connect_clients = [] //here would be the list of socket.id of connected users
http.listen(3000, function () {
console.log('listening on *:3000');
});
So on disconnect event i want to reconnect the disconnected user with same socket.id if possible
socket.on('disconnect',function(){
var disconnect_id = socket.id; //i want reconnect the users here
});
By default, Socket.IO does not have a server-side logic for reconnecting. Which means each time a client wants to connect, a new socket object is created, thus it has a new id. It's up to you to implement reconnection.
In order to do so, you will need a way to store something for this user. If you have any kind of authentication (passport for example) - using socket.request you will have the initial HTTP request fired before the upgrade happened. So from there, you can have all kind of cookies and data already stored.
If you don't want to store anything in cookies, the easiest thing to do is send back to client specific information about himself, on connect. Then, when user tries to reconnect, send this information again. Something like:
var client2socket = {};
io.on('connect', function(socket) {
var uid = Math.random(); // some really unique id :)
client2socket[uid] = socket;
socket.on('authenticate', function(userID) {
delete client2socket[uid]; // remove the "new" socket
client2socket[userID] = socket; // replace "old" socket
});
});
Keep in mind this is just a sample and you need to implement something a little bit better :) Maybe send the information as a request param, or store it another way - whatever works for you.

socket.io: how to make server run functions when disconnection from a room

Trying to learn socket io and I'm playing around with a test application where:
Sockets join different rooms depending on the page url (/page1 connections join room page1, etc)
I have a separate 'dashboard' page which I want to show how many connections are from each page
I have two problems (the documentation is confusing me):
When a user disconnects, I don't know how to determine which room they were in and hence do different functions depending on the room.
Here is my attempt:
Server Code
io.on('connection', function(socket){
socket.on('joinRoom', function(room){
console.log('New connection to room: ' + room);
socket.join(room); // Clients join different rooms depending on the page.
console.log(socket.rooms); // socket.rooms here has a value
// code to increment room counter will go here.
});
socket.on('disconnect', function(){
console.log(socket.rooms); // In this line, socket.rooms is EMPTY
if (socket.rooms == room1){
// decrement room 1 counter
}
});
});
Client Code
var socket = io();
socket.on('connect', function(){
socket.emit('joinRoom', 'client');
});
My next problem, I can't seem to get the right syntax for the client to emit to a room / the server to react to messages coming from a specific room. If someone could give me an example to follow it would be extremely helpful.
Thanks for reading.
Upon join you need to "register" the room for the socket like the following:
currentRoom[socket.id] = room.newRoom;
and when they leave just call:
socket.leave(currentRoom[socket.id]);
this should do.

Hosting multiple instances of a node.js server

I'm new to node.js and I'm working on learning how to use Socket.io to create multiple chat servers on my domain.
Here's the scenario:
you log onto the site
you pick a chat room or create a chat room
you join that individual chat room while other chat rooms are going on at the same time
Pretty standard operation on the web but I have yet to find a way to do it. Specifically, how to host it on your domain.
When creating and testing I always just use my localhost and tell the server to listen(8000) . However, how do write a script that:
A) creates a new listening port dynamically for each new chat sever?
B) how do I host it (I use Hostmonster)?
Instead of creating a separate server for each chat room, you could run all of them from the same server and just maintain a map of chat room name to the sockets involved in it.
For example,
//store a map of chat room name to sockets here
var chatRooms = {};
io.sockets.on('connection', function (socket) {
//when someone wants to join a chat room, check to see if the chat room name already exists, create it if it doesn't, and add the socket to the chat room
socket.on('joinChatRoom', function (data.message) {
var chatRoomName = data.message;
chatRooms[chatRoomName] = chatRooms[chatRoomName] || [];
chatRooms[chatRoomName].push(socket);
//set the chatRoomName into the socket so we can access it later
socket.set( "chatRoomName", chatRoomName, function() {
//when we receive a message
socket.on( "chatMessage", function(data) {
var chatMessage = data.message;
//figure out what chat room this socket belongs to
socket.get( "chatRoomName", function(err,chatRoomName) {
//iterate over the sockets in the chat room and send the message
chatRooms[chatRoomName].each(function( chatRoomSocket ) {
chatRoomSocket.emit("chatMessage", { message : chatMessage } );
});
});
});
});
});
});
Note, this code is untested and is just an idea (you should probably treat it more like pseudocode). There are a bunch of things it doesn't handle like cleanup upon disconnects, errors, etc. There are probably lots of other (and better) ways to accomplish this too but hopefully it'll give you some more ideas.

Resources