Writing a very simple IRC bot in Node.js
We will be using the net module, specifically net.Socket.
The basic bot
The extremely extremely basic IRC bot: (does not respond to ping)
var net = require('net');
var irc = {};
irc.socket = new net.Socket();
irc.socket.on('connect', function () {
console.log('Established connection, registering and shit...');
setTimeout(function () {
irc.raw('NICK nick');
irc.raw('USER callum 8 * :Node.js IRC bot');
}, 1000);
});
irc.socket.setEncoding('ascii');
irc.socket.setNoDelay();
irc.socket.connect(6667, 'irc.freenode.net');That's it. That code will connect to freenode under the nick "nick", idle for a couple minutes, and time out.
We want it to do something though, so we will add "listeners" to make it easy and avoid core code edits:
irc.socket.on('data', function (data) {
data = data.split('\n');
for (var i = 0; i < data.length; i++) {
console.log('RECV -', data[i]);
if (data !== '') {
irc.handle(data[i].slice(0, -1));
}
}
});
//handles incoming messages
irc.handle = function (data) {
var i, info;
for (i = 0; i < irc.listeners.length; i++) {
info = irc.listeners[i][0].exec(data);
if (info) {
irc.listeners[i][1](info, data);
if (irc.listeners[i][2]) {
irc.listeners.splice(i, 1);
}
}
}
};
irc.listeners = [];
irc.on = function (data, callback) {
irc.listeners.push([data, callback, false])
};
irc.on_once = function (data, callback) {
irc.listeners.push([data, callback, true]);
};This is fairly simple: use
irc.onwith a regex and a callback, and when the regex matches something, the callback is called.
irc.on_onceis similar, but it'll only be called once - good for something like joining a channel and setting a callback to send a message when we have joined the channel, instead of hoping you're on a fast connection and risking a 404 error. We'll also add an
irc.rawmethod, because we're too lazy to send everything manually:
irc.raw = function (data) {
irc.socket.write(data + '\n', 'ascii', function () {
console.log('SENT -', data);
});
};That writes the data to the socket, and then when it has been written logs it to console.
This is how you tell it to respond to ping:
irc.on(/^PING :(.+)$/i, function (info) {
irc.raw('PONG :' + info[1]);
});I said it was easy ;-)
The full code is here: https://gist.github.com/996827. The full code also contains configuration and automatic channel joining on connect, which is fairly self explanatory.
Additional features
Here are a few extra things you may wish to add:
Nick changes
When the bot's nick changes, it updates
irc.nick. This can be handy for other things, including a few methods I'll be putting below this one.
irc.on(/^[^ ]+ 001 ([0-9a-zA-Z\[\]\\`_\^{|}\-]+) :/, function (info) {
irc.nick = info[1];
});
irc.on(/^:([^!]+)![^@]+@[^ ]+ NICK :(.+)$/, function (info) {
if (info[1] === irc.nick) {
irc.nick = info[2];
}
});Join channel
This is fairly self explanatory, but just demonstrates how you can use
irc.on_oncefor callbacks.
irc.join = function (chan, callback) {
if (callback !== undefined) {
irc.on_once(new RegExp('^:' + irc.info.nick + '![^@]+@[^ ]+ JOIN :' + chan), callback);
}
irc.info.names[chan] = {};
irc.raw('JOIN ' + chan);
};(Yeah I know, my regex for that one sucks. But it works.)
Send message to channel
This code splits the message into nicely sized chunks, and then sends them.
irc.msg = function (chan, msg) {
var max_length, msgs, interval;
max_length = 500 - chan.length;
msgs = msg.match(new RegExp('.{1,' + max_length + '}', 'g'));
interval = setInterval(function () {
irc.raw('PRIVMSG ' + chan + ' :' + msgs[0]);
msgs.splice(0, 1);
if (msgs.length === 0) {
clearInterval(interval);
}
}, 1000);
};Kick / ban from channel
I think this is the only complicated piece of code in the entire thing.
irc.kickwithout ban specified is boring and just kicks the user, but with ban specified, it sends the ban command, waits for it to be executed, and then kicks the user, too.
irc.kick = function (nick, chan, msg, ban) {
if (ban !== undefined) {
irc.ban(nick, chan, function () {
irc.kick(nick, chan, msg);
});
return;
}
irc.raw('KICK ' + chan + ' ' + nick + ((msg !== undefined) ? ' :' + msg : ''));
};
irc.ban = function (nick, chan, callback) {
var host, regex;
if (irc.info.names[chan][nick] === undefined) {
return false;
}
host = irc.info.names[chan][nick].host;
regex = '^:' + irc.info.nick + '![^@]+@[^ ]+ MODE ' + chan + ' \\+b \\*!\\*@' + host;
if (callback !== undefined) {
irc.on_once(new RegExp(regex), function () {
callback();
});
}
irc.raw('MODE ' + chan + ' +b *!*@' + host);
};Remember: when in doubt, consult RFC 1459! (cmd+f is your friend)






Cartoon Clouds
Mountains
Sunrise
Clouds
Green Clouds
None













Help