+ Concept of PluginModule and inherited classes such as ServerModule, MenuModule, ...

* Client now tracks current menu module. Auto detach events, etc.
This commit is contained in:
Bryan Ashby 2015-03-18 23:08:23 -06:00
parent d3e35d286a
commit f7462bbbdd
11 changed files with 226 additions and 60 deletions

View File

@ -3,7 +3,7 @@
// ENiGMA½
var conf = require('./config.js');
var modules = require('./modules.js');
var moduleUtil = require('./module_util.js');
var logger = require('./logger.js');
var miscUtil = require('./misc_util.js');
var database = require('./database.js');
@ -117,7 +117,7 @@ function startListening() {
return [];
}
modules.loadModulesForCategory('servers', function onServerModule(err, module) {
moduleUtil.loadModulesForCategory('servers', function onServerModule(err, module) {
if(err) {
logger.log.info(err);
return;
@ -129,7 +129,8 @@ function startListening() {
return;
}
var server = module.createServer();
var moduleInst = new module.getModule();
var server = moduleInst.createServer();
// :TODO: handle maxConnections, e.g. conf.maxConnections

View File

@ -2,12 +2,15 @@
'use strict';
var stream = require('stream');
var term = require('./client_term.js');
var assert = require('assert');
var term = require('./client_term.js');
var miscUtil = require('./misc_util.js');
var ansi = require('./ansi_term.js');
var logger = require('./logger.js');
var logger = require('./logger.js'); // :TODO: cleanup and just use Log.
var Log = require('./logger.js').log;
var user = require('./user.js');
var moduleUtil = require('./module_util.js');
exports.Client = Client;
@ -183,6 +186,33 @@ Client.prototype.address = function() {
return this.input.address();
};
Client.prototype.gotoMenuModule = function(name, cb) {
var self = this;
// Assign a default missing module handler callback if none was provided
cb = miscUtil.valueWithDefault(cb, self.defaultHandlerMissingMod());
if(self.currentMenuModule) {
self.currentMenuModule.leave();
}
moduleUtil.loadModule(name, 'mods', function onModuleLoaded(err, mod) {
if(err) {
cb(err);
} else {
try {
Log.debug({ moduleName : name }, 'Goto menu module');
var modInst = new mod.getModule();
modInst.enter(self);
self.currentMenuModule = modInst;
} catch(e) {
cb(e);
}
}
});
};
///////////////////////////////////////////////////////////////////////////////
// Default error handlers
///////////////////////////////////////////////////////////////////////////////

View File

@ -43,7 +43,7 @@ module.exports = {
},
ssh : {
port : 8889,
enabled : true,
enabled : false,
rsaPrivateKey : paths.join(__dirname, './../misc/default_key.rsa'),
dsaPrivateKey : paths.join(__dirname, './../misc/default_key.dsa'),
}

View File

@ -3,7 +3,7 @@
var ansi = require('./ansi_term.js');
var artwork = require('./art.js');
var modules = require('./modules.js');
var moduleUtil = require('./module_util.js');
var Log = require('./logger.js').log;
var Config = require('./config.js').config;
var packageJson = require('../package.json');
@ -84,7 +84,8 @@ function connectEntry(client) {
setTimeout(function onTimeout() {
term.write(ansi.clearScreen());
modules.goto(Config.entryMod, client);
client.gotoMenuModule(Config.entryMod);
//moduleUtil.goto(Config.entryMod, client);
}, timeout);
});
}, 500);

29
core/menu_module.js Normal file
View File

@ -0,0 +1,29 @@
/* jslint node: true */
'use strict';
var PluginModule = require('./plugin_module.js').PluginModule;
exports.MenuModule = MenuModule;
function MenuModule() {
PluginModule.call(this);
this.viewControllers = [];
}
require('util').inherits(MenuModule, PluginModule);
MenuModule.prototype.enter = function(client) {
};
MenuModule.prototype.leave = function() {
this.viewControllers.forEach(function onVC(vc) {
vc.detachClientEvents();
});
};
MenuModule.prototype.addViewController = function(vc) {
this.viewControllers.push(vc);
return vc; // allow var vc = this.addViewController(new ViewController(...));
};

View File

@ -3,16 +3,14 @@
var fs = require('fs');
var paths = require('path');
var conf = require('./config.js');
var miscUtil = require('./misc_util.js');
var logger = require('./logger.js');
// exports
exports.loadModule = loadModule;
exports.loadModulesForCategory = loadModulesForCategory;
exports.goto = goto;
function loadModule(name, category, cb) {
var config = conf.config;
var path = config.paths[category];
@ -32,12 +30,17 @@ function loadModule(name, category, cb) {
try {
var mod = require(paths.join(path, name + '.js'));
if(!mod.moduleInfo) {
cb(new Error('module is missing \'moduleInfo\' section'));
return;
}
if(!mod.getModule || typeof mod.getModule !== 'function') {
cb(new Error('Invalid or missing missing \'getModule\' method'));
return;
}
mod.runtime = {
config : config
};
@ -46,7 +49,7 @@ function loadModule(name, category, cb) {
} catch(e) {
cb(e);
}
};
}
function loadModulesForCategory(category, cb) {
var path = conf.config.paths[category];
@ -63,23 +66,4 @@ function loadModulesForCategory(category, cb) {
loadModule(paths.basename(file, '.js'), category, cb);
});
});
};
function goto(name, client, cb) {
// Assign a default missing module handler callback if none was provided
cb = miscUtil.valueWithDefault(cb, client.defaultHandlerMissingMod());
loadModule(name, 'mods', function onMod(err, mod) {
if(err) {
cb(err);
} else {
try {
logger.log.debug({ moduleName : name }, 'Goto module');
mod.entryPoint(client);
} catch (e) {
cb(e);
}
}
});
};
}

