From 939e638d9304114f10cafc6fa9e4f80fad2d8d94 Mon Sep 17 00:00:00 2001 From: Darren Date: Sat, 30 Jul 2011 18:07:09 +0100 Subject: [PATCH] Plugin architecture example --- node/config.json | 5 +++- node/kiwi.js | 24 ++++++++++++++--- node/kiwi_modules/spamfilter.js | 21 +++++++++++++++ node/kiwi_modules/statistics.js | 24 +++++++++++++++++ node/lib/kiwi_mod.js | 48 +++++++++++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 node/kiwi_modules/spamfilter.js create mode 100644 node/kiwi_modules/statistics.js create mode 100644 node/lib/kiwi_mod.js diff --git a/node/config.json b/node/config.json index e16f948..d23345d 100644 --- a/node/config.json +++ b/node/config.json @@ -13,5 +13,8 @@ "cap_options": [], "handle_http": true, - "public_http": "./../" + "public_http": "./../", + + "module_dir": "./kiwi_modules/", + "modules": ["spamfilter", "statistics"] } diff --git a/node/kiwi.js b/node/kiwi.js index ae4d231..fc7eabe 100644 --- a/node/kiwi.js +++ b/node/kiwi.js @@ -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 index 0000000..140ee49 --- /dev/null +++ b/node/kiwi_modules/spamfilter.js @@ -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 index 0000000..1875a43 --- /dev/null +++ b/node/kiwi_modules/statistics.js @@ -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 index 0000000..0df9815 --- /dev/null +++ b/node/lib/kiwi_mod.js @@ -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 -- 2.25.1