summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--atom-bot/index.js217
-rw-r--r--dynobot-irc.js53
-rw-r--r--irc-client.js1
-rw-r--r--package.json5
4 files changed, 213 insertions, 63 deletions
diff --git a/atom-bot/index.js b/atom-bot/index.js
index 7de99bc..18eaf14 100644
--- a/atom-bot/index.js
+++ b/atom-bot/index.js
@@ -21,57 +21,55 @@
require('tinycolor');
var cron = require('cron').CronJob
- , parser = require('blindparser')
, events = require('events')
+ , fs = require('fs')
+ , parser = require('blindparser')
+ , url = require('url')
, _ = require('underscore');
-var irc = function() {
- var Proxy = require('../node_modules/dynobot/proxy');
- var Channel = require('../node_modules/dynobot/channel');
- var IrcClient = require('../irc-client.js').IrcClient;
+var Proxy = require('../node_modules/dynobot/proxy');
+var Channel = require('../node_modules/dynobot/channel');
- var channel = new Channel();
- return new Proxy(IrcClient.prototype, 'irc', channel);
-}();
+var irc = new Proxy(require('../irc-client.js').IrcClient.prototype, 'irc', new Channel());
function log(message) {
console.log(('log ' + message).green);
}
-var parserOptions = {};
-
-// Config
-var channel = '#dynobot';
-var feeds = [
-// "http://search.twitter.com/search.atom?q=from:AgileBorat",
-// "http://search.twitter.com/search.atom?q=from:KongenDin",
-// "http://search.twitter.com/search.atom?q=from:NestenSivJensen",
- "http://search.twitter.com/search.atom?q=ndc2012"
-// "http://search.twitter.com/search.atom?q=awesome",
-// "http://search.twitter.com/search.atom?q=eurovision",
-];
-var cronJobs = [];
+var config;
var state = {
channelTopic: undefined,
topic: undefined,
- updatingFeed: false,
- feeds: [],
newest: {
timestamp: 0,
text: undefined
}
};
+var feeds = {};
+
+function FeedState(url) {
+ this.url = url;
+ this.updatingFeed = false;
+ this.last = undefined;
+ this.job = undefined;
+}
+
var eventEmitter = new events.EventEmitter;
+function parseFeed(url, cb) {
+ var parserOptions = {};
+ parser.parseURL(url, parserOptions, cb);
+}
+
function updateFeed(feedState) {
log("Fetching " + feedState.url);
if(feedState.updatingFeed)
log("Already working");
feedState.updatingFeed = true;
- parser.parseURL(feedState.url, parserOptions, function(err, feed) {
+ parseFeed(feedState.url, function(err, feed) {
log("Fetched " + feedState.url + ", status=" + (err ? "failure" : "success"));
if(err) {
log(err);
@@ -106,7 +104,7 @@ function processFeed(feed) {
}
eventEmitter.on("feedChanged", function(url, newest) {
- state.feeds[url] = newest;
+ feeds[url].newest = newest;
if(state.newest.timestamp >= newest.timestamp) {
log("oold: " + newest.text);
@@ -120,33 +118,55 @@ eventEmitter.on("feedChanged", function(url, newest) {
state.newest = newest;
/*
if(state.channelTopic != text) {
- irc.topic(channel, text);
+ irc.topic(config.channel, text);
}
*/
- irc.notice(channel, text);
+ log(config.channel);
+ irc.notice(config.channel, text);
});
+function appendFeed(feedUrl) {
+ var feedState = new FeedState(feedUrl);
+ log("Job starting for " + feedUrl);
+ feedState.job = new cron("*/10 * * * *", function() {
+ updateFeed(feedState);
+ }, function() {
+ log("Job stopping for " + feedUrl);
+ }, true);
+ feeds[feedUrl] = feedState;
+ log("appendFeed: keys=" + _.keys(feeds));
+}
+
+function removeFeed(feedUrl) {
+ log("removeFeed: feedUrl=" + feedUrl);
+ log("removeFeed: keys=" + _.keys(feeds));
+ var feedState = feeds[feedUrl];
+ log("removeFeed: feedState=" + typeof feedState);
+ if(_.isObject(feedState)) {
+ log("removeFeed: keys feedState=" + _.keys(feedState));
+ feedState.job.stop();
+ }
+ else {
+ log("removeFeed: feed not found");
+ }
+ delete feeds[feedUrl];
+ log("removeFeed: keys=" + _.keys(feeds));
+}
+
function setup() {
- log("Stopping " + cronJobs.length + " cron jobs");
- _.each(cronJobs, function(job) { job.stop(); });
- cronJobs = [];
- _.each(feeds, function(feed) {
- var state = {
- url: feed,
- updatingFeed: false,
- last: undefined
- };
- var job = new cron("*/10 * * * *", function() {
- updateFeed(state);
- }, function() {}, true);
- cronJobs.push(job);
+ log('Starting..');
+
+ loadConfig(function(err, config) {
+ log('config: ' + JSON.stringify(config));
+ irc.join(config.channel, function(c) {
+ irc.notice(config.channel, 'Atom plugin online. Monitoring ' + config.feeds.length + ' feeds.');
+ });
+ _.each(config.feeds, function(feed) {
+ appendFeed(feed);
+ });
});
}
-irc.join(channel, function(c) {
- irc.notice(channel, 'well hello yall: ' + c);
-});
-
irc.on('topic', function(channel, topic) {
log("new topic: " + topic);
/* If we're not storing this, it is possible for people to set
@@ -158,4 +178,113 @@ irc.on('topic', function(channel, topic) {
state.channelTopic = topic;
});
+irc.on('privmsg', function(nick, channel, message) {
+ irc.whoami(function(whoami) {
+ // Hm, what happens if a nick contain funny characters like '.
+ var reg = new RegExp('^' + whoami + ': atom ');
+ if(!reg.test(message)) {
+ return;
+ }
+ var args = message.substring(whoami.length + 7).split(' ');
+
+ if(args.length < 1) {
+ usage(channel);
+ return;
+ }
+ var rest = _.rest(args);
+ switch(args[0]) {
+ case 'list-feeds': onListFeeds(channel); break;
+ case 'add-feed': onAddFeed(channel, rest); break;
+ case 'remove-feed': onRemoveFeed(channel, rest); break;
+ case 'load-config': onLoadConfig(channel); break;
+ }
+ });
+});
+
+function usage(channel) {
+}
+
+function onListFeeds(channel) {
+ _.each(config.feeds, function(feed, i) {
+ irc.notice(channel, 'feed #' + i + ': ' + feed);
+ });
+}
+
+function onAddFeed(channel, urls) {
+ if(urls.length != 1) {
+ return;
+ }
+ var u = urls[0];
+ log('Adding feed: ' + u);
+ url.parse(u); // TODO: Add error handling
+ parseFeed(u, function(err, feed) {
+ if(err) {
+ log('Unable to fetch feed');
+ log(util.format(err));
+ return;
+ }
+ config.feeds.push(u);
+ appendFeed(u);
+ saveConfig(function(err) {
+ if(err) throw err;
+ irc.notice(channel, 'Feed added');
+ });
+ });
+}
+
+function onRemoveFeed(channel, args) {
+ if(args.length != 1) {
+ return;
+ }
+ log("onRemoveFeed: args[0]=" + args[0]);
+ var i = parseInt(args[0]);
+ log("onRemoveFeed: i=" + i);
+ var feedUrl = config.feeds[i];
+ log("onRemoveFeed: config=" + JSON.stringify(config));
+ config.feeds.splice(i, 1);
+ log("onRemoveFeed: config=" + JSON.stringify(config));
+ log("onRemoveFeed: feedUrl=" + feedUrl);
+ removeFeed(feedUrl);
+ saveConfig(function(err) {
+ if(err) {
+ log(err);
+ irc.notice(channel, 'Error removing feed');
+ return;
+ }
+ irc.notice(channel, 'Feed removed');
+ });
+}
+
+function onLoadConfig(channel) {
+ loadConfig(function(err, config) {
+ if(err) {
+ irc.notice(channel, 'Unable to load config');
+ }
+ else {
+ irc.notice(channel, 'Loaded configuration, has ' + config.feeds.length + ' feeds.');
+ }
+ });
+}
+
+function loadConfig(cb) {
+ fs.readFile('config.json', function(err, data) {
+ if(err) return cb(err, undefined);
+
+ try {
+ config = JSON.parse(data);
+ } catch(e) {
+ log('Unable to parse config.json, using defaults.');
+ }
+
+ config.channel = _.isString(config.channel) ? config.channel : '#dynobot';
+ config.feeds = _.isArray(config.feeds) ? config.feeds : [];
+ cb(undefined, config);
+ });
+}
+
+function saveConfig(cb) {
+ log('Saving config: ' + JSON.stringify(config));
+ fs.writeFile('config.json', JSON.stringify(config), cb);
+}
+
setup();
diff --git a/dynobot-irc.js b/dynobot-irc.js
index 9cae258..a942883 100644
--- a/dynobot-irc.js
+++ b/dynobot-irc.js
@@ -1,14 +1,15 @@
require('tinycolor');
var Channel = require('dynobot/channel.js');
-var cmdopt = require('cmdopt')
-var cp = require('child_process');
var EventEmitter = require('events').EventEmitter;
var FakeSocket = require('./FakeSocket.js');
var IrcClient = require('./irc-client').IrcClient;
-var os = require('os')
-var _ = require('underscore');
var Service = require('dynobot/service.js');
+var _ = require('underscore');
+var cmdopt = require('cmdopt')
+var cp = require('child_process');
+var os = require('os')
var util = require('util');
+var watchTree = require("fs-watch-tree").watchTree;
var parser = new cmdopt.Parser();
parser.option("-h, --help", "Show this help");
@@ -82,35 +83,53 @@ var ircService = new Service('irc', irc);
irc.setDebugLevel(3);
-function Plugin(name, script) {
- this.name = name;
- this.script = script;
+function Plugin(dir, config) {
+ this.dir = dir;
+ this.config = config;
this.channel = undefined;
+// this.watch = undefined;
+
+ // TODO: Resolve plugin.script. Dir is relative to the plugin's
+ // installation directory.
+ this.script = 'index.js';
}
-var plugins = [
-// new Plugin('echo', './echo-bot/index.js')
- new Plugin('atom', './atom-bot/index.js')
-];
+Plugin.prototype.start = function(name) {
+ info('Starting ' + name);
-_.each(plugins, function(plugin) {
- info('Starting ' + plugin.name);
- // TODO: Resolve plugin.script
// TODO: set cwd option to the plugin's directory.
var args = [];
var options = {
- silent: true
+ silent: true,
+ cwd: this.dir
};
- var child = cp.fork(plugin.script, args, options);
+ var child = cp.fork(this.script, args, options);
var channel = new Channel(child);
ircService.handle(channel);
child.on('exit', function() {
- info(plugin.name + ' exited..');
+ info(name + ' exited..');
ircService.release(channel);
channel.close();
});
// TODO: set up consumers for child.stdout and color it before
// piping to process.stdout
+
+// this.watch = watchTree(this.dir);
+ info(name + ' started..');
+}
+
+Plugin.prototype.stop = function(name) {
+ log("Stooping pulugin " + name);
+// this.watch && this.watch.end();
+}
+
+var plugins = {
+// new Plugin('echo', './echo-bot')
+ atom: new Plugin('./atom-bot')
+};
+
+_.each(plugins, function(plugin, name) {
+ plugin.start(name);
});
irc.join(config.channel, function(name) {
diff --git a/irc-client.js b/irc-client.js
index 1be71bf..c94d8e5 100644
--- a/irc-client.js
+++ b/irc-client.js
@@ -136,5 +136,6 @@ function dispatch(name) {
IrcClient.prototype.notice = function() { this.irc.notice.apply(this.irc, arguments); }
IrcClient.prototype.privmsg = function() { this.irc.privmsg.apply(this.irc, arguments); }
IrcClient.prototype.topic = function() { this.irc.topic.apply(this.irc, arguments); }
+IrcClient.prototype.whoami = function(cb) { cb(this.irc.whoami()); }
module.exports.IrcClient = IrcClient;
diff --git a/package.json b/package.json
index 4a8d8fc..0cfef1c 100644
--- a/package.json
+++ b/package.json
@@ -21,11 +21,12 @@
"cron": "~0.3.2",
"date": "1.0.2",
"dynobot": "https://github.com/einaros/dynobot/tarball/master",
+ "fs-watch-tree": "~0.2.0"
"getit": "~0.1.7",
- "mocha": "~1.0.3",
"irc.js": "0.1.0",
+ "mocha": "~1.0.3",
"tinycolor": "0.0.1",
- "underscore": "1.3.3"
+ "underscore": "1.3.3",
},
"devDependencies": {},
"optionalDependencies": {},