So, do you
like socket.io? Once you’ve got the hang of it, it’s not really
complicated getting used to using Node.js. You can see that all sorts of
possibilities are suddenly open to us. Imagine what you can start doing
in real time - chat, games, collaborative work tools, etc.
Amongst
all of these possibilities, I think that chat is by far the simplest
app to create that’s both useful and efficient and will impress your
friends and family. So, let’s go!
I know, most of the socket.io courses already explain how to create a chat app... but I bet none of them has shown you how to create a "Super Chat"! (in case you're wondering, there's no difference... except for the pretty cool name)
I know, most of the socket.io courses already explain how to create a chat app... but I bet none of them has shown you how to create a "Super Chat"! (in case you're wondering, there's no difference... except for the pretty cool name)
Before we do anything else, look at the next figure. It shows you what our chat looks like.
I
deliberately opened 2 windows here. The left one is connected to the
"mateo21" username and the right one to the "gerry" username.
- I ask for the username with a dialog box when the person connects to the website
- I show the username of the person who just connected to everyone in the chat (e.g. "gerry joined the chat!")
- When we type a message, it’s immediately displayed in the browser under the form.
Basically,
nothing complicated! But even though it’s based on codes from the
previous chapter, you’re going to have to work a bit and think. And
that’s exactly the diabolical plan that I have in mind: to make you
work.
Need help?
Are you lost? Don’t know where to start?
Let’s
go, if you followed the previous chapter on socket.io it shouldn’t be
too difficult. Because I’m such a nice guy, I’ll give you a few clues to
help you along.
A little reminder of what you have to do:
Now let’s ask ourselves the right questions. How many files are we going to need? To me it’s obvious, I would say three:
- A package.json file that describes the dependencies of your Node.js project.
- An app.js file for the server-side application in Node.js.
- An index.html that contains the web page and the chat management client-side code.
Here’s a bit of help for you to create each of these files. If you genuinely feel OK about it, try not to use it.
(And worst case scenario you can come back to this section if you get stuck.)
(And worst case scenario you can come back to this section if you get stuck.)
package.json
At
this stage, you should know how to create a package.json with your eyes
closed. I shouldn’t have to explain the syntax to you again, if you’ve
had a memory lapse, I’ll let you go back to the relevant section
"Declaring and publishing your module" in this chapter.
However,
when it comes to external modules, what are we going to need? Here is
what I’d suggest (and what I use in my correction):
- socket.io: if you’ve forgotten it, that’s unforgivable.
- express: whilst we’re at it, we might as well use Express.js right from the start. We didn’t use it in the socket.io chapter but it’s not very complicated to use alongside socket.io. On their website there’s an explanation of how to use it in combination with Express.js.
- ent: a tiny module that protects the character strings sent by visitors to change the entities of the HTML. This saves visitors from sending each other JavaScript in the chat!
Frankly,
Express.js and ent aren’t essential to make the chat work. We can
easily do without them, but I chose them, partly simplify maintenance of
the code (for Express.js) and for security (for ent).
app.js
This
should send a webpage when we call the server. It’s up to you to send
an "index.html" file to your visitors when they connect to your website.
With Express.js, the syntax is a bit different but also shorter.
With Express.js, the syntax is a bit different but also shorter.
As
well as the "classic" webpage, your Node.js server will need to
generate socket.io events. In theory, I would say that you only need to
generate two:
- new_client (call it what you want): signals that a new client has logged on to the chat and should transmit their username to inform the clients with a message such as "robert has joined the chat!".
- message: signals that a new message has been posted. Your role, as a server, is simply to redistribute it to other clients who are connected with a little broadcast. Whilst we’re at it, collect the poster’s username in a session variable.
In the end, the app.js file isn’t too big or complicated. The more I look at it, the more I find it really short and simple.
index.html
In
truth, it’s may be the file that needs most work and that should give
you a (little) bit of trouble. You’ll need to handle a fair amount of
client-side JavaScript.
Start by structuring a basic HTML5 page with a title, a form made up of a text field and a button, and a
<div>
or a<section>
that will contain the chat messages (by default, it will be empty).
It’s
up to you then to write the client’s JavaScript code. Personally, I put
it at the bottom of the page (for performance reasons, it’s a good
habit to get into). I could also have put an external .js file, but I
didn’t do it here.
This code will need to:
- Connect to socket.io.
- Ask for the visitor’s username when the page loads (via a
prompt()
in JS, it’s the most simple one that I found) and send a "new_client" signal. - Manage the reception of "new_client" signals sent by the server. This means that a new client has logged on. Display their name in a message, for example "Robert has joined the Chat!".
- Manage the reception of "message" signals sent by the server. It means that another client has sent a message in the chat and that it therefore needs to be shown on the page.
- Manage sending the form when the client wants to send a message to the other people who are connected. You’ll need to retrieve the message typed in the JavaScript form, emit a message signal to the server so that it distributes it to the other clients, and also embed the message into your own page. Oh yes, don’t forget that the broadcast from the server sends the message to all the other people who are connected… except to you. You therefore need to update your own chat zone.
I’ve prepared the work so much that it’s starting to get me down… If you can’t do it with all of this… try harder!
Correction
If everything’s wrong, it’s time for correction!
So,
how did the creation of the chat go for you? You shouldn’t have
encountered too many problems; this practical exercise was a way to
reformulate the chapter before the introduction to socket.io a little
more concisely.
My project is made up of 3 files:
- package.json: the description of the project with the list of its dependencies. Any self-respecting Node.js project has one!
- app.js: the server-side Node.js app that manages the interactions with the different clients.
- index.html: the webpage sent to the client that contains JavaScript code to generate the chat on the client-side.
package.json
{
"name": "super-chat",
"version": "0.1.0",
"dependencies": {
"express": "~3.3.4",
"socket.io": "~1.2.1",
"ent": "~0.1.0"
},
"author": "Mateo21 <mateo21@email.com>",
"description": "A real-time super chat with socket .io"
}
As
I was saying (for those who read the tips earlier on), I obviously use
socket.io, but also Express.js (even though it’s not complulsory) and
ent (to call a function equivalent to
htmlentities()
in PHP, to secure exchanges and prevent clients from sending each other malicious JavaScript codes).app.js
The chat’s server code is relatively short and wasn’t the hardest file to write in practice.
var app = require('express')(),
server = require('http').createServer(app),
io = require('socket.io').listen(server),
ent = require('ent'), // Blocks HTML characters (security equivalent to htmlentities in PHP)
fs = require('fs');
// Loading the page index.html
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function (socket, username) {
// When the username is received it’s stored as a session variable and informs the other people
socket.on('new_client', function(username) {
username = ent.encode(username);
socket.username = username;
socket.broadcast.emit('new_client', username);
});
// When a message is received, the client’s username is retrieved and sent to the other people
socket.on('message', function (message) {
message = ent.encode(message);
socket.broadcast.emit('message', {username: socket.username, message: message});
});
});
server.listen(8080);
The
start of the file doesn’t contain anything extraordinary: a few calls
to modules, the management of the index ("/") where we send back
index.html… Seriously, it doesn’t get any easier than that.
Underneath,
there’s all the management of real-time messages with socket.io. In
reality, we only manage two different types of messages:
- new_client: sent by a new client who just loaded the page. It contains their username as a setting. I chose to encode it (with
ent.encode()
) for security reasons. So, if the visitor puts JavaScript in their username, we’re covered! Then, I only need to "save" this username in a session variable. - message: sent by the client who wants to send a message to other people who are connected. Firstly, we encode the message (to be safe from malicious JavaScript codes) and broadcast it with the username that we saved as a session variable. To send more data in one setting, I encapsulate them in a JavaScript object, which gives this code
{username: username, message: message}
.
That’s all the server has to do!
index.html
OK, the client code is a tad more complicated. But just a tad, honestly.
Here we go, we’ll explain it all afterwards, I promise:
<!DOCTYPE html>
charset="utf-8"
Real-time Super Chat!
#zone_chat strong {
color: white;
background-color: black;
padding: 2px;
}
Real-time Super Chat!
action="/" method="post" id="chat_form"
type="text" name="message" id="message" placeholder="Your message..." size="50" autofocus
type="submit" id="send_message" value="Send"
id="chat_zone"
src="http://code.jquery.com/jquery-1.10.1.min.js"
src="/socket.io/socket.io.js"
// Connecting to socket.io
var socket = io.connect('http://localhost:8080');
// The username is requested, sent to the server and displayed in the title
var username = prompt('What\'s your username?');
socket.emit('new_client', username);
document.title = username + ' - ' + document.title;
// When a message is received it's inserted in the page
socket.on('message', function(data) {
insertMessage(data.username, data.message)
})
// When a new client connects, the information is displayed
socket.on('new_client', function(username) {
$('#chat_zone').prepend('<p><em>' + username + ' has joined the chat!</em></p>');
})
// When the form is sent, the message is sent and displayed on the page
$('#chat_form').submit(function () {
var message = $('#message').val();
socket.emit('message', message); // Sends the message to the others
insertMessage(username, message); // Also displays the message on our page
$('#message').val('').focus(); // Empties the chat form and puts the focus back on it
return false; // Blocks 'classic' sending of the form
});
// Adds a message to the page
function insertMessage(username, message) {
$('#chat_zone').prepend('<p><strong>' + username + '</strong> ' + message + '</p>');
}
The
slightly complex part is in the JavaScript code at the end of the file.
This is where we find all that we need on the client-side to manage the
chat:
- The socket.io connection
- The username request and its transfer to the server via a "new_client" signal. The added bonus - I allowed myself to display the username in the
<title>
of the page so that it appears in the tabs of my navigator. Given that for my tests I have multiple tabs open, it helps me remember who’s who! - The retrieval of the message signal sent by the server. In this case, I insert the message in the page’s #chat_zone. I chose to create a function for that because I also need this function when sending the form.
- The retrieval of the "new_client" signal where I display "XXX has joined the chat!".
- The management of sending the form can be the hardest part. You need to retrieve the message typed by the client, send it to the server, and insert it in our page (because the server transmits the message to everyone except for us!). I also made the most of it, emptied the text zone, and put the focus back on it… and I blocked the ability to send the form the ‘classic’ way. The
return false
is essential if we don’t want the page to reload after the form has been sent. In fact,return false
is equivalent to the jQuerypreventDefault()
function. - Finally, the insertMessage() function is actually very simple. It adds the message that was sent with its username at the top of the chat form. The prepend() function is part of jQuery, I didn’t invent it.
I
chose to use jQuery in my code for practical reasons, but you can of
course use JavaScript to do all of this if you want to (or use a
different library).
Basically,
the JavaScript code on the client’s side is probably the biggest part.
The Node.js server part is, as you can see, very simple: we connect,
send signals, retrieve signals… that’s it!
Downloading the project
You already have everything you need but if you really want a .zip file, I suggest you download it on the following link:
Download the project here: super-chat.zip
Taking it further!
Do
you want more practice in using socket.io? Here are some ideas to keep
you busy for a while (by approximate order of difficulty)!
- Display a message to the other people when a person disconnects.
- Allow clients to change their username in the middle of a chat session.
- Try adding buttons to the page to make pre-loaded sounds play at a distance. A little "ding" to wake up sleeping clients?
- Try to save the messages in the memory on the server so that the list of the latest messages can be displayed when we connect. You can save information in the memory as we learnt… or try to couple Node.js with a MySQL, MongoDB, redis, etc. database.
- What if your clients could send each other images as well as text?
If despite all this, you’re still bored, take the code for the to do list practical exercise
and make a "to do list that’s shared in real time by several people".
The addition or deletion of tasks will automatically be carried out on
the other clients’ list!
No comments:
Post a Comment