Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Count number of online users with nodeJS and Socket.io without duplicates

I'm having trouble displaying the correct amount of online users. A question similar to this have shown me that I can count the users this way:

var count = 0
  socket.on('connection', function(client) {
  count++;
  client.broadcast({count:count})
  client.on('disconnect', function(){
    count--;
  })
})

The issue I'm constantly running into with that method is that when a user happens to reload the page too quickly, the counter pulls in too much it can throw out.

enter image description here

As you can see, on the right side of the image, a user spammed the reload and it caught more users online than there actually is. (There was only one user on the server at this time)

My question is is there a better or more reliable way to count the exact amount users online without the extra 'virtual users', without using the users++/users-- method?

like image 272
Ackados Avatar asked Mar 08 '23 11:03

Ackados


2 Answers

If they're logging in as a user, then you should authenticate them to the socket. Use that authentication to see if they already have a session, and disconnect them decrementing the count, before you increment it again with the new session.

An example below. The clients objects stores the connected clients, with values being the sockets they're connected to.

var clients = {};
socket.on('connection', function(client) {
  //Authenticate the client (Using query string parameters, auth tokens, etc...), and return the userID if the user.
  var userId = authenticate(client);

  if ( !userId ) {
    //Bad authentication, disconnect them
    client.disconnect();
    return;
  }

  if (clients[userId]) {
    //They already have a session, disconnect
    clients[userId].disconnect();
  }

  //Set session here
  clients[userId] = client;

  client.broadcast({count: Object.keys(clients).length})
  client.on('disconnect', function(){
    delete clients[userId];
  })
})
like image 186
ugh StackExchange Avatar answered Apr 30 '23 04:04

ugh StackExchange


Could do this pretty cleanly with the Observable pattern (using RxJS v5 here):

const { Observable } = require('rxjs')

const connections = Observable.fromEvent(socket, 'connection').mapTo(1)
const disconnections = Observable.fromEvent(socket, 'disconnect').mapTo(-1)

// emit 1 for connection, -1 for disconnection
Observable.merge(connections, disconnections)
  .scan((total, change) => total + change, 0) // emit total
  .subscribe(count => client.broadcast({ count }))
like image 39
Leon Li Avatar answered Apr 30 '23 04:04

Leon Li