Standardised server control interface
authorDarren <darren@darrenwhitlen.com>
Sat, 17 Aug 2013 18:55:28 +0000 (19:55 +0100)
committerDarren <darren@darrenwhitlen.com>
Sat, 17 Aug 2013 18:55:28 +0000 (19:55 +0100)
server/controlinterface.js [new file with mode: 0644]
server/kiwi.js
server_modules/control.js

diff --git a/server/controlinterface.js b/server/controlinterface.js
new file mode 100644 (file)
index 0000000..2d0a88a
--- /dev/null
@@ -0,0 +1,157 @@
+var _           = require('lodash'),
+    rehash      = require('./rehash.js'),
+    config      = require('../server/configuration.js'),
+    kiwiModules = require('../server/modules');
+
+
+
+var ControlInterface = module.exports = function(stream_in, stream_out, opts) {
+    stream_out = stream_out || stream_in;
+    this.stream_out = stream_out;
+    this.stream_in = stream_in;
+
+    opts = opts || {};
+    this.prompt = (typeof opts.prompt === 'string') ?
+        opts.prompt :
+        'Kiwi > ';
+
+    this._custom_commands = {};
+
+    this._onData = this.onData.bind(this);
+    stream_in.on('data', this._onData);
+
+    this.displayPrompt();
+};
+
+
+
+ControlInterface.prototype.dispose = function() {
+    this.stream_in.removeListener('data', this._onData);
+    this.stream_in = null;
+    this.stream_out = null;
+};
+
+
+
+ControlInterface.prototype.write = function(data, append) {
+    if (typeof append === 'undefined') append = '\n';
+    try {
+        this.stream_out.write(data + append);
+    } catch(err){}
+};
+
+
+
+ControlInterface.prototype.displayPrompt = function(prompt) {
+    prompt = prompt || this.prompt;
+    this.write(prompt, '');
+};
+
+
+
+ControlInterface.prototype.onData = function(buffered) {
+    var data = buffered.toString().trim(),
+        data_parts = data.split(' '),
+        cmd = data_parts[0] || null;
+
+    if (typeof this._custom_commands[cmd] === 'function') {
+        this._custom_commands[cmd].call(this, data_parts.slice(1), data);
+
+    } else if (typeof commands[cmd] === 'function') {
+        commands[cmd].call(this, data_parts.slice(1), data);
+
+    } else {
+        this.write('Unrecognised command: ' + cmd);
+    }
+
+    this.displayPrompt();
+};
+
+
+
+ControlInterface.prototype.addCommand = function(command, fn) {
+    this._custom_commands[command] = fn;
+};
+
+
+
+var commands = {};
+commands.stats = function(args, raw) {
+    this.write('Connected clients: ' + _.size(global.clients.clients).toString());
+    this.write('Num. remote hosts: ' + _.size(global.clients.addresses).toString());
+};
+
+
+commands.reconfig = function(args, raw) {
+    if (config.loadConfig()) {
+        console.log('New config file loaded');
+    } else {
+        console.log("No new config file was loaded");
+    }
+};
+
+
+commands.rehash = function(args, raw) {
+    rehash.rehashAll();
+    console.log('Rehashed');
+};
+
+
+commands.jumpserver = function(args, raw) {
+    var num_clients = _.size(global.clients.clients),
+        packet = {}, args_idx;
+
+    if (num_clients === 0) {
+        console.log('No connected clients');
+        return;
+    }
+
+    // For each word in the line minus the last, add it to the packet
+    for(args_idx=0; args_idx<args.length-1; args_idx++){
+        packet[args[args_idx]] = true;
+    }
+
+    packet.kiwi_server = args[args_idx];
+
+    console.log('Broadcasting jumpserver to ' + num_clients.toString() + ' clients..');
+    global.clients.broadcastKiwiCommand('jumpserver', packet, function() {
+        console.log('Broadcast complete.');
+    });
+};
+
+
+commands.module = function(args, raw) {
+    switch(args[0]) {
+        case 'reload':
+            if (!args[1]) {
+                this.write('A module name must be specified');
+                return;
+            }
+
+            if (!kiwiModules.unload(args[1])) {
+                this.write('Module ' + (args[1] || '') + ' is not loaded');
+                return;
+            }
+
+            if (!kiwiModules.load(args[1])) {
+                this.write('Error loading module ' + (args[1] || ''));
+            }
+            this.write('Module ' + args[1] + ' reloaded');
+
+            break;
+
+        case 'list':
+        case 'ls':
+        default:
+            var module_names = [];
+            kiwiModules.getRegisteredModules().forEach(function(module) {
+                module_names.push(module.module_name);
+            });
+            this.write('Loaded modules: ' + module_names.join(', '));
+    }
+};
+
+
+commands.hello = function(args, raw) {
+    this.write('Hello, beautiful :)');
+};
index baf8124f0e7f9063d753dbf104c110e85ba46a74..0255e1a62290864ba40192315b7ea9f8e763c4c8 100755 (executable)
@@ -3,9 +3,9 @@ var fs          = require('fs'),
     util        = require('util'),
     WebListener = require('./weblistener.js'),
     config      = require('./configuration.js'),
