Permalink
Browse files

[api] Working channels synchronization.

  • Loading branch information...
1 parent 0a41187 commit 3d2cc1c1080aaa44cfae3f50344dbaac63ab2190 @jfhbrook jfhbrook committed Jun 27, 2012
Showing with 366 additions and 33 deletions.
  1. +2 −5 bin/kohai
  2. +67 −0 lib/core/channels.js
  3. +15 −0 lib/core/hook.js
  4. +11 −0 lib/core/index.js
  5. +68 −0 lib/core/irc-hook.js
  6. +97 −0 lib/core/irc/channel.js
  7. +92 −0 lib/core/router.js
  8. +5 −18 lib/kohai.js
  9. +9 −10 package.json
View
@@ -5,14 +5,11 @@ var kohai = require('../lib/kohai'),
utile = require('utile'),
port = kohai.config.get('http-port') || 9000;
-kohai.start(port, function (err) {
+kohai.start(function (err) {
if (err) {
kohai.log.error('there was an error.');
- kohai.log.error('err.stack');
+ console.log(err);
}
- var address = kohai.server.address();
-
- kohai.log.info(utile.format('http server chilling on %s:%d', address.address, address.port));
});
View
@@ -0,0 +1,67 @@
+var util = require('utile');
+ Channel = require('./irc/channel').Channel;
+
+exports.name = 'irc-channels';
+
+exports.attach = function () {
+
+ var self = this,
+ irc = this.irc,
+ channels = {};
+
+ irc.on('self::joined', join);
+ irc.on('self::parted', part);
+
+ this.channels = {
+ join: join,
+ part: part,
+ synchronize: synchronize
+ };
+
+ function join(data) {
+ if (!channels[data.channel]) {
+ channels[data.channel] = new Channel(data);
+ }
+ channels[data.channel].join();
+ }
+
+ function part(data) {
+ channels[data.channel].part();
+ }
+
+ function synchronize(cb) {
+ irc.channels(function (err, reply) {
+ if (err) {
+ return cb(err);
+ }
+
+ var chans = reply.channels;
+
+ Object.keys(chans).forEach(function (chan) {
+ chans[chan].channel = chan;
+ join(chans[chan]);
+ });
+ cb();
+ });
+ };
+
+ this.hook.on('**::irc::connected', function (data) {
+ if (data.type == 'irc') {
+ self.channels.synchronize(function (err) {
+ if (err) {
+ self.emit('error', err);
+ }
+ });
+ }
+ });
+
+};
+
+exports.init = function (done) {
+ var self = this,
+ hook = this.hook;
+
+ hook.on('hook::ready', function () {
+ self.channels.synchronize(done);
+ });
+};
View
@@ -0,0 +1,15 @@
+// Flatiron plugin that adds a vanilla hook.
+exports.name = 'hook.io';
+
+var Hook = require('hook.io').Hook;
+
+exports.attach = function attachHook (options) {
+ this.hook = new Hook(options);
+};
+
+exports.init = function initHook (done) {
+ this.hook.on('hook::ready', function (data) {
+ done(null);
+ });
+ this.hook.start();
+};
View
@@ -0,0 +1,11 @@
+exports.name = 'kohai-base';
+
+var hook = require('./hook'),
+ irc = require('./irc-hook'),
+ channels = require('./channels');
+
+exports.attach = function (opts) {
+ this.use(hook, {});
+ this.use(irc, {});
+ this.use(channels, {});
+}
View
@@ -0,0 +1,68 @@
+exports.name = 'irc-hooks';
+
+var util = require('utile'),
+ EventEmitter2 = require('eventemitter2').EventEmitter2;
+
+// Core irc management functionality. Basically unpacks the api.
+var IRC = exports.IRC = function (hook) {
+ EventEmitter2.call(this, {
+ wildcard: true,
+ delimiter: '::'
+ });
+
+ this.hook = hook;
+
+ this.hook.on('**::irc::joined', function (data) {
+ if (data.nick) {
+ this.emit('joined', data);
+ }
+ else {
+ this.emit('self::joined', data);
+ }
+ });
+
+ this.hook.on('**::irc::parted', function (data) {
+ if (data.nick) {
+ this.emit('parted', data);
+ }
+ else {
+ this.emit('self::parted', data);
+ }
+ });
+};
+util.inherits(IRC, EventEmitter2);
+
+IRC.prototype.join = function (channel) {
+ this.hook.emit('irc::join', channel);
+};
+
+IRC.prototype.part = function (channel) {
+ this.hook.emit('irc::part', channel);
+};
+
+IRC.prototype.say = function (to, msg) {
+ this.hook.emit('irc::say', {
+ to: to,
+ msg: msg
+ });
+};
+
+IRC.prototype.channels = function (cb) {
+ try {
+ this.hook.emit('irc::channels', {}, function (channels) {
+ cb(null, channels);
+ });
+ }
+ catch (err) {
+ cb(err);
+ }
+};
+
+// broadway attachments
+exports.attach = function (options) {
+ this.irc = new IRC(this.hook);
+};
+
+exports.init = function (done) {
+ done();
+};
View
@@ -0,0 +1,97 @@
+/*
+ *
+ * channel.js - an object to hold various channel data
+ *
+ * (c) 2011 Nodejitsu Inc.
+ *
+ */
+
+var Channel = exports.Channel = function (options) {
+ for (var o in options) {
+ this[o] = options[o];
+ }
+};
+
+Channel.prototype.part = function () {
+ this.active = false;
+};
+
+Channel.prototype.join = function () {
+ this.active = true;
+};
+
+Channel.prototype.startVolume = function () {
+ this._ircRate();
+ this._twitRate();
+};
+
+Channel.prototype.stopVolume = function () {
+ clearInterval(this.ircInterval);
+ clearInterval(this.twitInterval);
+};
+
+Channel.prototype.config = function (key, value) {
+ if (typeof value === 'undefined') {
+ return this[key];
+ }
+ if (typeof key === 'string') {
+ this[key] = value;
+ return key + ' has been set to ' + value;
+ }
+ else {
+ return false;
+ }
+};
+
+Channel.prototype._ircRate = function () {
+ var self = this,
+ timespan = 60;
+ self.rateValues = [];
+ self.ircInterval = setInterval(function () {
+ var sum = 0;
+ if (self.rateValues.length > timespan) {
+ self.rateValues.shift();
+ }
+
+ self.rateValues.push(self.messageCount);
+ self.messageCount = 0;
+
+ self.rateValues.forEach(function (value) {
+ sum += Number(value);
+ });
+ self.rate = sum;
+ self._volumetrics();
+ }, 1000);
+
+};
+
+Channel.prototype._volumetrics = function () {
+ var self = this;
+
+ if (self.autoVolume) {
+ if (self.rate > 10) {
+ self.rate = 10;
+ }
+ if ((self.volume < 0) || (typeof self.volume === 'undefined')) {
+ self.volume = 0;
+ }
+ if ((10 - self.rate) <= self.volume) {
+ self.volume = 10 - self.rate;
+ self.lastVolume = self.volume;
+ }
+ else if ((10 - self.rate) > self.volume) {
+ self.lastVolume += self.lastVolume +0.05;
+ self.volume = Math.round(self.lastVolume);
+ }
+ }
+};
+
+Channel.prototype._twitRate = function () {
+ var self = this;
+
+ self.twitInterval = setInterval(function () {
+ if (self.currentTweetCount > 0) {
+ self.currentTweetCount--;
+ }
+ }, self.twitPeriod * 1000);
+};
View
@@ -0,0 +1,92 @@
+/*
+ *
+ * router.js - This should contain a director router or similar for handling
+ * "triggers."
+ *
+ * (c) 2012 Nodejitsu Inc.
+ *
+ */
+
+// Mostly copy-pasted from the cli router from director core.
+var utile = require('utile'),
+ director = require('director');
+
+var Router = exports.Router = function (routes) {
+ director.Router.call(this, routes);
+ this.recurse = 'backward';
+};
+
+//
+// Inherit from `director.Router`.
+//
+utile.inherits(Router, director.Router);
+
+//
+// ### function configure (options)
+// #### @options {Object} **Optional** Options to configure this instance with
+// Configures this instance with the specified `options`.
+//
+Router.prototype.configure = function (options) {
+ options = options || {};
+ director.Router.prototype.configure.call(this, options);
+
+ //
+ // Our delimiter here is a space.
+ // e.g. `!foo bar baz`
+ //
+ this.delimiter = ' ';
+
+ // This way, you can use a custom trigger symbol.
+ // e.g. `@foo bar baz`
+ this.trigger = options.trigger || '!';
+
+ return this;
+};
+
+//
+// ### function dispatch (method, path)
+// #### @method {string} Method to dispatch
+// #### @path {string} Path to dispatch
+// Finds a set of functions on the traversal towards
+// `method` and `path` in the core routing table then
+// invokes them based on settings in this instance.
+//
+Router.prototype.dispatch = function (method, data, app, callback) {
+
+ var path = data.text,
+ trig = new RegExp('^' + this.trigger);
+
+ //
+ // Replace the trigger with a space so that the traversal
+ // algorithm will recognize it. This is because we always assume
+ // that the `path` begins with `this.delimiter`.
+ //
+ path = (path || '').replace(trig, this.delimiter);
+
+ var fns = this.traverse(method, path, this.routes, '');
+
+ if (!fns || fns.length === 0) {
+
+ if (callback) {
+
+ callback(new Error(
+ utile.format('IRC command router could not find cmd for: "%s"', path)
+ ));
+ }
+
+ return false;
+ }
+
+ if (this.recurse === 'forward') {
+ fns = fns.reverse();
+ }
+
+ // Second arg is set to "this" in the route handler.
+ // Needs some helper fxns
+ this.invoke(this.runlist(fns), {
+ cmd: path.substring(1),
+ data: data,
+ app: app
+ }, callback);
+ return true;
+};
Oops, something went wrong.

0 comments on commit 3d2cc1c

Please sign in to comment.