+ Start work on MenuView & friends

* connect.js no longer a module. Part of initial connection always
* Cleaner & expandable BBS init
* Better theme handling
This commit is contained in:
Bryan Ashby 2014-10-30 22:59:21 -06:00
parent 14a321de2f
commit c3aa4c44e2
8 changed files with 96 additions and 64 deletions

View File

@ -11,6 +11,7 @@ var database = require('./database.js');
var iconv = require('iconv-lite');
var paths = require('path');
var async = require('async');
var util = require('util');
exports.bbsMain = bbsMain;
@ -51,22 +52,15 @@ function bbsMain() {
conf.createDefault();
}
logger.init();
initialize(function onInit(err) {
if(err) {
console.error('Error initializing: ' + util.inspect(err));
return;
}
process.on('SIGINT', function onSigInt() {
// :TODO: for any client in |clientConnections|, if 'ready', send a "Server Disconnecting" + semi-gracefull hangup
// e.g. client.disconnectNow()
logger.log.info('Process interrupted, shutting down');
process.exit();
startListening();
});
database.initializeDatabases();
preServingInit();
startListening();
};
}
function parseArgs() {
var args = [];
@ -91,11 +85,13 @@ function initialize(cb) {
process.exit();
});
iconv.extendNodeEncodings();
callback(null);
},
function initDatabases(callback) {
database.initializeDatabases();
callback(null);
callback(null);
},
function initThemes(callback) {
// Have to pull in here so it's after Config init
@ -112,10 +108,6 @@ function initialize(cb) {
);
}
function preServingInit() {
iconv.extendNodeEncodings();
}
var clientConnections = [];
function startListening() {
@ -151,14 +143,13 @@ function startListening() {
}
addNewClient(client);
//client.runtime.id = clientConnections.push(client) - 1;
//logger.log.info({ clientId : client.runtime.id, from : client.address(), server : module.moduleInfo.name }, 'Client connected');
client.on('ready', function onClientReady() {
// Go to module -- use default error handler
prepareClient(client, function onPrepared() {
modules.goto(conf.config.entryMod, client);
require('./connect.js').connectEntry(client);
});
});
@ -199,6 +190,7 @@ function removeClient(client) {
}
function prepareClient(client, cb) {
// :TODO: it feels like this should go somewhere else... and be a bit more elegant.
if('*' === conf.config.preLoginTheme) {
var theme = require('./theme.js');
theme.getRandomTheme(function onRandTheme(err, themeId) {

View File

@ -7,7 +7,7 @@ var miscUtil = require('./misc_util.js');
module.exports = {
// :TODO: remove this ... anti-pattern!
config : undefined,
//config : undefined,
defaultPath : function() {
var base = miscUtil.resolvePath('~/');
@ -26,7 +26,7 @@ module.exports = {
bbsName : 'Another Fine ENiGMA½ BBS',
// :TODO: probably replace this with 'firstMenu' or somthing once that's available
entryMod : 'connect',
entryMod : 'matrix',
preLoginTheme : '*',

View File

@ -1,21 +1,17 @@
/* jslint node: true */
'use strict';
var ansi = require('../core/ansi_term.js');
var artwork = require('../core/art.js');
var modules = require('../core/modules.js');
var Log = require('../core/logger.js').log;
var ansi = require('./ansi_term.js');
var artwork = require('./art.js');
var modules = require('./modules.js');
var Log = require('./logger.js').log;
var Config = require('./config.js').config;
var packageJson = require('../package.json');
var assert = require('assert');
var util = require('util');
exports.moduleInfo = {
name : 'Connect',
desc : 'First module upon connection',
author : 'NuSkooler',
};
exports.entryPoint = entryPoint;
exports.connectEntry = connectEntry;
function ansiQueryTermSizeIfNeeded(client) {
if(client.term.termHeight > 0 || client.term.termWidth > 0) {
@ -30,10 +26,13 @@ function ansiQueryTermSizeIfNeeded(client) {
return;
}
assert(2 === pos.length);
client.term.termHeight = pos[0];
client.term.termWidth = pos[1];
Log.debug({ termWidth : client.term.termWidth, termHeight : client.term.termHeight, updateSource : 'ANSI CPR' }, 'Window size updated');
Log.debug(
{ termWidth : client.term.termWidth, termHeight : client.term.termHeight, updateSource : 'ANSI CPR' },
'Window size updated');
};
client.once('cursor position report', onCPR);
@ -46,7 +45,21 @@ function ansiQueryTermSizeIfNeeded(client) {
client.term.write(ansi.queryScreenSize());
}
function entryPoint(client) {
function prepareTerminal(term) {
term.write(ansi.normal());
term.write(ansi.disableVT100LineWrapping());
// :TODO: set xterm stuff -- see x84/others
}
function displayBanner(term) {
// :TODO: add URL to banner
term.write(ansi.fromPipeCode(util.format('' +
'|33Conected to |32EN|33|01i|32|22GMA|32|01½|00 |33BBS version|31|01 %s\n' +
'|00|33Copyright (c) 2014 Bryan Ashby\n' +
'|00', packageJson.version)));
}
function connectEntry(client) {
var term = client.term;
//
@ -55,24 +68,8 @@ function entryPoint(client) {
//
ansiQueryTermSizeIfNeeded(client);
term.write(ansi.normal());
term.write(ansi.disableVT100LineWrapping());
//
// If we don't yet know the client term width/height, try
// a nonstandard ANSI query
//
// :TODO: set xterm stuff -- see x84/others
// :TODO: add URL to banner
term.write(ansi.fromPipeCode(util.format('' +
'|33Conected to |32EN|33|01i|32|22GMA|32|01½|00 |33BBS version|31|01 %s\n' +
'|00|33Copyright (c) 2014 Bryan Ashby\n' +
'|00', packageJson.version)));
prepareTerminal(term);
displayBanner(term);
setTimeout(function onTimeout() {
term.write(ansi.clearScreen());
@ -87,7 +84,7 @@ function entryPoint(client) {
setTimeout(function onTimeout() {
term.write(ansi.clearScreen());
modules.goto('matrix', client);
modules.goto(Config.entryMod, client);
}, timeout);
});
}, 500);

31
core/menu_view.js Normal file
View File

@ -0,0 +1,31 @@
/* jslint node: true */
'use strict';
var View = require('./view.js').View;
var ansi = require('./ansi_term.js');
var util = require('util');
var assert = require('assert');
exports.MenuView = MenuView;
function MenuView(client, options) {
View.call(this, client, options);
this.items = [];
if(this.options.items) {
this.options.items.forEach(function onItem(itemText) {
this.items.push({
text : itemText,
focused : false,
selected : false,
});
});
}
this.itemSpacing = this.options.itemSpacing || 1;
this.focusPrefix = this.options.focusPrefix || '';
this.focusSuffix = this.options.focusSuffix || '';
}
util.inherits(MenuView, View);

View File

@ -13,8 +13,6 @@ exports.TextView = TextView;
function TextView(client, options) {
View.call(this, client, options);
var self = this;
if(this.options.maxLength) {
this.maxLength = this.options.maxLength;
}
@ -31,7 +29,7 @@ function TextView(client, options) {
this.setText(this.options.text || '');
this.isPasswordTextStyle = 'P' === self.textStyle || 'password' === self.textStyle;
this.isPasswordTextStyle = 'P' === this.textStyle || 'password' === this.textStyle;
if(this.isPasswordTextStyle) {
this.textMaskChar = miscUtil.valueWithDefault(this.options.textMaskChar, '*').substr(0, 1);

View File

@ -33,15 +33,14 @@ function getThemeInfo(themeID, cb) {
var availableThemes = {};
function initAvailableThemes(cb) {
// lazy init
async.waterfall(
[
function getDir(callback) {
fs.readdir(Config.paths.themes, function onReadDir(err, files) {
fs.readdir(Config.paths.themes, function onReadDir(err, files) {
callback(err, files);
});
},
function filterFiles(files, callback) {
function filterFiles(files, callback) {
var filtered = files.filter(function onFilter(file) {
return fs.statSync(paths.join(Config.paths.themes, file)).isDirectory();
});
@ -56,9 +55,9 @@ function initAvailableThemes(cb) {
}
availableThemes[themeId] = info;
}
callback(null);
});
});
callback(null);
}
],
function onComplete(err) {

View File

@ -0,0 +1,17 @@
/* jslint node: true */
'use strict';
var MenuView = require('./menu_view.js').MenuView;
var ansi = require('./ansi_term.js');
var util = require('util');
var assert = require('assert');
function VerticalMenuView(client, options) {
MenuView.call(this, client, options);
}
util.inherits(VerticalMenuView, MenuView);
VerticalMenuView.prototype.redraw = function() {
VerticalMenuView.super_.prototype.redraw.call(this);
};

View File

@ -40,8 +40,6 @@ function entryPoint(client) {
return;
}
console.log(mci);
user.authenticate('NuSkooler', 'password', client, function onAuth(isValid) {
console.log(isValid);
});