-    rehash      = require('./rehash.js'),
     modules     = require('./modules.js'),
-    Identd      = require('./identd.js');
+    Identd      = require('./identd.js'),
+    ControlInterface = require('./controlinterface.js');
 
 
 
@@ -306,63 +306,5 @@ process.on('SIGUSR2', function() {
 /*
  * Listen for runtime commands
  */
-
 process.stdin.resume();
-process.stdin.on('data', function (buffered) {
-    var data = buffered.toString().trim(),
-        data_parts = data.split(' '),
-        cmd = data_parts[0] || null;
-
-    switch (cmd) {
-        case 'stats':
-            console.log('Connected clients: ' + _.size(global.clients.clients).toString());
-            console.log('Num. remote hosts: ' + _.size(global.clients.addresses).toString());
-            break;
-
-        case 'reconfig':
-            if (config.loadConfig()) {
-                console.log('New config file loaded');
-            } else {
-                console.log("No new config file was loaded");
-            }
-
-            break;
-
-
-        case 'rehash':
-            (function () {
-                rehash.rehashAll();
-                console.log('Rehashed');
-            })();
-
-            break;
-
-        case 'jumpserver':
-            (function() {
-                var num_clients = _.size(global.clients.clients),
-                    packet = {}, parts_idx;
-
-                if (num_clients === 0) {
-                    console.log('No connected clients');
-                    return;
-                }
-
-                // For each word in the line minus the last, add it to the packet
-                for(parts_idx=1; parts_idx<data_parts.length-1; parts_idx++){
-                    packet[data_parts[parts_idx]] = true;
-                }
-
-                packet.kiwi_server = data_parts[parts_idx];
-
-                console.log('Broadcasting jumpserver to ' + num_clients.toString() + ' clients..');
-                global.clients.broadcastKiwiCommand('jumpserver', packet, function() {
-                    console.log('Broadcast complete.');
-                });
-            })();
-
-            break;
-
-        default:
-            console.log('Unrecognised command: ' + data);
-    }
-});
+new ControlInterface(process.stdin, process.stdout, {prompt: ''});
index bbe42544fab54d8f9df8766ebf5aaf3d11e3d13f..83e562f4d2b1bd0e9fd6e5e76f7f0f24c0a744c5 100644 (file)
@@ -4,11 +4,10 @@
  * Listens on localhost:8888 by default\r
  */\r
 \r
-var net         = require('net'),\r
-    kiwiModules = require('../server/modules'),\r
-    rehash      = require('../server/rehash.js'),\r
-    config      = require('../server/configuration.js'),\r
-    _           = require('lodash');\r
+var net                = require('net'),\r
+    kiwiModules        = require('../server/modules'),\r
+    ControlInterface   = require('../server/controlinterface.js'),\r
+    _                  = require('lodash');\r
 \r
 var control_module = new kiwiModules.Module('Control');\r
 \r
@@ -17,6 +16,8 @@ var control_module = new kiwiModules.Module('Control');
  * The socket client\r
  */\r
 function SocketClient (socket) {\r
+    var that = this;\r
+\r
     this.socket = socket;\r
     this.socket_closing = false;\r
 \r
@@ -26,59 +27,33 @@ function SocketClient (socket) {
     this.bindEvents();\r
 \r
     socket.write("\nHello, you are connected to the Kiwi server :)\n\n");\r
-    this.displayPrompt();\r
+\r
+    this.control_interface = new ControlInterface(socket);\r
+    _.each(socket_commands, function(fn, command_name) {\r
+        console.log('adding command', command_name);\r
+        that.control_interface.addCommand(command_name, fn.bind(that));\r
+    });\r
 }\r
 \r
 SocketClient.prototype.bindEvents = function() {\r
     var that = this;\r
 \r
-    this.socket.on('data', function() { that.onData.apply(that, arguments); });\r
     this.socket.on('close', function() { that.onClose.apply(that, arguments); });\r
 };\r
-SocketClient.prototype.unbindEvents = function() {\r
-    this.socket.removeAllListeners();\r
-};\r
-\r
-\r
-\r
-SocketClient.prototype.write = function(data, append) {\r
-    if (typeof append === 'undefined') append = '\n';\r
-    if (this.socket && !this.socket_closing)\r
-        this.socket.write(data + append);\r
-};\r
-SocketClient.prototype.displayPrompt = function(prompt) {\r
-    prompt = prompt || 'Kiwi > ';\r
-    this.write(prompt, '');\r
-};\r
-\r
-\r
-\r
-SocketClient.prototype.onData = function(data) {\r
-    data = data.toString().trim();\r
-\r
-\r
 \r
-    try {\r
-        var data_split = data.split(' ');\r
 \r
-        if (typeof socket_commands[data_split[0]] === 'function') {\r
-            socket_commands[data_split[0]].call(this, data_split.slice(1));\r
-        } else {\r
-            this.write('Unrecognised command: ' + data);\r
-        }\r
-\r
-    } catch (err) {\r
-        console.log('[Control error] ' + err);\r
-        this.write('An error occured. Check the Kiwi server log for more details');\r
-    }\r
-\r
-    this.displayPrompt();\r
+SocketClient.prototype.unbindEvents = function() {\r
+    this.socket.removeAllListeners();\r
 };\r
 \r
 \r
 SocketClient.prototype.onClose = function() {\r
+    this.control_interface.dispose();\r
+    this.control_interface = null;\r
+\r
     this.unbindEvents();\r
     this.socket = null;\r
+\r
     console.log('Control connection from ' + this.remoteAddress + ' closed');\r
 };\r
 \r
@@ -89,56 +64,6 @@ SocketClient.prototype.onClose = function() {
  * Each function is run in context of the SocketClient\r
  */\r
 var socket_commands = {\r
-    module: function(data) {\r
-        switch(data[0]) {\r
-            case 'reload':\r
-                if (!data[1]) {\r
-                    this.write('A module name must be specified');\r
-                    return;\r
-                }\r
-\r
-                if (!kiwiModules.unload(data[1])) {\r
-                    this.write('Module ' + (data[1] || '') + ' is not loaded');\r
-                    return;\r
-                }\r
-\r
-                if (!kiwiModules.load(data[1])) {\r
-                    this.write('Error loading module ' + (data[1] || ''));\r
-                }\r
-                this.write('Module ' + data[1] + ' reloaded');\r
-\r
-                break;\r
-\r
-            case 'list':\r
-            case 'ls':\r
-            default:\r
-                var module_names = [];\r
-                kiwiModules.getRegisteredModules().forEach(function(module) {\r
-                    module_names.push(module.module_name);\r
-                });\r
-                this.write('Loaded modules: ' + module_names.join(', '));\r
-        }\r
-\r
-    },\r
-\r
-    stats: function(data) {\r
-        this.write('Connected clients: ' + _.size(global.clients.clients).toString());\r
-        this.write('Num. remote hosts: ' + _.size(global.clients.addresses).toString());\r
-    },\r
-\r
-    rehash: function(data) {\r
-        rehash.rehashAll();\r
-        this.write('Rehashed');\r
-    },\r
-\r
-    reconfig: function(data) {\r
-        if (config.loadConfig()) {\r
-            this.write('New config file loaded');\r
-        } else {\r
-            this.write("No new config file was loaded");\r
-        }\r
-    },\r
-\r
     quit: function(data) {\r
         this.socket.destroy();\r
         this.socket_closing = true;\r