Skip to content

Instantly share code, notes, and snippets.

@JessieAMorris
Created December 14, 2010 00:45
Show Gist options
  • Save JessieAMorris/739849 to your computer and use it in GitHub Desktop.
Save JessieAMorris/739849 to your computer and use it in GitHub Desktop.
The guts of the IRC bot.
ruleset a41x149 {
meta {
name "IRC Bot"
description <<
IRC Bot
>>
author ""
logging off
}
dispatch {
// Some example dispatch domains
// domain "example.com"
// domain "other.example.com"
}
global {
// datasource which has the insults
datasource shakespeare:HTML <- "http://www.pangloss.com/seidel/Shaker/" cachable for 1 seconds;
// A function that will get the channel name (#kynetx) if message was in a channel or the username (private messages)
getChannel = function(parameters){
parameters.pick("$.channel").match(re/^#/) => parameters.pick("$.channel") | parameters.pick("$.user");
};
}
rule say {
select when irc recieved text ".*?~say\s+(.*)\s+(.*).*?" setting (text,channel)
// Rule selects when a message from irc is received with text containing that regex.
// It also grabs the text and channel.
// example: selects if you type "~say Hello #kynetx"
pre {
eventParams = event:params();
}
// say <text> to <channel>
send_directive("say") with text = "#{text}" and to = channel;
// No more commands should fire after this one.
fired {
last;
}
}
rule irc_insult is active {
select when irc recieved text ".*?~insult\s+(\w+).*?" setting (username)
// Selects when a message in IRC has the text matching regex.
// Grabs username so that a specific user can be insulted.
pre {
eventParams = event:params(); // grabs all event parameters passed in
channel = getChannel(eventParams); // runs the getChannel function
page = datasource:shakespeare({}); // call the shakespeare datasource to get an insult
insult = page.query("font[size=+2]", true); // grabs the insult out of the HTML
textToSay = "#{username}: #{insult[0]}"; // constructs the message in the form of <username>:<insult>
}
send_directive("say") with text = "#{textToSay}" and to = channel; // say the text and to the channel
fired {
last;
}
}
}
// change settings and save to ./config.js
exports.config = {
host: 'chat.freenode.net',
port: 6667,
user: 'AKynetxBot',
channel: '#kynetx-test',
};
// File location should be ./lib/irc.js
var sys = require('sys');
var tcp = require('net');
var irc = exports;
function bind(fn, scope) {
var bindArgs = Array.prototype.slice.call(arguments);
bindArgs.shift();
bindArgs.shift();
return function() {
var args = Array.prototype.slice.call(arguments);
fn.apply(scope, bindArgs.concat(args));
};
}
function each(set, iterator) {
for (var i = 0; i < set.length; i++) {
var r = iterator(set[i], i);
if (r === false) {
return;
}
}
}
var Client = irc.Client = function(host, port) {
this.host = host || 'localhost';
this.port = port || 6667;
this.connection = null;
this.buffer = '';
this.encoding = 'utf8';
this.timeout = 10 * 60 * 60 * 1000;
this.nick = null;
this.user = null;
this.real = null;
}
sys.inherits(Client, process.EventEmitter);
Client.prototype.connect = function(nick, user, real) {
var connection = tcp.createConnection(this.port, this.host);
connection.setEncoding(this.encoding);
connection.setTimeout(this.timeout);
connection.addListener('connect', bind(this.onConnect, this));
connection.addListener('data', bind(this.onReceive, this));
connection.addListener('end', bind(this.onEof, this));
connection.addListener('timeout', bind(this.onTimeout, this));
connection.addListener('close', bind(this.onClose, this));
this.nick = nick;
this.user = user || 'guest';
this.real = real || 'Guest';
this.connection = connection;
};
Client.prototype.disconnect = function(why) {
if (this.connection.readyState !== 'closed') {
this.connection.close();
this.emit('DISCONNECT', why);
}
};
Client.prototype.send = function(arg1) {
if (this.connection.readyState !== 'open') {
return this.disconnect('cannot send with readyState: '+this.connection.readyState);
}
var message = [];
for (var i = 0; i< arguments.length; i++) {
if (arguments[i]) {
message.push(arguments[i]);
}
}
message = message.join(' ');
message = message + "\r\n";
this.connection.write(message, this.encoding);
};
Client.prototype.parse = function(message) {
var match = message.match(/(?:(:[^\s]+) )?([^\s]+) (.+)/);
var parsed = {
prefix: match[1],
command: match[2]
};
var params = match[3].match(/(.*?) ?:(.*)/);
if (params) {
// Params before :
params[1] = (params[1])
? params[1].split(' ')
: [];
// Rest after :
params[2] = params[2]
? [params[2]]
: [];
params = params[1].concat(params[2]);
} else {
params = match[3].split(' ');
}
parsed.params = params;
return parsed;
};
Client.prototype.onConnect = function() {
this.send('NICK', this.nick);
this.send('USER', this.user, '0', '*', ':'+this.real);
};
Client.prototype.onReceive = function(chunk) {
this.buffer = this.buffer + chunk;
while (this.buffer) {
var offset = this.buffer.indexOf("\r\n");
if (offset < 0) {
return;
}
var message = this.buffer.substr(0, offset);
this.buffer = this.buffer.substr(offset + 2);
message = this.parse(message);
this.emit.apply(this, [message.command, message.prefix].concat(message.params));
if (message !== false) {
this.onMessage(message);
}
}
};
Client.prototype.onMessage = function(message) {
switch (message.command) {
case 'PING':
this.send('PONG', ':'+message.params[0]);
break;
}
};
Client.prototype.onEof = function() {
this.disconnect('eof');
};
Client.prototype.onTimeout = function() {
this.disconnect('timeout');
};
Client.prototype.onClose = function() {
this.disconnect('close');
};
exports.user = function(prefix) {
return prefix.match(/:([^!]+)!/)[1]
};
// Includes the needed libraries and config files.
var sys = require('sys');
var config = require('./config')['config'];
var irc = require('./lib/irc');
/* kynetx lib/setup */
var knsevents = require('kns');
kns = new knsevents('a41x140', {
'appversion': 'dev',
'eventdomain': 'irc',
'logging':'true'
});
var client = new irc.Client(config.host, config.port);
// connect to IRC
client.connect(config.user);
// On connect, join the given channel;
client.addListener('001', function() {
console.log("Connected!");
this.send('JOIN', config.channel);
});
// A user joined the channel
client.addListener('JOIN', function(prefix, channel, text) {
var user = irc.user(prefix);
kns.signal("joined", {"user":user, "channel":channel});
});
// A user left the channel
client.addListener('PART', function(prefix, channel, text) {
var user = irc.user(prefix);
kns.signal("leave", {"user":user, "channel":channel});
});
// Regular message
client.addListener('PRIVMSG', function(prefix, channel, text) {
var user = irc.user(prefix);
kns.signal("recieved", {'text':text,'channel':channel,'user':user});
});
// directive handlers (callbacks)
// error
kns.on("error", function(error){
console.log("ERROR:");
console.log(error);
client.send("PRIVMSG", config.channel, ":There was an error connecting to KNS");
});
// say something in the channel
kns.on("say", function(eventargs){
if(eventargs.to && eventargs.text){
client.send("PRIVMSG", eventargs.to, ":" +eventargs.text);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment