Oliver Goossens
Oliver Goossens

Reputation: 1913

JS: Node.js and Socket.io - globals and architecture

Dear all,

Im working with JS for some weeks and now I need a bit of clarification. I have read a lot of sources and a lot of Q&A also in here and this is what I learned so far.

Everything below is in connection with Node.js and Socket.io

Ok I build up some chat example, multiple users - all get served with broadcast but no private messages for example.

Fairly simple and fairly ok. But now I am stuck in my mind and cant wrap my head around.

Lets say:

In my head I imagined:

1. Custom object USER - defined globally on Node.js

function User(socket) {
this.Name;
this.socket = socket; }

2. Than hold an ARRAY of these globally

users = [];

and on newConnection, create a new User, pass on its socket and store in the array for further action with

users.push(new User(socket));

3. And on a Socket.io request that wants to contact all BRIANs do something like

for (var i = 0; i < users.length; i++) {
if(user[i].Name == "BRIAN") {
    // Emit to user[i].socket
}}

But after trying and erroring, debugging, googling and reading apparently this is NOT how something like this should be done and somehow I cant find the right way to do it, or at least see / understand it. can you please help me, point me into a good direction or propose a best practice here? That would be awesome :-)

Note: I dont want to store the data in a DB (that is next step) I want to work on the fly.

Thank you very much for your inputs

Oliver

Upvotes: 0

Views: 164

Answers (1)

Theo
Theo

Reputation: 2042

first of all, please don't put users in a global variable, better put it in a module and require it elsewhere whenever needed. you can do it like this:

users.js

var users = {
    _list : {}
};

users.create = function(data){
  this._list[data.id] = data;
}

users.get = function(user_id){
    return this._list[user_id];
};

users.getAll = function(){
    return this._list;
};
    
module.exports = users;

and somewhere where in your implementation

var users = require('users');

For your problem where you want to send to all users with name "BRIAN", i can see that you can do this good in 2 ways.

First. When user is connected to socketio server, let the user join a socketio room using his/her name. so it will look like this:

var custom_namespace = io.of('/custom_namespace');
custom_namespace.on('connection', function(client_socket){
    //assuming here is where you send data from frontend to server
    client_socket.on('user_data', function(data){
        //assuming you have sent a valid object with a parameter "name", let the client socket join the room 
        if(data != undefined){
            client_socket.join(data.name); //here is the trick
        }
    });
});

now, if you want to send to all people with name "BRIAN", you can achieve it by doing this

io.of('/custom_namespace').broadcast.to('BRIAN').emit('some_event',some_data);

Second. By saving the data on the module users and filter it using lodash library

sample code

var _lodash = require('lodash');
var Users = require('users');
var all_users = Users.getAll();
var socket_ids = [];
var users_with_name_brian = _lodash.filter(all_users, { name : "BRIAN" });

users_with_name_brian.forEach(function(user){
   socket_ids.push(user.name);
});

now instead of emitting it one by one per iteration, you can do it like this in socketio

io.of('/custom_namespace').broadcast.to(socket_ids).emit('some_event',some_data);

Here is the link for lodash documentation

I hope this helps.

Upvotes: 1

Related Questions