After all the great feedback that I have received from you guys about the chat app that I wrote using node.js and socket.io, I decided to upgrade it a bit and I took your considerations into account and added new features as well. In this post I am going to explain what changes I have done and most importantly, how.
First of all I have removed the requirement for multiple ports - the socket.io backend and the ExpressJS frontend are now on the same port as opposed to being separated, and the whole functionality now lives in server.js
. (Please note that the code snippet below has been trimmed)
var express = require('express');
var app = (module.exports = express());
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
server.listen(3000, '192.168.56.101', function () {
console.log('Express server up and running.');
});
The second change was that I have added a features that forbids the same room to be added twice - each and every chat room has to be unique - and it's enforced on the name of the room.
On the client side (client.js
) I have added an emit statement that communicates with the web socket and checks whether the room name a user entered exists:
$('#createRoomBtn').click(function () {
var roomExists = false;
var roomName = $('#createRoomName').val();
socket.emit('check', roomName, function (data) {
roomExists = data.result;
if (roomExists) {
} else {
if (roomName.length > 0) {
//also check for roomname
socket.emit('createRoom', roomName);
$('#createRoom').hide();
$('#createRoomForm').hide();
}
}
});
});
The backend portion (server.js
) iterates through the rooms hash and checks the name property:
socket.on('check', function (name, fn) {
var keys = Object.keys(rooms);
var match = false;
if (keys.length != 0) {
for (var i = 0; i < keys.length; i++) {
console.log(rooms[keys[i]].name);
if (rooms[keys[i]].name === name) {
console.log('matched room: ' + name);
match = true;
break;
}
}
}
console.log('match: ' + match);
fn({ result: match });
});
The additional fn
is required for the callback to finish before the jQuery portion of the client side code can continue with its execution.
I am also pleased to announce the arrival of the 'whisper' function. From now on, a person can 'whisper' to another person - that is, send a private message that is only visible to the selected person. This is currently a 'beta' feature and probably works in a very ugly way, to send a private message, the following syntax is accepted by the inputbox: w:USER:MESSAGE
. The code is rather clever - first it checks if the aforementioned syntax was typed in, if it was, it will parse it accordingly, also doing a lookup for the USER and make sure that they are connected. If nothing is found or if it's not a private message, everything will continue as before.
socket.on('send', function (msg) {
var re = /^[w]:.*:/;
var whisper = re.test(msg);
var whisperStr = msg.split(':');
var found = false;
if (whisper) {
var whisperTo = whisperStr[1];
var keys = Object.keys(people);
if (keys.length != 0) {
for (var i = 0; i < keys.length; i++) {
if (people[keys[i]].name === whisperTo) {
console.log('matched person');
var whisperId = keys[i];
found = true;
if (socket.id === whisperId) {
//can't whisper to ourselves
socket.emit('update', "You can't whisper to yourself.");
}
break;
}
}
}
if (found && socket.id !== whisperId) {
var whisperTo = whisperStr[1];
var whisperMsg = whisperStr[2];
socket.emit('whisper', { name: 'You' }, whisperMsg);
io.sockets
.socket(whisperId)
.emit('whisper', people[socket.id], whisperMsg);
} else {
socket.emit('update', "Can't find " + whisperTo);
}
} else {
if (
io.sockets.manager.roomClients[socket.id]['/' + socket.room] !== undefined
) {
io.sockets.in(socket.room).emit('chat', people[socket.id], msg);
} else {
socket.emit('update', 'Please connect to a room.');
}
}
});
Finally I have added some more styling, but trust me, I'm not a designer so it's probably still ugly, but the functionality is there.
You can find the whole codebase on GitHub.
To install npm install && bower install
and to launch run npm start
.