Chat 2.0 - Supercharged chat written in node.js and socket.io

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.

Show Comments