Plugin architecture example
authorDarren <darren@darrenwhitlen.com>
Sat, 30 Jul 2011 17:07:09 +0000 (18:07 +0100)
committerDarren <darren@darrenwhitlen.com>
Sat, 30 Jul 2011 17:07:09 +0000 (18:07 +0100)
node/config.json
node/kiwi.js
node/kiwi_modules/spamfilter.js [new file with mode: 0644]
node/kiwi_modules/statistics.js [new file with mode: 0644]
node/lib/kiwi_mod.js [new file with mode: 0644]

index e16f948476dc52427f41bf605f724636d2ce08cb..d23345d11235308c8729d8ba55a0df60b7382b82 100644 (file)
@@ -13,5 +13,8 @@
     "cap_options":      [],
 
     "handle_http":      true,
-    "public_http":         "./../"
+    "public_http":         "./../",
+
+    "module_dir":       "./kiwi_modules/",
+    "modules":          ["spamfilter", "statistics"]
 }
index ae4d23158064c9d8284b21b11c80c24d07c854a9..fc7eabee4beef6786704a6d24063a08cf72fd046 100644 (file)
@@ -8,7 +8,12 @@ var tls = require('tls'),
     url = require('url'),
     ws = require('socket.io'),
     _ = require('./lib/underscore.min.js'),
-    starttls = require('./lib/starttls.js');
+    starttls = require('./lib/starttls.js'),
+    kiwi_mod = require('./lib/kiwi_mod.js');
+
+    // Libraries may need to know kiwi.js path as __dirname
+    // only gives that librarys path. Set it here for usage later.
+    kiwi_root = __dirname;
 
 
 /*
@@ -16,7 +21,7 @@ var tls = require('tls'),
  * - /etc/kiwi/config.json
  * - ./config.json
  */
-var config = null, config_filename = 'config.json';
+config = null, config_filename = 'config.json';
 var config_dirs = ['/etc/kiwiirc/', __dirname + '/'];
 for(var i in config_dirs){
     try {
@@ -37,6 +42,14 @@ if(config === null){
 
 
 
+/*
+ * Load the modules as set in the config and print them out
+ */
+kiwi_mod.loadModules();
+kiwi_mod.printMods();
+
+
+
 
 /*
  * Some process changes
@@ -276,7 +289,9 @@ var parseIRCMessage = function (websocket, ircSocket, data) {
                     websocket.emit('message', {event: 'ctcp_request', nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing.substr(1, msg.trailing.length - 2)});
                 }
             } else {
-                websocket.emit('message', {event: 'msg', nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing});
+                var obj = {event: 'msg', nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing};
+                obj = kiwi_mod.run('msg', obj);
+                if(obj !== null) websocket.emit('message', obj);
             }
             break;
         case 'CAP':
@@ -508,7 +523,8 @@ io.of('/kiwi').on('connection', function (websocket) {
             switch (msg.data.method) {
             case 'msg':
                 if ((args.target) && (args.msg)) {
-                    websocket.ircSocket.write('PRIVMSG ' + args.target + ' :' + args.msg + '\r\n');
+                    var obj = kiwi_mod.run('msgsend', args, {websocket: websocket});
+                    if (obj !== null) websocket.ircSocket.write('PRIVMSG ' + args.target + ' :' + args.msg + '\r\n');
                 }
                 break;
                case 'action':
diff --git a/node/kiwi_modules/spamfilter.js b/node/kiwi_modules/spamfilter.js
new file mode 100644 (file)
index 0000000..140ee49
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Example Kiwi module.
+ * This is by no means is a production ready module.
+ */
+
+var filters;
+var compiled_regex;
+
+exports.onload = function(){
+       filters = ['sad', 'kill', 'death'];
+       compiled_regex = new RegExp(filters.join('|'), 'im');
+}
+
+
+exports.onmsg = function(msg){
+       if (msg.msg.search(compiled_regex) > -1) {
+               return null;
+       }
+
+       return msg;
+}
\ No newline at end of file
diff --git a/node/kiwi_modules/statistics.js b/node/kiwi_modules/statistics.js
new file mode 100644 (file)
index 0000000..1875a43
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Example Kiwi module.
+ * This is by no means is a production ready module.
+ */
+
+var stats = {msgs: 0, topic_changes: 0};
+
+exports.onmsgsend = function(msg, opts){
+       stats.msgs++;
+
+       if(msg.msg === '!kiwistats'){
+               msg.msg = 'Messages sent: ' + stats.msgs.toString();
+               opts.websocket.emit('message', {event: 'msg', nick: msg.target, ident: '', hostname: '', channel: msg.target, msg: msg.msg});
+               return null;
+       }
+
+       return msg;
+}
+
+exports.ontopic = function(topic){
+       stats.topic_changes++;
+
+       return topic;
+}
\ No newline at end of file
diff --git a/node/lib/kiwi_mod.js b/node/lib/kiwi_mod.js
new file mode 100644 (file)
index 0000000..0df9815
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Kiwi module handler
+ *
+ * To run module events:
+ *     kiwi_mod.run(event_name, obj);
+ *
+ * - Each module call must return obj, with or without changes.
+ * - If a module call returns null, the event is considered cancelled
+ *   and null is passed back to the caller to take action.
+ *   For example, if null is returned for onmsg, kiwi stops sending
+ *   the message to any clients.
+*/
+
+this.loaded_modules = {};
+
+
+exports.loadModules = function(){
+       // Warn each module it is about to be unloaded
+       this.run('unload');
+       this.loaded_modules = {};
+
+       // Load each module and run the onload event
+       for(var i in config.modules){
+               var mod_name = config.modules[i];
+               this.loaded_modules[mod_name] = require(kiwi_root + '/' + config.module_dir + mod_name);
+       }
+       this.run('load');
+}
+
+exports.run = function (event, obj, opts){
+       var ret = obj;
+
+       for (var mod_name in this.loaded_modules) {
+               if (typeof this.loaded_modules[mod_name]['on' + event] === 'function') {
+                       ret = this.loaded_modules[mod_name]['on' + event](ret, opts);
+                       if (ret === null) return null;
+               }
+       }
+
+       return ret;
+}
+
+exports.printMods = function(){
+       console.log('Loaded Kiwi modules');
+       for (var mod_name in this.loaded_modules) {
+               console.log(' - ' + mod_name);
+       }
+}
\ No newline at end of file