Wednesday, August 17, 2011

Design Primitives in Javascript: Pulling it Together

Now to pull together the components into a functional random number and date server!  I'm certain to get loads of venture funding for this highly in demand service, something to look forward to.

Anyway, at this level, I maintain two modules.  The first, the Node.js entry point, starts the server with callbacks defined in the main module.  To be precise, the first file is not actually a module as we've defined modules so far.  Rather, it's a simple script calling the appropriate bootstrapping methods:

(server.js)

var net = require('net');
var main = require('./main').main;


net.createServer(main.connection_listener)
  .listen(1337, "127.0.0.1", main.event_listener);

That's it! Pretty cool.  This just spawns a server on port 1337 using listeners defined in main, where the bulk of the communication implementation resides:

(main.js)

var version = require('./version').version;
var date = require('./date').date;
var random = require('./random').random;


exports.main = function() {



  // This is a private class object used to build 
  // the response generator needed based on the 
  // type of request. The dispatch(.) method takes 
  // a string and then calls the corresponding 
  // factory method based on the predefined module 
  // interfaces (see the previous two posts for 
  // more information on  those interface 
  // definitions).  If someone  requests an 
  // operation we don't recognize, we create an
  // anonymous class object implementing 
  // the generator interface.
  var _processor = function() {

    var SCALE = 10;
    var DATE = 1;
    var RANDOM = 2;
    var UNKNOWN = 3;

    var parser = function(cmd) {
      if (cmd.match(/date/ig)) return DATE;
      if (cmd.match(/random/ig)) return RANDOM;
      return UNKNOWN;
    }


    this.dispatch = function(cmd) {
      var generator;
      switch(parser(cmd.toString())) {
        case DATE:
          generator = new date.Generator();
          break;
        case RANDOM:
          generator = new random.Generator(SCALE);
          break;
        default:
          generator = new function() {
            this.generate = function() { 
              return 'undefined token submitted.';
            }
          }
      }
      return generator.generate();  
    }

  }



  // This is a private function building a version 
  // string using information defined in the version
  // module.
  var _build_version_string = function() {
    return version_string = version.major + '.' 
      + version.minor + '.' 
      + version.patch + ' - '
      + version.status;
  }



  // The server entry point.  We write output to the 
  // requestor socket as well as debug information 
  // to the console, first. We then define a handler
  // for submitted data using our private processor
  // class.  The handler processes the request
  // and emits a bit more status information to the
  // console.  Finally, we drop binding status to the
  // console and return.
  var _entry_pt = function(socket) {

    socket.write('date & random server: ' 
      + _build_version_string()
      + '; enter command\r\n', 
      'ascii', 
      function() { 
        console.log('...welcome sent to ' 
        + socket.remotePort 
        + '@' 
        + socket.remoteAddress); 
      });

    var processor = new _processor();


    socket.on('data', function(data) {
      console.log('data received: "' + data + '"');
      var retval = processor.dispatch(data);
      console.log('response: ' + retval);
      socket.write(retval + '\r\n');
    });


  }


  var _event_listener = function() {
    console.log('...server has been bound.'); 
  }


  // The module signature implementation.
  return {
    connection_listener: _entry_pt,
    event_listener: _event_listener
  }
}();


Note the comments above describing what's what in the implementation module.


Now, to run this on the command line type:


$ node lib/server.js


This'll bootstrap the server and kick it off, sending confirmation messages to the console.  To connect, use telnet:


$ telnet localhost 1337


And you'll be greeted by the smarmy welcome screen:


Connected to localhost.
Escape character is '^]'.
date & random server: 1.0.0 - gold; enter command

From here, you can type random or date.  The response will be either a randomly generated number or the current date.  That's it!  Now, I would generally not do something even this trivial without some kind of unit test support.  Next, I'm going to delve into how you can integrate Jasmine with Node.js to do test driven development.

No comments:

Post a Comment