Nika Nika - 1 month ago 18
Node.js Question

How to share dynamic objects across workers?

I'm trying to make a game, which works on rooms, lobby and such (imagine the chat app, except with additional checks/information storing).

Let's say, I have a module room.js

var EventEmitter = require('events');

class Room extends EventEmitter {
constructor (id, name) {
super();

this.id = id;
this.name = name;
this.users = [];
}
}

Room.prototype.addUser = function (user) {
if(this.users.indexOf(user) === -1) {
this.users.push(user);
this.emit('user_joined', user);
} else {
/* error handling */
}
};

module.exports = {
Room: Room,
byId: function (id) {
// where should I look up?
}
};


How can I get exactly this object (with events)? How can I access events emitted by this object?

In a single instance of node, I would do something like:

var rooms = [];
var room = new Room(1234, 'test room');
room.on('user_joined', console.log);
rooms.push(room);


Also, I don't quite understood how Redis is actually helping (is it replacement of EventEmitter?)

Regards.

EDIT: Would accept PM2 solutions too.

Answer

Instead of handling rooms in Node, you can replace them with channels in Redis).

When a new client wants to join in a room, the NodeJS app returns it the ID of this given room (that is to say the name of the channel), then the client suscribes to the selected room (your client is directly connected to Redis.

You can use a Redis Set to manage the list of rooms.

In this scenario, you don't need any event emitter, and your node servers are stateless.

Otherwise, it would mean Redis would be exposed on the Internet (assuming your game is public), so you must activate Redis authentication. A major problem with this solution is that you have to give the server password to all clients, so it's definitely unsecure. Moreover, Redis' performances allow brute force attacks so exposing it on Internet is not recommended. That's why I think all communications should go through a Node instance, even if Redis is used as a backend.

To solve this, you can use socket.io to open sockets between Node and your clients, and make the Node instances (not the client) subscribe to the Redis channel. When a message is published by Redis, send it to the client through the socket. And add a layer of authentication to ensure only valid clients connect to a given channel.

Event emitter is not required. It's the Redis client which will be an event emitter (like in this example based on ioRedis)