node-websocket-server: possible to have multiple, separate "broadcasts" for a single node.js process?


Question

I'd like to know if it's possible to broadcast on different websocket "connections" running from the same node-websocket-server app instance. Imagine a chatroom server with multiple rooms, only broadcasting messages to the participants specific to each room, on a single node.js server process. I've successfully implemented a one-chatroom-per-process solution, but I want to take it to the next level.

1
57
7/5/2014 12:54:33 PM

Accepted Answer

You would probably like to try Push-it: http://github.com/aaronblohowiak/Push-It which is built on top of Socket.IO. Design adheres to the Bayeux Protocol.

However, if you need something that uses redis pubsub you can check http://github.com/shripadk/Socket.IO-PubSub

Specifically answering your question: You can maintain an array of all the clients connected to the websocket server. And probably just broadcast to a subset of those clients? The broadcast method does essentially that under the hood. node-websocket-server/Socket.IO maintains an array of all the clients connected and just loops through all of them "send"ing a message to each of the clients. Gist of the code:

// considering you storing all your clients in an array, should be doing this on connection:
clients.push(client)

// loop through that array to send to each client
Client.prototype.broadcast = function(msg, except) {
      for(var i in clients) {
          if(clients[i].sessionId !== except) {
             clients[i].send({message: msg});
          }
      }
}

So if you want to relay messages only to specific channels, just maintain a list of all the channels subscribed by the client. Here is a simple example (to just get you started) :

clients.push(client);


Client.prototype.subscribe = function(channel) {
      this.channel = channel;
}

Client.prototype.unsubscribe = function(channel) {
     this.channel = null;
}

Client.prototype.publish = function(channel, msg) {
      for(var i in clients) {
         if(clients[i].channel === channel) {
            clients[i].send({message: msg});
         }
      }
}

To make it even easier use EventEmitters. So in node-websocket-server/Socket.IO see where the messages are being received and parse the message to check the type (subscribe/unsubscribe/publish) and emit the event with the message depending on the type. Example:

Client.prototype._onMessage = function(message) {
       switch(message.type) {
         case 'subscribe':
             this.emit('subscribe', message.channel);
         case 'unsubscribe':
             this.emit('unsubscribe', message.channel);
         case 'publish':
             this.emit('publish', message.channel, message.data);
         default:

       }
}

Listen to the events emitted in your app's on('connection') :

client.on('subscribe', function(channel) {
     // do some checks here if u like
     client.subscribe(channel);
});
client.on('unsubscribe', function(channel) {
     client.unsubscribe(channel);
});
client.on('publish', function(channel, message) {
     client.publish(channel, message);
});

Hope this helps.

53
5/19/2011 9:12:47 AM

I'm not sure if rooms were a feature when the other answers were created, but in the documentation, they have a feature exactly what you are looking for. So go to that link and search for rooms.

Here is an example from the site:

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  socket.join('justin bieber fans');
  socket.broadcast.to('justin bieber fans').emit('new fan');
  io.sockets.in('rammstein fans').emit('new non-fan');
});

Based on the other answers, it was more focused on scaling, I would love some insight if the built in version scales well as the proposed answers.


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon