Monday, 24 April 2017

Socket io Nodejs- manage when a user open multiple tabs

I am trying to write a chat in my app, I have an issue that have no idea how to manage it! Here is the senario: We have lot's of users that are authenricated so all of them have a unique id, I want to implement a chat like Facebook so every two users can chat with each other. For that I have a server.js file with content:

var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var redis = require('redis');
var users = [];
server.listen(8890);
io.on('connection', function (socket) {

    console.log("client connected");
    var redisClient = redis.
    redisClient.subscribe('message');

    redisClient.on("message", function(channel, data) {
        var data = JSON.parse(data);
        socket.to('user_'+data.user).emit(channel, data);
    });

    // join a room    
    socket.on('newUser',function (user, type){
        socket.type = type;
        socket.join('user_'+user); 

    }); 
});

And a client.js:

var socket = io.connect( 'http://127.0.0.1:8890' );
if (auth) {
    socket.on('connect', function(){
        socket.emit('newUser', userId, userType);
    });
}

socket.on( 'message', function( data ) {

    console.log(data);
    // var data = JSON.parse(data);
    var content = $( "#messages" ).html();
    var newMsgContent = '<li>' + data.message + '</li>';
    var newContent = newMsgContent + content;

    $( "#messages" ).html( newContent );
});

A form that message will be sent with:

<form action="" method="POST" class="ajax-form">
    <input name="_method" value="put" type="hidden"/>
    <input name="user" value="" type="hidden"/>
    <input name="item" value="" type="hidden"/>
    <input name="type" value="" type="hidden"/>
    <input name="socketId" value="" type="hidden"/>
    <input name="message" value="message to  from " type="text" class="input-xxlarge" placeHolder="Message" />
    <br>
    <input type="submit" value="Send" />
</form>

And at last with Redis I will send the message:

$redis = \LRedis::connection();
$data = ['user' => $request->user, 'message' => $request->message];
if($redis->publish('message', json_encode($data)))
   return true;

In above codes simply when a user open my app a connection will be used and newUser will fire up so I create a room for this user with his Id and join him to this room (socket.join('user_'+user)). Then when a user want to send a message to this user simply I send id of receiver user (that we created a room before for him) and send the message to the room that this Id is in it (socket.to('user_'+data.user).emit(channel, data);). The problem is that when a user open multiple tabs each one of them recognized as a user and will join to the same room with another socket.id but both are a user with one unique Id! Then when I send a message to a user that has two tabs open, he will get 2 messages from one request! like: Hello id 5 Hello id 5

So now what should I do to sent message per tab to all tabs that user opened! Thanks in advance.



via Hassan Shojaei

No comments:

Post a Comment