Introduction
As you may know, we can run a WebSocket server through Nodejs using the Socket.io module. The main issue in a socket.io server is how to manage sessions and users. In this article we are going to create a simple Nodejs module to help us out with this issue.
Here we go!
Socket IO
Whenever a user connects to a Socket.io Server, the server will create a session with a unique Id which is essential for unicasting. Here is a sample code which show’s you, how socket.io works; but for more information go to socket.io
var io = require('socket.io').listen(3000);
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
In this example we are just going to store a username, user id and role for each session.
Here is our Roles list:
var userRoles = {
Admin: "administrator",
User: "user",
Supervisor: "supervisor"
};
Now, let’s write our session manager class and then turn it into a Nodejs Module.
sessionManagement.js:
var sessionManagement = {
};
For such a module, we’ll need to do the followings:
- Add/Remove user
- Find session by id
- Find session by user id
- Check Permission
At first we need to store the data. I prefer using a simple array because they are fast and easy to use.
You might ask “What if server falls?!” Well, I say that if server falls all sessions are lost and remade; but if you need the data for any reason, I suggest mongoose, which is a MongoDB module for Nodejs.
I’ll put the array outside of the class scope for more security.
var sessions = [];
var sessionManagement = {
};
Except then mentioned methods, we’ll need a method to find the index of a given user Id, so we won’t need to code it each single time:
function(sessionId) {
for(var i in sessions) {
if(sessions[i].sessionId == sessionId)
return i;
}
}
Here is our complete script (sessionManagement.js):
var sessions = [];
var userRoles = {
Admin: "administrator",
User: "user",
Supervisor: "supervisor"
};
var sessionManagement = {
indexOf: function(sessionId) {
for(var i in sessions) {
if(sessions[i].sessionId == sessionId)
return i;
}
return null;
},
indexOfUser: function(userId) {
for(var i in sessions) {
if(sessions[i].userId == userId)
return i;
}
return null;
},
add: function(sessionData) {
sessions.push(sessionData);
},
remove: function(sessionId) {
var index = this.indexOf(sessionId);
if(index != null) {
sessions.splice(index, 1);
} else {
return null;
}
},
removeByUserId: function(userId) {
var index = this.indexOf(userId);
if(index != null) {
sessions.splice(index, 1);
} else {
return null;
}
},
getSessionById: function(userId) {
var index = this.indexOfUser(userId);
if(index != null) {
return sessions[index];
} else {
return null;
}
},
getSessionByUserId: function(sessionId) {
var index = this.indexOfUser(userId);
if(index != null) {
return sessions[index];
} else {
return null;
}
},
isAdmin: function(userId) {
var index = this.indexOfUser(userId);
if(index != null) {
if(users[index].role == userRoles.Admin) {
return true;
} else {
return false;
}
} else {
return null;
}
},
getUsersByRole: function(role) {
var usersByRole = [];
for(var i in users) {
if(users[i].role == role)
usersByRole.push(users[i]);
}
return usersByRole;
}
};
Now, it’s time to convert it to a Nodejs Module…
As you can see in Nodejs manual, we must add any desired object to the module.exports
object in order to use it in another module or script. So we’ll just need to assign our class to this variable:
module.exports = sessionManagement;
There We Are!
Now we can use the module in any desired script by simply putting the sessionManagement.js in our application directory or the node_modules
directory.
Sample usage:
var sessionMgm = require("sessionManagement");
io.sockets.on('connection', function (socket) {
socket.on('setUserInfo', function (data) {
var sess = new Object();
sess.sessionId = socket.id;
sess.userId = data.userId;
sess.username = data.username;
sess.role = data.role;
sessionMgm.add(sess);
});
socket.on('sendPm', function(data) {
if(data != null) {
var user = sessionMgm.getSessionByUserId(data.userId);
if(user != null) {
io.sockets.socket(user.sessionId).emit('newMessage', data.message);
} else {
var sysMsg = {type: "error", message: "User not found!"};
socket.emit('systemMessage', sysMsg);
}
}
});
socket.on('disconnect', function() {
sessionMgm.remove(socket.id);
});
}
Conclusion
Socket.io dedicates a unique id to each session. To send an event directly to a specific user, we need to know their session id. We wrote a class to manage these sessions and then turned it to a Nodejs module to use it simpler in our next applications. Using this module we can simply manage the users by their session id, user id or role.