* Work on themes. Ability to use ANSI to detect screen size if NAWS/etc. fail

This commit is contained in:
Bryan 2014-10-29 05:30:20 -06:00
parent 1ef9a4a1ce
commit 14a321de2f
6 changed files with 107 additions and 50 deletions

View File

@ -10,8 +10,11 @@ var database = require('./database.js');
var iconv = require('iconv-lite'); var iconv = require('iconv-lite');
var paths = require('path'); var paths = require('path');
var async = require('async');
exports.bbsMain = function() { exports.bbsMain = bbsMain;
function bbsMain() {
var mainArgs = parseArgs(); var mainArgs = parseArgs();
var configPathSupplied = false; var configPathSupplied = false;
@ -74,6 +77,41 @@ function parseArgs() {
return args; return args;
} }
function initialize(cb) {
async.series(
[
function basicInit(callback) {
logger.init();
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();
});
callback(null);
},
function initDatabases(callback) {
database.initializeDatabases();
callback(null);
},
function initThemes(callback) {
// Have to pull in here so it's after Config init
var theme = require('./theme.js');
theme.initAvailableThemes(function onThemesInit(err, themeCount) {
logger.log.info({ themeCount : themeCount }, 'Themes initialized');
callback(err);
});
}
],
function onComplete(err) {
cb(err);
}
);
}
function preServingInit() { function preServingInit() {
iconv.extendNodeEncodings(); iconv.extendNodeEncodings();
} }
@ -164,16 +202,11 @@ function prepareClient(client, cb) {
if('*' === conf.config.preLoginTheme) { if('*' === conf.config.preLoginTheme) {
var theme = require('./theme.js'); var theme = require('./theme.js');
theme.getRandomTheme(function onRandTheme(err, themeId) { theme.getRandomTheme(function onRandTheme(err, themeId) {
if(err) { client.user.properties.art_theme_id = themeId || '';
// :TODO: how to propertly set default/fallback? cb(null);
client.user.properties.art_theme_name = '';
} else {
client.user.properties.art_theme_name = themeId;
}
cb();
}); });
} else { } else {
client.user.properties.art_theme_name = conf.config.preLoginTheme; client.user.properties.art_theme_id = conf.config.preLoginTheme;
cb(); cb(null);
} }
} }

View File

@ -34,6 +34,7 @@ module.exports = {
mods : paths.join(__dirname, './../mods/'), mods : paths.join(__dirname, './../mods/'),
servers : paths.join(__dirname, './servers/'), servers : paths.join(__dirname, './servers/'),
art : paths.join(__dirname, './../mods/art/'), art : paths.join(__dirname, './../mods/art/'),
themes : paths.join(__dirname, './../mods/art/themes/'),
logs : paths.join(__dirname, './../logs/'), // :TODO: set up based on system, e.g. /var/logs/enigmabbs or such logs : paths.join(__dirname, './../logs/'), // :TODO: set up based on system, e.g. /var/logs/enigmabbs or such
db : paths.join(__dirname, './../db/'), db : paths.join(__dirname, './../db/'),
}, },

View File

