Brian Tanner

Web Developer, Entrepreneur

Real-time hit log using node.js and nowjs

When looking to break into a new technology, I usually like to go in head strong, and build something that I can use in our live applications. Ever since first learning about node.js, I have wanted to build a new hitlog for our application. The hitlog is basically an activity monitor of what is going on right now, in our application. It's basically a extreme access logs, with a lot of custom data, and I stream that to the browser using AJAX. We have various logs, for various aspects of our application, and like to monitor activity from time to time, in order to see what's going on, if there are any problems, and when a problem occurs, we can easily search the logs for a particular user. Quite frankly, I just like to see live, moving things.

What I found when searching for real-time data, was that most people were creating things that are of no use to me. Such as chasing cursors around a screen. Not that I'm saying that isn't a great starting point for many projects and even I will look at the code and thing oooh, ahhh.

Getting started.

While rummaging around trying to find a place to start, I ran across nowjs. A real-time framework for server and client communications using node.js and socket.io. What I love about it is, a client can talk to all clients, or the server can talk to all clients. Clients can be added to groups, and it can detect connects and disconnects. The examples are generally for creating web based chat, but it offers much more functionality that can be used for say.... this project.

The best part of node.js and nowjs is that I managed to build the server and client in a matter of minutes.

To start, I installed node.js on my test server, and installed the nowjs module. nowjs is simple to install with:

npm install now

..and we're ready to go.

So, I created a folder for the new project, and created two files, server.js and client.html.

In server.js we want to start by including a few modules and creating the http server that will process post requests from the application, and send data to clients.

var fs = require('fs'),
    sys = require('sys'),
    querystring = require('querystring');
var server = require('http').createServer(function(req, response){
  if (req.method === "POST"){
    // Process POST data  
  } else {
    // Handle clients
});
server.listen(8080);

From here we need to setup nowjs to handle the clients and send the incoming hits to connected clients. To do this, we create the now and everyone objects for nowjs.

var now = require("now");
var everyone = now.initialize(server);

With these defined, we are now ready to start the client and post data handling which makes this thing work. :-) Lets start with the client. The way nowjs works is that everything is shared between client and server. I can create a function or variable in one place, and access it in the other. Since this is a purpose built node.js server, we don't need to serve any more than 1 file. In the code below, if it's not a post, we will only serve one file, client.html.

var fs = require('fs'),
    sys = require('sys'),
    querystring = require('querystring');
var server = require('http').createServer(function(req, response){
  if (req.method === "POST"){
    // Process POST data  
  } else {
    fs.readFile(__dirname+'/client.html', function(err,data){
      response.writeHead(200, {'Content-Type':'text/html'});
      response.write(data);
      response.end();
    });
});
server.listen(8080);

var now = require("now");
var everyone = now.initialize(server);

Now as you can see, we've added the now and everyone objects, and all requests made to the server will serve client.html. Next we need to take post data from the application, and send it out to our connected clients. To do this, we will add event listeners for data and end of the post request.

var fs = require('fs'),
    sys = require('sys'),
    querystring = require('querystring');
var server = require('http').createServer(function(req, response){
  if (req.method === "POST"){
    var post = '';
    req.addListener("data",function(chunk){
      post += chunk;
    }).addListener("end",function(){
      var postData = querystring.parse(post);
      console.log(sys.inspect(postData)+"\n");
      everyone.now.receiveMessage("[ "+postData.i+" ] "+postData.p+" [ "+postData.u+" ] [ "+postData.t+" ] [ "+postData.s+" ] "+postData.r+"");
      response.writeHead(200, {'Content-Type':'text/html'});
      response.end();
    });
  } else {
    fs.readFile(__dirname+'/client.html', function(err,data){
      response.writeHead(200, {'Content-Type':'text/html'});
      response.write(data);
      response.end();
    });
});
server.listen(8080);

var now = require("now");
var everyone = now.initialize(server);

There are plenty of tutorials out there on how to handle post data, I just picked a simple method that worked. The point of interest here is the everyone.now.receiveMessage() function. This is not defined, and is not a property of everyone or now. I'll get to that in a minute. The important point to note here, is that my server is now complete. That's it, though I'm sure it needs some refining, security, etc. In a nutshell, that's 25 lines of code, and we're ready to go server side. Now lets take a look at the client.

As simple as the server was to write, you would think that the client were much more in depth. It may be when I'm done with it, but for the purpose of this tutorial, it was surprisingly simple. Basically we needed to include two dependencies, jquery and now.js.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js" type="text/javascript"></script>
<script src="/nowjs/now.js"></script>

Once we have that in place, all we really need to do is define now.receiveMessage() and create the messages div, as seen below.

<script>
$(document).ready(function(){
  now.receiveMessage = function(message){
    $("#messages").append("<br>" + message);
  }
});
</script>

And we add our messages div in the body.

<div id="messages"></div>

Now, I won't get into posting the data from the application to the node.js server. Basically, I add a script to the footer of each page which posts data via ajax to a script on the server which curls that data over to our node.js server. :-) Once we have the client and the server set up, all we have to do is run it.

node server.js

Once connected to the client, and pushing the app script live, we start to see hits pop up in our simple, no-db hit log. :-)

You can see the full source of both files below and I'm going to go work on my next node.js project!

Cheers!

 

var fs = require('fs'),
    sys = require('sys'),
    querystring = require('querystring');
var server = require('http').createServer(function(req, response){
  if (req.method === "POST"){
    var post = '';
    req.addListener("data",function(chunk){
      post += chunk;
    }).addListener("end",function(){
      var postData = querystring.parse(post);
      console.log(sys.inspect(postData)+"\n");
      everyone.now.receiveMessage("[ "+postData.i+" ] "+postData.p+" [ "+postData.u+" ] [ "+postData.t+" ] [ "+postData.s+" ] "+postData.r+"");
      response.writeHead(200, {'Content-Type':'text/html'});
      response.end();
    });
  } else {
    fs.readFile(__dirname+'/client.html', function(err,data){
      response.writeHead(200, {'Content-Type':'text/html'});
      response.write(data);
      response.end();
    });
});
server.listen(8080);

var now = require("now");
var everyone = now.initialize(server);

 

client.html

<!DOCTYPE html>
<html lang="en">
<head>
<title>Real Time Test</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script src="/nowjs/now.js"></script>
<script>
$(document).ready(function(){
  now.receiveMessage = function(message){
    $("#messages").append("<br>" + message);
  }
});
</script>
</head>
<body>
<div id="messages"></div>
</body>
</html>

Posted July 21, 2011

A web developer without a website.

Am I the only web developer that forgets about his own website?

So, I decided to have a peek at my website (which I don't do very often), and what do ya know. "Your account has been suspended.". =O Nearly ten servers, eating massive holes in my pocket each month, I managed to let a little $5/mo. hosting account expire. For some reason, all past attempts at managing my own website have failed. I've designed and built four versions, set up two blogs, and have yet to make it past the second or third post. I think it's time for a change.

I've given up taking the time to setup a new website, blog, etc. simply because, I end up putting more effort into the website than I do maintaining it after it's put together. Enter Posterous. I'll skip how I came to found posterous and get right to the point. In about 10-25 lazy minutes, I've gone from no website, to themed site/blog, and first post done. Let's hope I can mange to keep this one up to date. Maybe integrating the API into something I use every day will keep me motivated and in tune.

Hopefully in my next post, I'll be talking about some node.js project I'm starting, or maybe an HTML5 game, or both actually. Well, I should probably be taking baby steps, but I can't help diving head strong into something interesting. :-)

To the 0 readers I have now,

Cheers! 

Posted July 20, 2011