Keep Reference to Connected Sockets Per User

I have a (for clarity's sake) a chat.

Users can login, write messages, and the others will see [name]:[message].

I don't want to send the user's name and ID every time I write socket.emit('say', message); because that's redundant, so what I'm doing on the server is like so:

var io = require("socket.io").listen(server),
    sockets = {};

io.sockets.on('connection', function (socket){
    socket.on('savePersonToSocket', function(user){
        socket.user = user;
        sockets[user.id] = socket;
    }
    socket.on('doSomething', doSomething);
});

// must be outside of 'connection' since I have TONS of these in a much more 
//complex structure and I don't want to create them all per user connection.
function doSomething(){
    ...
    sockets[userID].emit('foo'); // how to get the userID at this point?
    ...
}

So, how would I get the userID at that point?

Notes:

  • For each user that logs in and connects with their Facebook account, the client will tell the server to save the person's name and ID.

I thought of doing it with a cookie that saves the user's name and ID, and the server would know which user it is by reading the cookie, but that's a bit of an ugly solution: it's redundant to send that information every time.

I could also hijack the 'on' function (somehow) and add functionality that will know which user it is, because all the 'on' listeners must reside inside the 'connection' listener anyway.

What is probably happening is that a user connects to your chat application, so here

io.sockets.on('connection', function (s){
  socket = s; // cache for later usage

you assign "his socket" to the variable socket which is unbound from the context, it is on its own. Now let's say a second user arrives, socket gets reassigned with the second of the second user, but if you get a savePersonToSocket event then socket will be used, which is the same for everyone and more in detail it is related to the last user that connected.

There is no need for you to keep a reference to s, you will probably have to deal with that when you will have a lot of users connecting to your application, but the solution will be very different from your approach.

EDIT: another way could be by mapping user ids and sockets:

// this assumes that the name of a user is unique
var userSocket = {};

io.sockets.on('connection', function (s){
  socket.on('savePersonToSocket', function(user){
    userSocket[user.name] = s;
  }

So basically you are saying that you don't want to pass to doSomething event payload the userID? Because that seems like a valid solution for me, it's not redudant, it's the simplest way to let the server know about what user it is dealing with. Other solutions might be more elegant, but I doubt they are as simple and as easily maintainable as this one.

If you can save sockets under one account can sit a few people, for example, such a system would be:

var socketsList
io.sockets.on('connection', function (socket) {
   socket.on('auth', function (data) {
      // request to database
    if ( ! (UNIQUE_ID in socketsList)) {
         socketsList[UNIQUE_ID] = {};
         socketsList[UNIQUE_ID][socket.id] = socket;
   });
});

// ONEXIT - BROWSER EVENT
var onExit = function () { socket.emit('exit', { UNIQUE_ID : 123}) }
    window.onunload = onExit;
// 

socket.on('exit', function (data) {
   delete socketsList[UNIQUE_ID][socket.id]
})

Correct me if I'm wrong

you can't save the connection literally, it is changing quite frequently. however you can save the socket.id. you have io.sockets.sockets[socketid] this is probably what you are looking for.

you can save array of ids and names and reuse them if you like.

(be aware that process related variables are make it not so scaleable. but you can don't care for it the long first time :)

also you have socket related store object socket.handshake socket.handshake.somevariable=simple_value_a_string_or_a_number

Theoretically, something as ugly as this should work, but the usage of apply is bad IMHO, and the lack of simple function pointers makes the code uglier

var io = require("socket.io").listen(server);

io.sockets.on('connection', function (socket){
    socket.on('savePersonToSocket', function(user){
        socket.user = usr;
    }

    // No more simple function pointers....
    socket.on('doSomething', function(){
       // pass the Socket as the scope
       doSomething.apply(socket, arguments);
    });

});

function doSomething(){
    ...
    this.emit('foo');
    ...
}

how about this:

var io = require("socket.io").listen(server),
    sockets = {};

io.sockets.on('connection', function (socket){
    socket.on('savePersonToSocket', function(user){
        socket.user = user;
        sockets[user.id] = socket;
    }
    socket.on('doSomething', function() { doSomething(socket.user) });
});

// must be outside of 'connection' since I have TONS of these in a much more 
//complex structure and I don't want to create them all per user connection.
function doSomething(user){
    ...
    sockets[user.id].emit('foo');
    ...
}

I know it has been a long time since you asked this, but Just 4 ago I published a module for node js, express and socket.io which manages that exactly thing you wanted. Check the Usage and Example, I hope you will find this module helpful!

You can install it via NPM socket.io.users This is a node js module for socket.io applications. One user per client.

You can loook some of the usage code on this answer