@ -562,14 +562,16 @@ TelnetClient.prototype.handleSbCommand = function(evt) {
// * Map COLUMNS -> 'termWidth' and only update if ours is 0 // * Map COLUMNS -> 'termWidth' and only update if ours is 0
// * Map ROWS -> 'termHeight' and only update if ours is 0 // * Map ROWS -> 'termHeight' and only update if ours is 0
// * Add any new variables, ignore any existing // * Add any new variables, ignore any existing
// //
Object.keys(evt.envVars).forEach(function onEnv(name) { Object.keys(evt.envVars).forEach(function onEnv(name) {
if('TERM' === name && 'unknown' === self.term.termType) { if('TERM' === name && 'unknown' === self.term.termType) {
self.setTermType(evt.envVars[name]); self.setTermType(evt.envVars[name]);
} else if('COLUMNS' === name && 0 === self.term.termWidth) { } else if('COLUMNS' === name && 0 === self.term.termWidth) {
self.term.termWidth = parseInt(evt.envVars[name]); self.term.termWidth = parseInt(evt.envVars[name]);
logger.log.debug({ termWidth : self.term.termWidth, updateSource : 'NEW-ENVIRON'}, 'Window width updated');
} else if('ROWS' === name && 0 === self.term.termHeight) { } else if('ROWS' === name && 0 === self.term.termHeight) {
self.term.termHeight = parseInt(evt.envVars[name]); self.term.termHeight = parseInt(evt.envVars[name]);
logger.log.debug({ termHeight : self.term.termHeight, updateSource : 'NEW-ENVIRON'}, 'Window height updated');
} else { } else {
if(name in self.term.env) { if(name in self.term.env) {
assert(evt.type === SB_COMMANDS.INFO); assert(evt.type === SB_COMMANDS.INFO);
@ -582,6 +584,7 @@ TelnetClient.prototype.handleSbCommand = function(evt) {
} }
} }
}); });
} else if('window size' === evt.option) { } else if('window size' === evt.option) {
// //
// Update termWidth & termHeight. // Update termWidth & termHeight.
@ -598,7 +601,7 @@ TelnetClient.prototype.handleSbCommand = function(evt) {
self.term.env['ROWS'] = evt.height; self.term.env['ROWS'] = evt.height;
} }
logger.log.debug({ termWidth : evt.width , termHeight : evt.height }, 'Window size updated'); logger.log.debug({ termWidth : evt.width , termHeight : evt.height, updateSource : 'NAWS' }, 'Window size updated');
} else { } else {
console.log('unhandled SB: ' + JSON.stringify(evt)); console.log('unhandled SB: ' + JSON.stringify(evt));
} }

View File

