Search code examples
node.jsexpresschatexpress.io

Connected clients in express.io


I'm developing a simple chat app using node.js and express.io

I would like to display a list of the connected clients (or online for chat) all the time.

In express.io's doc, there is no clear way on how to "get" the list of connected clients once a new one has entered the room, i.e there is just the "broadcast" but not the "get".

Have someone done this before?

Any clues will be really helpful.

Thanks!

Edit:

After trying @jibsales's answer. I think we are almost there. What clients returns me is not the actual array of clients but this one:

[ { id: 'OWix3sqoFZAa20NLk304',
namespace: 
 { manager: [Object],
   name: '',
   sockets: [Object],
   auth: false,
   flags: [Object],
   _events: [Object] },
manager: 
 { server: [Object],
   namespaces: [Object],
   sockets: [Object],
   _events: [Object],
   settings: [Object],
   handshaken: [Object],
   connected: [Object],
   open: [Object],
   closed: [Object],
   rooms: [Object],
   roomClients: [Object],
   oldListeners: [Object],
   sequenceNumber: 496205112,
   router: [Object],
   middleware: [],
   route: [Function],
   use: [Function],
   broadcast: [Function],
   room: [Function],
   gc: [Object] },
disconnected: false,
ackPackets: 0,
acks: {},
flags: { endpoint: '', room: '' },
readable: true,
store: { store: [Object], id: 'OWix3sqoFZAa20NLk304', data: {} },
_events: 
 { error: [Function],
   ready: [Function],
   connection: [Function],
   NewChatPrivateLine: [Function],
   NewIdea: [Function],
   NewChatLine: [Function],
   NewPost: [Function] } } ]

The functions are:

var app = require('express.io')();
app.io.route('connection', function(req) {
  req.io.join(req.data.room);
  var clients = app.io.sockets.clients(req.data.room);
  console.log(clients)
  app.io.room(req.data.room).broadcast('announce', {
    user: req.data.user,
    clients: clients
  }) 
});

This actually returns an error ( data = JSON.stringify(ev); TypeError: Converting circular structure to JSON) as the array has several circular objects and hence it cannot be broadcasted.

Any thoughts?


Solution

  • Well, finally I went with the "tacking" solution proposed by @Brad. It is not the most elegant but, if you can help me improve it, It'd be awesome!!

    This is the final code:

    Server-side

    var app = require('express.io')();
    
    //To broadcast the users online in room sent by the client
    var clients = [];
    app.io.route('connect', function (req) {
      req.io.leave(req.data.room).on('disconnect', function() {
        //To remove client from list when disconnected
        var index = clients.indexOf(req.data.user);
        if (index > -1) {
          clients.splice(index, 1);
        }
        app.io.room(req.data.room).broadcast('announce', {
          user: req.data.user,
          clients: clients
        }) 
      });
      req.io.join(req.data.room);
      //To avoid repeating the same client with several opened windows/tabs
      var index = clients.indexOf(req.data.user);
      if (index === -1) {
        clients.push(req.data.user); 
      }
      app.io.room(req.data.room).broadcast('announce', {
        user: req.data.user,
        clients: clients
      }) 
    });
    

    Client-side

    // Emit ready event with person name and predefined room for who's online
    io.emit('connect', {
      room: room,
      user: user
    });
    
    //Get the signal from server and create your list
    io.on('announce', function (data){
     //Do awesome stuff with data 
    });