Building a IRC bot with node.js

Reading time ~9 minutes

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.

console example

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.

  1. Connect to IRC and idle
  2. 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.

  1. 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.

Application deployment at scale with torrents

# Intro This post will give a short overview on how to deploy your app and subsequentupdates using torrents. First some basics will be co...… Continue reading

Race Report - Soweto Marathon

Published on November 19, 2016

Review - Theft of swords

Published on November 19, 2016