@ -11,18 +11,10 @@ var async = require('async');
exports.getThemeInfo = getThemeInfo; exports.getThemeInfo = getThemeInfo;
exports.getThemeArt = getThemeArt; exports.getThemeArt = getThemeArt;
exports.getRandomTheme = getRandomTheme; exports.getRandomTheme = getRandomTheme;
exports.initAvailableThemes = initAvailableThemes;
// getThemeInfo(themeName)
/*
// getThemeFile(themeShortName, name)
// getArt(name, {
basePath : themeDir,
}
*/
function getThemeInfo(themeID, cb) { function getThemeInfo(themeID, cb) {
var path = paths.join(Config.paths.art, themeID, 'theme_info.json'); var path = paths.join(Config.paths.themes, themeID, 'theme_info.json');
fs.readFile(path, function onData(err, data) { fs.readFile(path, function onData(err, data) {
if(err) { if(err) {
@ -38,20 +30,20 @@ function getThemeInfo(themeID, cb) {
}); });
} }
var availableThemes; var availableThemes = {};
function loadAvailableThemes(cb) { function initAvailableThemes(cb) {
// lazy init // lazy init
async.waterfall( async.waterfall(
[ [
function getDir(callback) { function getDir(callback) {
fs.readdir(Config.paths.art, function onReadDir(err, files) { fs.readdir(Config.paths.themes, function onReadDir(err, files) {
callback(err, files); callback(err, files);
}); });
}, },
function filterFiles(files, callback) { function filterFiles(files, callback) {
var filtered = files.filter(function onFilter(file) { var filtered = files.filter(function onFilter(file) {
return fs.statSync(paths.join(Config.paths.art, file)).isDirectory(); return fs.statSync(paths.join(Config.paths.themes, file)).isDirectory();
}); });
callback(null, filtered); callback(null, filtered);
}, },
@ -75,30 +67,17 @@ function loadAvailableThemes(cb) {
return; return;
} }
if(!availableThemes) { cb(null, availableThemes.length);
cb(new Error('No themes found'));
return;
}
cb(null);
} }
); );
} }
function getRandomTheme(cb) { function getRandomTheme(cb) {
var themeIds; if(availableThemes.length > 0) {
if(availableThemes) { var themeIds = Object.keys(availableThemes);
themeIds = Object.keys(availableThemes);
cb(null, themeIds[Math.floor(Math.random() * themeIds.length)]); cb(null, themeIds[Math.floor(Math.random() * themeIds.length)]);
} else { } else {
loadAvailableThemes(function onThemes(err) { cb(new Error('No themes available'));
if(err) {
cb(err);
} else {
themeIds = Object.keys(availableThemes);
cb(null, themeIds[Math.floor(Math.random() * themeIds.length)]);
}
});
} }
} }
@ -113,11 +92,11 @@ function getThemeArt(name, themeID, options, cb) {
options.asAnsi = true; options.asAnsi = true;
options.readSauce = true; // can help with encoding options.readSauce = true; // can help with encoding
options.random = miscUtil.valueWithDefault(options.random, true); options.random = miscUtil.valueWithDefault(options.random, true);
options.basePath = paths.join(Config.paths.art, themeID); options.basePath = paths.join(Config.paths.themes, themeID);
art.getArt(name, options, function onThemeArt(err, theArt) { art.getArt(name, options, function onThemeArt(err, theArt) {
if(err) { if(err) {
// try fallback // try fallback of art directory
options.basePath = Config.paths.art; options.basePath = Config.paths.art;
art.getArt(name, options, function onFallbackArt(err, theArt) { art.getArt(name, options, function onFallbackArt(err, theArt) {
if(err) { if(err) {

View File

@ -4,7 +4,9 @@
var ansi = require('../core/ansi_term.js'); var ansi = require('../core/ansi_term.js');
var artwork = require('../core/art.js'); var artwork = require('../core/art.js');
var modules = require('../core/modules.js'); var modules = require('../core/modules.js');
var Log = require('../core/logger.js').log;
var packageJson = require('../package.json'); var packageJson = require('../package.json');
var util = require('util'); var util = require('util');
exports.moduleInfo = { exports.moduleInfo = {
@ -15,17 +17,55 @@ exports.moduleInfo = {
exports.entryPoint = entryPoint; exports.entryPoint = entryPoint;
function entryPoint(client) { function ansiQueryTermSizeIfNeeded(client) {
/*var self = this; if(client.term.termHeight > 0 || client.term.termWidth > 0) {
this.client = client; return;
var term = this.client.term;*/ }
var onCPR = function(pos) {
//
// If we've already found out, disregard
//
if(client.term.termHeight > 0 || client.term.termWidth > 0) {
return;
}
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');
};
client.once('cursor position report', onCPR);
// give up after 2s
setTimeout(function onTimeout() {
client.removeListener('cursor position report', onCPR);
}, 2000);
client.term.write(ansi.queryScreenSize());
}
function entryPoint(client) {
var term = client.term; var term = client.term;
//
// If we don't yet know the client term width/height,
// try with a nonstandard ANSI DSR type request.
//
ansiQueryTermSizeIfNeeded(client);
term.write(ansi.normal()); term.write(ansi.normal());
term.write(ansi.disableVT100LineWrapping()); 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: set xterm stuff -- see x84/others
// :TODO: add URL to banner // :TODO: add URL to banner

View File

@ -29,7 +29,8 @@ function entryPoint(client) {
// :TODO: types, random, and others? could come from conf.mods.matrix or such // :TODO: types, random, and others? could come from conf.mods.matrix or such
//art.getArt('SO-CC1.ANS'/* 'MATRIX'*/, { types: ['.ans'], random: true}, function onArt(err, theArt) { //art.getArt('SO-CC1.ANS'/* 'MATRIX'*/, { types: ['.ans'], random: true}, function onArt(err, theArt) {
theme.getThemeArt('MATRIX_1', client.user.properties.art_theme_name, function onArt(err, theArt) { //client.user.properties.art_theme_id = '';
theme.getThemeArt('MATRIX_1', client.user.properties.art_theme_id, function onArt(err, theArt) {
//art.getArt('MATRIX_1.ANS', {}, function onArt(err, theArt) { //art.getArt('MATRIX_1.ANS', {}, function onArt(err, theArt) {
if(!err) { if(!err) {