Intro - What is node.js
Node.js is a event based server side JS application. The reason that I refer to node as a application not a framework is because you write JavaScript not node. Node.js simply parses and runs your JavaScript while at the same time providing users with some core libraries with which to build applications with. In the background node uses the v8 JavaScript engine to extract the maximum performance out of JavaScript.
Server side JavaScript is nothing new , mozilla has been doing it for a while but it has never
this accessible. Writing server side JavaScript means that you use JavaScript in a the way
you would use any other programming language but for a function that it is really good at (dealing with events and callbacks).
But the most important difference between normal browser based JavaScript and node is that you
dont have a browser dom to work with , so familiar variables like window
do not exist , instead
you are given a new variables like process
which gives you information about the current running
node process. While you do no work with the browser it does not mean you can not work with web pages.
There are a good few libraries that provide this functionality (more on this later).
Getting started with node.js is pretty easy if you are familiar with the unix way of building applications from source. If not this article should get you going pretty quickly, the basics are get the source, configure , build , build install. There are distribution for windows but it lags slightly behind the latest version , you could of course build it from source if you wanted to. Although you should keep in mind that unix is the preferred dev/working environment.
Once you have node up and running , you can check that everything is working by simply typing
node at the command line. This will launch the node.js repl interpreter which is extremely useful
for testing small chunks of code as you are working. To run a node script type node script.js
at
the console and node will execute your script.js file.
A simple console hello world can be seen below.
One of the things that many people find hard to grasp is the non-blocking aspect of node. Non blocking is simply the concept of fire and forget in such a way that it never waits for a response from a line of code. An example of this is listed below.
var fs = require('fs');
fs.writeFile('/tmp/1.txt', 'some content that takes long to write', function() {
console.log('done writing file');
});
console.log('some other message');
The code above does 2 things , it writes to messages to the console and writes a file to the disk. When you run the code because writeFile is non blocking it fire of the text writing code and immediately print ‘here I am’ , once the file is finished writing it will print ‘done writing file’. In a synchronous language we would typically write it something like this :
file.writeText('some text')
print done writing file
print some other message
Because line 2 would only print once the code is finished writing the text to file in contrast if we had to write the same code the done writing file would fire before the file was finished writing to disk
The code below is a example of a node hello world application. You can paste this into the node
interpreter or save it to a js file. If executing it from a js file run , node <filename.js>
where
filename is the name of the file you saved the text into
Hello World Server
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');
This example creates and hosts a web server on port 1337 , when ever a client connects to it (with a web browser,curl,wget) it will return the words Hello World. Something to be kept in mind is that this is all non blocking so when the code runs it doesn’t halt and the createServer line and wait for input. Rather it hooks up a callback to the request that will be executed every time a user requests the url. This is important because until a user hits the server the pc is not doing anything it is simply idling and waiting for a request on the web server.
So why would you want to use node over any other language , well there is no magic bullet with node , you simply have to evaluate it to see if it makes sense to use node or not to use it. For example are you happy that its still in development , do you need to be able to handle multiple concurrent connections , what is the size of your project. These are just some of the questions that you need to ask.
If you want a better explanation of the ups and downs of node and how it handles processing I highly suggest reading this article by Felix Geisendorger
So lets build something
We are going to walk through building a fairly simple IRC bot that will log all the conversation in a channel as a means of archiving data.
Before building there are a few things we need to know about what the bot should do.
- Connect to IRC and idle
- When a user send a message to the channel it should save it to file.
We next need to decide what node.js libraries we want to use , in almost all cases there are already libraries out there for interacting with various services.
- There is already a IRC lib called irc so half our work is done.
The file system interaction is built into the default libraries node provides so we dont need worry about anything else. Node.js libraries can be acquired by 2 methods , either get the source code directly from the user( or repo ) or install it with a package manager. There are quite a few package managers out there but we will be using npm.
Getting Started
This tutorial will be run on a mac and should work on any unix enviroment , windows users will just have to adapt.
First follow the instructions here to install node and npm. Only proceed once you have both installed.
Next in your console run the following command to create a dir and change into it and then finally create a blank file that we will fill later.
mkdir ircWatch && cd ircWatch
touch app.js
Next install the libs that we are going to be using with the commands below.
npm install irc
By default npm install modules into a local folder called node_modules unless you use the -g option to install into the global dir. You will notice that when ever node installs a library it all the source files for that library can be found in the folder ./node_modules/moduleName/lib/. This is very usefull for debugging and generally learning how the various libraries are written.
app.js
Lets start by loading and caching the file system and irc libraries.
var ircLib = require('irc');
var fs = require('fs');
This does 2 things it loads the irc lib and stores the resulting library object in the ircLib variable. If you ever need to make calls to the irc library you now do it throught the ircLib variable. We do the exact same thing for the file system library (called fs).
Next we need to setup the irc connection and handle any events it may expose. This is done as follows :
var client = new ircLib.Client('republiccommandos.co.za', 'mybot', {
channels: ['#jumpdeck'],
});
Here we are creating a instance of the irc client and passing some default
parameters to it. The first param is the server to connect to , next the
name of the bot and finally the channel to join. By default the bot is set
to auto join as soon as the app is run ,if you do want this you can add autoConnect : false
after the channels and then call client.join('#channel')
to join a
specific channel. If you want more info about what parameters you can pass
and what else the lib can do look at the readme here
You now have the base for the app complete if you save the file , you can
start your bot with the command node app.js
. This will run the app and connect
to the server you specified in your parameters. The bot does nothing yet but
we shall give it some power soon.
Logging info and writing to the filesystem
As you may have noticed our bot doesnt do much besides idle , so its time for it to start listening to other people and save it to file. To do this we hook into the events the ircLib exposes. Currently we are interested in the ‘message’ event. To hook up a listener to this event use the following code:
client.addListener('message', function (from, to, message) {
});
Now when ever the client object fires the message event (which indicates there is a new message in the channel) we can execute our code to save the message to disk.
fs.open('irc.log', 'a', function( e, id ) {
fs.write( id, message+'\n', null, 'utf8', function(){
fs.close(id, function(){ });
});
});
The code above opens the irc.log file in append mode , if the file does not exit it will be created. After its opened it will then write the message the message to file. Its important to note that we need to add a new line char to the end of the file , otherwise all the data will be written to a single line.
Now we dont close the file imediately after calling fs.write since the write is happening async and as such if you close it before it has had a chance to write no data will be saved. To solve this we only call fs.close in the call back function to ensure that its only called after the data is written.
Now you may be wondering at this point if we are going to have inconsistent writes because we are only closing the file after each write. Node handles this correctly by ensuring that the functions fire in the correct order in the background.
<jameel> hello
<jameel> test
<jameel> 123
So if we had to send the messages above all at once (but in the order above) node will correctly write it to file in the exact same order that it was recived in the channel.
This is a really simple example to get you up and running with something useful in node.js (I spend alot of time in IRC) , but there is alot more that you can do with this example you can add date stamps , save to a db instead of to file, create a file per day to name but a few.