Node.js, Comet, real-time chat — a great first project
For my own learning process, I usually start by reading a bunch of articles on a topic. Once I feel I have a basic understanding, I find that building something really improves my knowledge and retention about the subject quickly. I also know once I’ve achieved that milestone (you could call it a beyond-Hello-World program), it becomes a lot easier to learn the more advanced concepts regarding the subject.
Taking that philosophy, I’m sharing my first experience building a NodeJS project — a real-time group chat. There’s a few reasons I thought this would be a good project:
- Managing many requests and responses is what NodeJS excels at, assuming that waiting for I/O and user responses is the key slowdown
- I’ve been meaning to learn more about Comet techniques (to do HTTP push)
- It’s a pretty small project
The idea is for you to try to code this on your own. Peek at my code as necessary, but take a stab at doing it yourself first.
So to start with, reviewing/learning something about Comet is useful. This wikipedia article has a great summary about it: http://en.wikipedia.org/wiki/Comet_(programming)
Although I prefer building things from scratch to learn, it often more makes sense to use a well-written library when available. Socket.IO is pretty solid. Take a quick look at their homepage to understand what they offer for when you want to build something more real: http://socket.io/. For this tutorial we’ll be writing it all ourselves. You won’t need any modules outside of what comes with node.js.
Now let’s start writing some code. We’ll tackle the problem in stages:
- The client code that runs on the browser. It should setup the initial Comet connection, listen for new messages, and send messages to the server.
- The server code which delivers this client code to the browser
- The server code which receives new messages from clients
- The server code which pushes new messages to clients
So we can focus on learning these specific concepts, we’ll ignore authentication and security and also assume all packets are always 100% successful.
BTW, here’s what the end result looked like for me:
Step 1. The client
- The URLs implemented by the server are (sorry this is not REST)
- /listen : this is the src for the Comet iframe. Required query parameter is ‘user=<username>’
- /addText : the client calls this when it has a new line of text from the user. It is called via HTTP GET. Required query parameters are ‘user’ and ‘text=<new text>’.
Step 2. Deliver this client code
For our first NodeJS code, we’ll simply deliver this HTML page to the client when they hit the root URL. It should be pretty straightforward to implement. Hint: take a look at ‘fs’ in the Node.js docs. Bonus points for:
- Loading the file off disk without blocking (avoid the *Sync functions)
- Caching the file after the first time it’s read to avoid re-reading it.
- Preparing to handle other URLs coming up in the next steps
Step 3. Receive new messages
Now let’s implement the /addText handler. For now you can just log out the new text and user to the console to know that it’s receiving the text correctly from the client
Step 4. Push new messages
Finally, lets’ implement the /listen handler. Since we are doing chunked transfers to an iframe, read this short blog post with more detail on the topic: http://weblog.rubyonrails.org/2011/4/18/why-http-streaming
If you’re like me and have never dealt with Comet before, here is some information I found useful:
- Note the piece of trivia in the Why HTTP Streaming article about the browser buffering for ‘text/html’ MIME types. You’ll need to make your Content-Type ‘text/html;charset=utf-8′
- For every user, you’ll want to store their response object somewhere to push new messages to them as they come in (I pushed back messages as soon as they were received in /addText)
- Make sure not to do a ‘response.end()’ or you’ll have closed the connection you needed for Comet
Now you should have a working real-time group chat and some practical NodeJS code under your belt. I hope this exercise has been as useful for you as it was for me.
In the next lesson, we convert this to use Socket.IO: Node.js + Socket.IO for real-time chat