Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how do I store socket resources from specific users with socket.io?

I'm designing a chat script which I test on my machine using different browsers. I'm tryng to send messages to specific users with socket.io, so here it is :

client:

socket.on('msgFromServer', function (data) {
     message = data['message'],
     from = data['from'],
     to = data['to'];               

    if($('#chatbox.'+from).dialog("isOpen") === true){
        $('#chatbox.'+from+' #messageOutput textarea.readOnly').text(message);      
    }   
    else if(($('#chatbox.'+from).dialog("isOpen") !== true)){
        createChatbox(from,to,message);
    }
});




server:

var users = {};
io.sockets.on('connection', function (socket) {
    if( ( users.hasOwnProperty(req.session.name) === false))
            users[req.session.name] = socket;

    socket.on('msgToServer', function (data) {
         for (var u in users){
              console.log("%s | %s",u,users[u]);
         }      

     });
}); 

Well, I'll talk about the structure of code related to the server. It is in charge of storing a user on a 'connection' event. The problem starts when I reload the page: it stores the user from browser A in the users object, if I reload and reconnect stores it again , but when I ask which are the contents of the users object in browser B ... the info is outdated and does not show the same result as when I ask which are the contents of the object in broser A, even though I'm trying to do some cheking of nullity to store vals if users is empty --> if( ( users.hasOwnProperty(req.session.name) === false)). Basically, what I need is a means of storing each socket resource in a container(in fact, doesn't necessarily needs to be an object) with an identifier(req.session.name) and to have such container available to all sessions in all browsers, so when server receives a message from browser A to browser B it could identify it and emit a response to browser B.

I got an I idea of what I wanted from https://github.com/generalhenry/specificUser/blob/master/app.js and http://chrissilich.com/blog/socket-io-0-7-sending-messages-to-individual-clients/

If you look carefully at the code... in chrissilich.com , the author states that we need to store the 'socket.id' (users[incoming.phonenumber] = socket.id), whereas in git generalhenry states we have to store the 'socket'(users[myName] = socket) resource. The latter is the correct one , because the values of socket.id tend to be the same in both browsers... and that value changes automatically , I don't know why is there... I suppose in earlier versions of node it worked that way.

like image 782
Charlie Avatar asked Dec 15 '22 15:12

Charlie


1 Answers

The problem is that socket.id identifies sockets, not users, so if an user has several tabs opened at same time, every tab would have different socket.id, so if you store only one socket.id for an user, every time you assign it, you overwrite previous socketid.

So, beside other possible problems, at least you need to do this or it won't work. I bet that you say about 1 socket for all browsers is that you overwrite the id every time (it happened to me when I started using Socket.IO)

As a general rule, remember that you manage CONNECTIONS and not USERS... an user can have more than one connection!.

On connection

function onConnection( socket ) {
    var arr = users[incoming.phonenumber] || null;
    if( !arr ) 
        users[incoming.phonenumber] = arr = [];
    if( arr.indexOf( socket.id ) === -1 )
        arr.push( socket.id ); // Assigns socket id to user
}

On disconnection

function onDisconnect( socket ) {
    var arr = users[incoming.phonenumber] || null;
    if( !arr ) return; // Should not happen since an user must connect before being disconnected
    var index = arr.indexOf( socket.id );
    if( index !== -1 )
        arr.splice( index, 1 ); // Removes socket id from user
}
like image 83
JR. Avatar answered Jun 01 '23 16:06

JR.