Boter is a simple library to build your own smooth IRC bot using node.js. It allows you to easily respond to highlights, mentions and PMs.
Boter is built on top of the excellent node-irc and written in CoffeeScript. The name (boter) is obviously derived from the word "bot" but is also the Dutch word for "butter".
Installation is as simple as:
$ npm install boter
If you want to hack on boter or check if it works correctly on your system you can clone the repository or copy the files to your path of choice, and then:
$ cd path/to/node-boter/
$ npm install
You can then run the tests by simple calling:
$ cake test
You can create a boter Bot like your would create a node_irc
client:
var boter = require('boter');
var opts = {
channels: [#bar]
};
var bot = new boter.Bot('irc.server.foo', 'MyBoter', opts);
In addition to the nickname, you can give the bot a few aliasses to which it will respond:
var opts = {
channels: [#bar],
aliasses: ['BoterBot', 'Boter']
}
var bot = new boter.Bot('irc.server.foo', 'MyBoter', opts);
Now for the fun part: receiving and sending messages. Since version 1.0.0, boter is plugin-based. It's really easy to write a plugin. For example, here's a simple "Good morning" plugin:
goodMorning = function(message) {
if (/^good morning/.test(message.text))
message.reply("Good morning to you, too, "+message.from+"!");
}
goodMorningPlugin = {
events: {
highlight: goodMorning,
mention: goodMorning
}
};
Now all you have to do is load the plugin:
bot.load(goodMorningPlugin);
...and use it!
<Someone>: BoterBot: Good morning!
<MyBoter>: Good morning to you, too, Someone!
<Person>: good morning, boter.
<MyBoter>: Good morning to you, too, Person!
Note that the "BoterBot: " prefix is automatically trimmed from the message, and message.text
is lower cased. The original text (also trimmed, but not decapitalized) can be found in message.original
.
Boter allows you to listen to three kinds of events:
'pm'
event handlers are called when a PM (or "query") is received;'highlight'
when the Bot is specifically adressed, e.g. "BoterBot: hey, you!";'mention'
when the bot is mentioned elsewhere in the message. e.g. "Ceterum censeo boterbot delendam est.".
All of these events pass a Message
object to the callback, as shown above. Mentions and highlights are triggered on the bot's nick or any of its aliasses, which are matched case insensitively.
Boter also supports a command-style system, which is also tied in with the plugin system. A plugin can listen for commands as wel as other types of messages, so you can make your plugins as flexible as you like.
To extend the example from above:
// goodMorning = function(message) { // ... }
goodMorningPlugin = {
events: {
highlight: goodMorning,
mention: goodMorning
},
commands: {
hello: goodMorning,
greet: goodMorning
}
};
bot.load(goodMorningPlugin);
And now it listens to commands as well!
<Someone>: !greet
<MyBoter>: Good morning to you, too, Someone!
Easy as ~3.1415
!
All event and command handlers receive a message
object. You've already seen message.text
and message.reply
. It has a few more properties:
The text of the message, converted to lower case. If the message highlights the bot (e.g. "BotNick: how are you?"), the bot's nickname is trimmed from the message (e.g. "how are you?").
Not converted to lower case, but otherwise the same as text
.
The user that sent the message. This is a user
object (see below), so to get the user's nickname, use message.from.nickname
.
Where the message was sent to. This is either the name of a channel (e.g. "#ponies") or the name of a user, depending on whether it was a channel message or a PM.
Shortcut to bot.say(message.context, replyText)
, if you have access to the bot
. This allows you to easily respond to incoming messages.
If the original message was a PM, reply
sends a PM back to the sender. If it was a channel message, the reply
goes to the same channel.
Removed any whitespace from the beginnen and end of message.text
and message.original
.
Known users are saved to a tiny database. As mentioned before, message.from
contains a special user
object. It has the following properties:
The user's nickname. Case sensitive.
This function can be used to check user rights. It can check whether the user is registered with NickServ, whether the user is an admin
, and whether the user has channelOp
status in a given channel.
// the chanOp check return the result immediately:
isChanOp = user.is('op', '#pwnies');
// the other two use callbacks:
user.is('registered', function(isRegistered){
console.log("Registered:", isRegistered);
});
user.is('admin', function(isAdmin){
console.log("Admin:", isAdmin);
});
Shortcut to send the user a PM.
Kick the user from the given channel
for the given reason
(optional). Only works if the bot has ops status in that channel (obviously).
Sets whether the user is an admin.
user.setIsAdmin(true, function(error) {
if (!error) {
console.log("User", user.username, "successfully made admin.");
}
});
Note: a user can be made admin while he or she is not registered with NickServ, but user.is('admin')
will only report true
while the user is registered.
Alternatively, you can use user.makeAdmin(cb)
and user.unmakeAdmin(cb)
.
To get access to the bot's methods in your plugin, you could define your plugin in the same file as the bot. But there is a cleaner (and safer) way to get access to some of the bot's features: the botProxy
.
Instead of returning an object
as your plugin, return a function
:
goodMorningPlugin = function(botProxy) {
console.log(botProxy)
// { say: [Function], action: [Function], checkNickServ: [Function], getUser: [Function] }
return {
events: // ...
commands: // ...
}
}
Make the bot say something in the given context
(which can be a channel, like #ponies
; or a user, in which case it's a PM).
Make the bot do an action
in the given context
(which can be a channel, like #ponies
; or a user, in which case it's a PM).
Actions are what happens when you use /me does something
in your IRC client.
Trigger a NickServ status check. The user DB will be updated. The callback is optional, but if given, it will report back whether the user is registered with NickServ.
bot.checkNickServ('someUser', function(isRegistered) {
console.log("User is registered:", isRegistered);
});
Get a user
object for the user with the given nickname
. For a description of this object, see User management.
bot.getUser('someUser', function(err, user) {
if (err) console.warn err
else {
user.kick('#pwnies', "Muhuhahahaha");
}
});
At the moment, the load
command is the only way to manage plugins. I'm still working on an easy-to-use system to load plugins from files, as well as load, unload and reload plugins while the bot is running. Look for that in the next version. :)
To run the test:
$ cd path/to/node-boter/
$ cake test
In addition, you can:
- use
cake build
to build the CoffeeScript source tolib/
; - use
cake watch
to monitor and run the test when they change, or; usecoverage is broken right now because of the switch fromcake coverage
to generate a code coverage report (which is saved tolib-cov/report.html
).make
tocake
.
Alternatively, you can use npm [command]
instead of cake [command]
(they're equivalent).
Note: jscoverage
is needed to generate a coverage report.
For testing, boter uses Mocha and should.js. In addition, Mockery and sinon are used to test in isolation (with a mock of node_irc
).
This software is licensed under the Simplified BSD License (see LICENSE).