7
core/plugin_module.js Normal file
View File

@ -0,0 +1,7 @@
/* jslint node: true */
'use strict';
exports.PluginModule = PluginModule;
function PluginModule() {
}

19
core/server_module.js Normal file
View File

@ -0,0 +1,19 @@
/* jslint node: true */
'use strict';
var PluginModule = require('./plugin_module.js').PluginModule;
exports.ServerModule = ServerModule;
function ServerModule() {
PluginModule.call(this);
this.viewControllers = [];
}
require('util').inherits(ServerModule, PluginModule);
ServerModule.prototype.createServer = function() {
console.log('ServerModule createServer')
return null;
};

View File

@ -25,7 +25,7 @@ function SSHClient(input, output) {
this.input.on('authentication', function onAuthentication(ctx) {
console.log('auth: ' + ctx.method);
if('password' == ctx.method) {
if('password' === ctx.method) {
// :TODO: Log attempts
user.authenticate(ctx.username, ctx.password, self, function onAuthResult(isAuth) {
if(isAuth) {
@ -34,9 +34,19 @@ function SSHClient(input, output) {
ctx.reject();
}
});
} else if('publickey' == ctx.method) {
} else if('publickey' === ctx.method) {
console.log('pub key path');
} else if('keyboard-interactive' === ctx.method) {
ctx.reject(['password']);
// :TODO: support this. Allow users to generate a key for use or w/e
/*} else if('keyboard-interactive' === ctx.method) {
console.log(ctx.submethods); // :TODO: proper logging; handle known types, etc.
ctx.prompt([ { prompt : 'Password: ', echo : false } ], function onPromptResponses(err, responses) {
console.log(err);
console.log(responses);
});*/
} else {
ctx.reject();
}
@ -44,10 +54,10 @@ function SSHClient(input, output) {
this.input.on('ready', function onReady() {
console.log('Client authenticated');
});
this.input.on('session', function onSession(accept, reject) {
var session = accept();
self.input.on('session', function onSession(accept, reject) {
});
});
this.input.on('end', function onEnd() {
@ -66,7 +76,8 @@ function createServer() {
};
var server = ssh2.Server(serverConf);
server.on('connection', function onConnection(conn) {
server.on('connection', function onConnection(conn, info) {
console.log(info); // :TODO: Proper logging
var client = new SSHClient(conn, conn);
this.emit('client', client);
});

View File

@ -2,14 +2,16 @@
'use strict';
// ENiGMA½
var baseClient = require('../client.js');
var logger = require('../logger.js');
var baseClient = require('../client.js');
var logger = require('../logger.js');
var ServerModule = require('../server_module.js').ServerModule;
var net = require('net');
var buffers = require('buffers');
var binary = require('binary');
var stream = require('stream');
var assert = require('assert');
var net = require('net');
var buffers = require('buffers');
var binary = require('binary');
var stream = require('stream');
var assert = require('assert');
var util = require('util');
//var debug = require('debug')('telnet');
@ -19,7 +21,8 @@ exports.moduleInfo = {
author : 'NuSkooler'
};
exports.createServer = createServer;
exports.getModule = TelnetServerModule;
//
// Telnet Protocol Resources
@ -469,7 +472,7 @@ function TelnetClient(input, output) {
});
}
require('util').inherits(TelnetClient, baseClient.Client);
util.inherits(TelnetClient, baseClient.Client);
///////////////////////////////////////////////////////////////////////////////
// Telnet Command/Option handling
@ -716,7 +719,7 @@ Object.keys(OPTIONS).forEach(function(name) {
});
});
/*
function createServer() {
var server = net.createServer(function onConnection(sock) {
var self = this;
@ -729,3 +732,27 @@ function createServer() {
return server;
}
*/
function TelnetServerModule() {
console.log('TelnetServerModule')
ServerModule.call(this);
}
util.inherits(TelnetServerModule, ServerModule);
TelnetServerModule.prototype.createServer = function() {
console.log('TelnetServerModule createServer')
TelnetServerModule.super_.prototype.createServer.call(this);
var server = net.createServer(function onConnection(sock) {
var self = this;
var client = new TelnetClient(sock, sock);
client.banner();
self.emit('client', client);
});
return server;
};

View File

@ -1,18 +1,18 @@
/* jslint node: true */
'use strict';
var ansi = require('../core/ansi_term.js');
var art = require('../core/art.js');
var user = require('../core/user.js');
var theme = require('../core/theme.js');
var modules = require('../core/modules.js');
var ansi = require('../core/ansi_term.js');
var art = require('../core/art.js');
var user = require('../core/user.js');
var theme = require('../core/theme.js');
var MenuModule = require('../core/menu_module.js').MenuModule;
//var view = require('../core/view.js');
var textView = require('../core/text_view.js');
//var view = require('../core/view.js');
var textView = require('../core/text_view.js');
var editTextView = require('../core/edit_text_view.js');
var ViewController = require('../core/view_controller.js').ViewController;
var async = require('async');
//var async = require('async');
exports.moduleInfo = {
name : 'Matrix',
@ -20,8 +20,63 @@ exports.moduleInfo = {
author : 'NuSkooler',
};
exports.entryPoint = entryPoint;
//exports.entryPoint = entryPoint;
exports.getModule = MatrixModule;
function MatrixModule() {
MenuModule.call(this);
}
require('util').inherits(MatrixModule, MenuModule);
MatrixModule.prototype.enter = function(client) {
MatrixModule.super_.prototype.enter.call(this);
var self = this;
client.term.write(ansi.resetScreen());
//client.term.write('\x1b[?33h');
theme.displayThemeArt('MATRIX', client, function onMatrix(err, mciMap) {
console.log(mciMap);
if(mciMap.ET1 && mciMap.ET2 && mciMap.BN1 && mciMap.BN2 && mciMap.BN3) {
//
// Form via EditTextViews and ButtonViews
// * ET1 - userName
// * ET2 - password
// * BN1 - Login
// * BN2 - New
// * BN3 - Bye!
//
} else if(mciMap.VM1) {
//
// Menu via VerticalMenuView
//
// * VM1 - menu with the following items:
// 0 - Login
// 1 - New
// 2 - Bye!
//
//var vc = new ViewController(client);
var vc = self.addViewController(new ViewController(client));
vc.on('submit', function onSubmit(form) {
console.log(form);
});
vc.loadFromMCIMap(mciMap);
vc.setViewOrder();
// :TODO: Localize
vc.getView(1).setItems(['Login', 'New User', 'Goodbye!']);
vc.getView(1).submit = true;
vc.switchFocus(1);
}
});
};
/*
function entryPoint(client) {
client.term.write(ansi.resetScreen());
@ -50,17 +105,19 @@ function entryPoint(client) {
var vc = new ViewController(client);
vc.on('submit', function onSubmit(form) {
console.log(form);
});
vc.loadFromMCIMap(mciMap);
vc.setViewOrder();
// :TODO: Localize
vc.getView(1).setItems(['Login', 'New User', 'Goodbye!']);
vc.getView(1).submit = true;
vc.switchFocus(1);
}
});
}
*/
/*
function entryPoint(client) {