Rooms

In this section we will use another multiplexing feature of socket.io, called rooms. And we will use it to do just what the name says, create rooms. A chat room will be very noisy and confusing if everyone in the network is chatting in the same room. So as the first step, let's move our chat away from the landing page of our website to /chatroom. For this, we should move our code from index.jade to chatroom.jade and put the following code in index.jade:

extends layout

block content
  section#welcome
    div Welcome
    a#startchat(type="button", class="btn", href="/chatroom") Start now

Basically, we will create a landing page with a welcome message and a link to go to the chat room. Let's also add the following styles for the landing page in style.css:

#welcome div{
  font-family: fantasy;
  font-size: 100px;
  margin-left: 20px;
  margin-top: 100px;
}

.btn {
    background-color: #5BB75B;
    background-image: linear-gradient(to bottom, #62C462, #51A351);
    background-repeat: repeat-x;
    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
    color: #FFFFFF;
    text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
    border-image: none;
    border-radius: 4px 4px 4px 4px;
    border-style: solid;
    border-width: 1px;
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.2) inset, 
          0 1px 2px rgba(0, 0, 0, 0.05);
    cursor: pointer;
    display: inline-block;
    font-size: 14px;
    line-height: 20px;
    margin-bottom: 0;
    padding: 4px 12px;
    text-align: center;
    vertical-align: middle;
    position: absolute;
    right: 40px;
    bottom: 80px;
    text-decoration: none;
}

Now our landing page will look like this:

Rooms

The landing page

The Start now link will send you to the chat room, but there is nothing there yet. So let us modify our routes/index.js file to serve chatroom. Add the following snippet to the end of the file:

exports.chatroom = function(req, res){
  res.render('chatroom', { title: 'Express Chat' });
}

We will also have to add the mapping to app.js:

app.get('/chatroom', routes.chatroom);

Now that we have a landing page, we are ready to add multiple rooms. We will now add support for the chat room page so that it can accept a room parameter and will connect to that room when requested. So the call to connect to enter the chat room will look like this:

http://localhost:3000/chatroom?room=jsconf 

For this we need to edit our chat.js client script file:

var chatInfra = io.connect('/chat_infra'),
    chatCom = io.connect('/chat_com'),

var roomName = decodeURI(
  (RegExp("room" + '=' + '(.+?)(&|$)').exec(location.search) 
    || [, null])[1]);

if (roomName) {
  chatInfra.on('name_set', function (data) {
    chatInfra.emit('join_room', {'name':roomName});

    //EXISTING CODE
  });
}

$(function () {
  $('#setname').click(function () {
    chatInfra.emit("set_name", {name:$('#nickname').val()});
  });
});

The first thing is to parse the URL query to get the room name, here is how this is done:

var roomName = decodeURI(
  (RegExp("room" + '=' + '(.+?)(&|$)').exec(location.search) 
    || [, null])[1]);

Here, in the preceding code, we are creating a regex to parse out the value between room= and & or to the end of the content. In the next line, we check if a room name was provided and once the user has entered the name, we will join the room.

To join the room, we emit the join_room event with roomName as a parameter. This event will be handled on the server:

if (roomName) {
  chatInfra.on('name_set', function (data) {
    chatInfra.emit('join_room', {'name':roomName});

Since we will use the room only to restrict the broadcast messages (others are anyhow sent only to the recipient's socket), this is all we need to do on the client.

Now we will edit the sockets.js file on our server to handle the join_room event on chat_infra and to change the broadcasts to send messages in the room they are meant for. Let us take a look at the changes in sockets.js:

var io = require('socket.io'),

exports.initialize = function (server) {
  io = io.listen(server);
  var self = this;

  this.chatInfra = io.of("/chat_infra");
  this.chatInfra.on("connection", function (socket) {
    //EXISTING CODE
    });
    socket.on("join_room", function (room) {
      socket.get('nickname', function (err, nickname) {
        socket.join(room.name);
        var comSocket = self.chatCom.sockets[socket.id];
        comSocket.join(room.name);
        comSocket.room = room.name;
        socket.in(room.name).broadcast
    .emit('user_entered', {'name':nickname});
      });
    });
  });

  this.chatCom = io.of("/chat_com");
  this.chatCom.on("connection", function (socket) {
    socket.on('message', function (message) {
      message = JSON.parse(message);
      if (message.type == "userMessage") {
        socket.get('nickname', function (err, nickname) {
          message.username = nickname;
          socket.in(socket.room).broadcast.send(JSON.stringify(message));
          message.type = "myMessage";
          socket.send(JSON.stringify(message));
        });
      }
    });
  });
}

So this brings in some minor structural changes. Since we will need to refer chatCom in chatInfra, we add them both to the current object, which is also stored as itself, so that they are accessible in the closures. In the chat_infra connection handler, we register a new event handler for join_room:

    socket.on("join_room", function (room) {
      socket.get('nickname', function (err, nickname) {
        socket.join(room.name);
        var comSocket = self.chatCom.sockets[socket.id];
        comSocket.join(room.name);
        comSocket.room = room.name;
        socket.in(room.name).broadcast
    .emit('user_entered', {'name':nickname});
      });
    });

In the handler, we are receiving the room object, which will in turn have the name of the room to join. Next we connect the chat_infra socket to the room. This is done using the join method of the socket object:

        socket.join(room.name);

The join method takes a name string for the room. The room will be created if not present, else the socket will be connected to an existing room.

Now, once our client joins the room, it will get all the messages intended for the specific room in the chat_infra namespace. But, this will not be useful until we also join the room in the chat_com namespace. For this, we will need to obtain the socket object, corresponding to the current socket object in the chat_com namespace and then call the same join method on it:

        var comSocket = self.chatCom.sockets[socket.id];
        comSocket.join(room.name);

To get the corresponding socket object on chat_com, we fetch it using the current socket object's ID (as it will be similar) from the sockets array in the chatCom namespace object. The next line simply calls the join method on it. Now both have joined the room in both the namespaces. But when we receive the messages in the chat_com namespace, we will need the name of the room this socket is connected to. For this, we will set the room property on the comSocket object to the room it is connected to:

    comSocket.room = room.name;

Now that all is set up, we will announce in the room that the user has joined:

        socket.in(room.name).broadcast
    .emit('user_entered', {'name':nickname});
      });

As we did earlier, we still use broadcast.emit, but instead of calling it on the socket, we restrict it to be sent only in the room, using in(room.name). Another change we make will be that of broadcasting the user messages again by restricting them to the room:

  socket.in(socket.room).broadcast.send(JSON.stringify(message));

Now you can open the chat room by going to the following URL:

http://localhost:3000/chatroom?room=test001 

Open this in two browser windows and log in with different names. Open another chat room in another browser window using the following URL:

http://localhost:3000/chatroom?room=test002

The messages and alerts sent only in the room test001 will be visible in the first two browsers, while the one connected to test002 will not be able to see them:

Rooms

User one connected to the room test001

Here is the second user connected to the room test001:

Rooms

User two connected to the room test001

Here, in the following screenshot, the third user is shown connected to the room test002:

Rooms

User three connected to the room test002

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset