Monday, July 29, 2013

Node.JS tutorial - Create a simple chat with socket.io module - Part 3

Source Code: 

In that part we will create the chat functionallity (= Communication between the clients and the server).

Adding the chat communication functionallity


Client 
1

Add inside the body tag a script block:


<script type="text/javascript">
</script>


Client 
2Creating a client socket

socket.io uses WebSockets. That means that when a client connects to the server, the connection remains open ("Wikipedia": WebSocket is a web technology providing full-duplex communications channels over a single TCP connection).
Let's connect to the server and get a brand new socket for our client by adding:

  // our websocket
 var socket = io.connect();

Keep the userName in a global variable by adding:

 var userName;


Client 
3Writing login client logic

Let's start by implementing "onLogInLogOut()" function.
First we will take his user name from the text-box by :

userName = document.getElementById("txtUserName").value; 


And we'll check whether it's a "LogIn" or "LogOut" :


// get button text
var btnLogInLogOut = document.getElementById('btnLogInLogOut');
var txtBtnLogInLogOut = btnLogInLogOut.textContent || btnLogInLogOut.innerText;
if(txtBtnLogInLogOut == 'LogIn') {
}
else {
}

Suppose it's a LogIn, we need to inform the server that a new user has just connected.
We do it by:


// send join message
socket.emit('join', userName);

Here is the full LogIn condition, including changing "LogIn" button to a "LogOut" button after the user connected:


if(txtBtnLogInLogOut == 'LogIn') {
// send join message
socket.emit('join', userName);
btnLogInLogOut.innerText = 'LogOut';
document.getElementById('btnSendMessage').disabled = false;
}


Server
4

We need to keep the users, so we'll add an array as a global variable:

var users = {};

g. Let's define the 'join' event whenever a client connects:

io.sockets.on('connection', function (socket) {
   socket.on('join', function(userNameParam) {
   });
}

io.sockets.on('connection', function() { .. } ) - is a socket.io built-in event, and we use it to trigger each client connection.
As a result, we are getting a socket for that client, and we define the event that we have been using in the client side (remember "socket.emit('join', userName);" ?).

Here's a brief on the LogOn cycle from socket.io point of view:
User loads the page and socket is created ( "var socket = io.connect();" ).
"io.sockets.on('connection', ...)" is being triggered and all of the events definitions are save to that socket.
User clicks on the LogOn button and 'join' is being called on server ("socket.emit('join', userName);").
"socket.on('join', function(userNameParam)" is triggered due to the call.


Server
5

Add the full 'join' event:

socket.on('join', function(userNameParam) {
    socket.join('chatchannel'); // create/join a socket.io room
    users[userNameParam] = userNameParam; // save the user name in the users array
    socket.userName = userNameParam; // save the user name inside the socket
    socket.emit('firstLogin',users); // when a user login first, call 'firstLogin' only in that client socket
    socket.broadcast.to('chatchannel').emit('addConnectedUser',userNameParam); // tells everyone except that user that a new user has been connected
   io.sockets.in('chatchannel').emit('message',userNameParam, 'I am connected !'); // tells every client that the user connected
});

socket.io allows us to use a "room" functionallity. That means a few sockets can join a room, and the server can refer to that room when transferring messages (it's very easy to implement chat rooms like that, right ?).
In our chat version, we use only one room which called 'chatchannel' : 
"socket.join('chatchannel');".

Regarding the UI, if a user login we want to add all of the users to the listview, so we need a special event for it on the client side. We will call 'firstLogin' on the client by: "socket.emit('firstLogin',users);".

Now we need to inform all the connected users (clients) about that user who had just connected:
socket.broadcast.to('chatchannel').emit('addConnectedUser',userNameParam);
That will inform everyone in that room, except the brand new user (= the current socket).



Client
6

Define the 'firstLogin' event on the client, which adds all user names to the users list, and 'addConnectedUser' which adds the new user to an existing users list on a connected client.
Again, 'firstLogin' - for a brand new connected user, 'addConnectedUser' - for all of the connected users which already has a users list in their UI.

socket.on('firstLogin', function(data) {
    var ulFriends = document.getElementById('friends');
    ulFriends.innerHTML = '';
    for (i in data) {
addUserToList(ulFriends, data[i]);
   }
});
socket.on('addConnectedUser', function(data) {
    var ulFriends = document.getElementById('friends');
    addUserToList(ulFriends, data);
});
function addUserToList(ulFriends, userName) {
    var li = document.createElement('li');
    li.appendChild(document.createTextNode(userName));
   li.setAttribute('id','user-' + userName);
   ulFriends.appendChild(li);
}



Server
7.
When a user closes the chat browser tab, or press 'LogOut' we notify the chat clients, and leaving the socket.io 'chatchannel' room:

socket.on('leave', onUserDisconnected);

socket.on('disconnect', onUserDisconnected);

function onUserDisconnected() {
  delete users[socket.userName]; // removing the user from users list
  io.sockets.in('chatchannel').emit('logout',socket.userName); // call logout event on each client
  io.sockets.in('chatchannel').emit('message',socket.userName, 'I am disconnected !'); // tells every client that the user disconnected
  socket.leave('chatchannel'); // leaving socket.io 'chatchannel' room
}

Keep in mind that 'leave' is our event, and 'disconnect' is a built-in socket.io event.


Client
8.
Removing the disconnected client from the users list in each client:

socket.on('logout', function(data) {
var user = document.getElementById('user-' + data);
user.parentNode.removeChild(user);
});


Client
9.
When a user sends message, we want to notify the server:

function onSendMessageClick() {
    var messageText = document.getElementById("txtUserMessage").value;
    socket.emit('send',userName, messageText);
}


Server
10.
Sending the message to all clients:

socket.on('send', function(userName, messageText) {
  io.sockets.in('chatchannel').emit('message',userName, messageText);
});


Client
11.
Getting the message and publish it to the text area place:

socket.on('message', function(userName, messageText) {
   document.getElementById("txtUserMessage").value = '';
   var ulChat = document.getElementById('chat');
   var li = document.createElement('li');
   var userSpan = document.createElement('span');
   userSpan.style.color = 'red';
   userSpan.innerHTML = userName + ': ';
   var messageSpan = document.createElement('span');
   messageSpan.innerHTML = messageText;
   li.appendChild(userSpan);
   li.appendChild(messageSpan);
   ulChat.appendChild(li);
});


Summary

We're done! 
Now you have a nice not-fancy chat built with node.js.

No comments:

Post a Comment

Thank you Blogger, hello Medium

Hey guys, I've been writing in Blogger for almost 10 years this is a time to move on. I'm happy to announce my new blog at Med...