From 14a321de2fb0df8dd4f2ca0e1ff96ba987f0aff2 Mon Sep 17 00:00:00 2001 From: Bryan Date: Wed, 29 Oct 2014 05:30:20 -0600 Subject: [PATCH] * Work on themes. Ability to use ANSI to detect screen size if NAWS/etc. fail --- core/bbs.js | 53 ++++++++++++++++++++++++++++++++++-------- core/config.js | 1 + core/servers/telnet.js | 7 ++++-- core/theme.js | 45 ++++++++++------------------------- mods/connect.js | 48 ++++++++++++++++++++++++++++++++++---- mods/matrix.js | 3 ++- 6 files changed, 107 insertions(+), 50 deletions(-) diff --git a/core/bbs.js b/core/bbs.js index 757dae4b..fba64c66 100644 --- a/core/bbs.js +++ b/core/bbs.js @@ -10,8 +10,11 @@ var database = require('./database.js'); var iconv = require('iconv-lite'); var paths = require('path'); +var async = require('async'); -exports.bbsMain = function() { +exports.bbsMain = bbsMain; + +function bbsMain() { var mainArgs = parseArgs(); var configPathSupplied = false; @@ -74,6 +77,41 @@ function parseArgs() { 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() { iconv.extendNodeEncodings(); } @@ -164,16 +202,11 @@ function prepareClient(client, cb) { if('*' === conf.config.preLoginTheme) { var theme = require('./theme.js'); theme.getRandomTheme(function onRandTheme(err, themeId) { - if(err) { - // :TODO: how to propertly set default/fallback? - client.user.properties.art_theme_name = ''; - } else { - client.user.properties.art_theme_name = themeId; - } - cb(); + client.user.properties.art_theme_id = themeId || ''; + cb(null); }); } else { - client.user.properties.art_theme_name = conf.config.preLoginTheme; - cb(); + client.user.properties.art_theme_id = conf.config.preLoginTheme; + cb(null); } } \ No newline at end of file diff --git a/core/config.js b/core/config.js index 9d5bfe95..627a97ac 100644 --- a/core/config.js +++ b/core/config.js @@ -34,6 +34,7 @@ module.exports = { mods : paths.join(__dirname, './../mods/'), servers : paths.join(__dirname, './servers/'), 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 db : paths.join(__dirname, './../db/'), }, diff --git a/core/servers/telnet.js b/core/servers/telnet.js index 2d66b79b..e9e6a186 100644 --- a/core/servers/telnet.js +++ b/core/servers/telnet.js @@ -562,14 +562,16 @@ TelnetClient.prototype.handleSbCommand = function(evt) { // * Map COLUMNS -> 'termWidth' and only update if ours is 0 // * Map ROWS -> 'termHeight' and only update if ours is 0 // * Add any new variables, ignore any existing - // + // Object.keys(evt.envVars).forEach(function onEnv(name) { if('TERM' === name && 'unknown' === self.term.termType) { self.setTermType(evt.envVars[name]); } else if('COLUMNS' === name && 0 === self.term.termWidth) { 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) { self.term.termHeight = parseInt(evt.envVars[name]); + logger.log.debug({ termHeight : self.term.termHeight, updateSource : 'NEW-ENVIRON'}, 'Window height updated'); } else { if(name in self.term.env) { assert(evt.type === SB_COMMANDS.INFO); @@ -582,6 +584,7 @@ TelnetClient.prototype.handleSbCommand = function(evt) { } } }); + } else if('window size' === evt.option) { // // Update termWidth & termHeight. @@ -598,7 +601,7 @@ TelnetClient.prototype.handleSbCommand = function(evt) { 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 { console.log('unhandled SB: ' + JSON.stringify(evt)); } diff --git a/core/theme.js b/core/theme.js index 26f24192..e9eb28ed 100644 --- a/core/theme.js +++ b/core/theme.js @@ -11,18 +11,10 @@ var async = require('async'); exports.getThemeInfo = getThemeInfo; exports.getThemeArt = getThemeArt; exports.getRandomTheme = getRandomTheme; - - -// getThemeInfo(themeName) -/* -// getThemeFile(themeShortName, name) - // getArt(name, { - basePath : themeDir, - } -*/ +exports.initAvailableThemes = initAvailableThemes; 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) { if(err) { @@ -38,20 +30,20 @@ function getThemeInfo(themeID, cb) { }); } -var availableThemes; +var availableThemes = {}; -function loadAvailableThemes(cb) { +function initAvailableThemes(cb) { // lazy init async.waterfall( [ function getDir(callback) { - fs.readdir(Config.paths.art, function onReadDir(err, files) { + fs.readdir(Config.paths.themes, function onReadDir(err, files) { callback(err, files); }); }, function filterFiles(files, callback) { 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); }, @@ -75,30 +67,17 @@ function loadAvailableThemes(cb) { return; } - if(!availableThemes) { - cb(new Error('No themes found')); - return; - } - - cb(null); + cb(null, availableThemes.length); } ); } function getRandomTheme(cb) { - var themeIds; - if(availableThemes) { - themeIds = Object.keys(availableThemes); + if(availableThemes.length > 0) { + var themeIds = Object.keys(availableThemes); cb(null, themeIds[Math.floor(Math.random() * themeIds.length)]); } else { - loadAvailableThemes(function onThemes(err) { - if(err) { - cb(err); - } else { - themeIds = Object.keys(availableThemes); - cb(null, themeIds[Math.floor(Math.random() * themeIds.length)]); - } - }); + cb(new Error('No themes available')); } } @@ -113,11 +92,11 @@ function getThemeArt(name, themeID, options, cb) { options.asAnsi = true; options.readSauce = true; // can help with encoding 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) { if(err) { - // try fallback + // try fallback of art directory options.basePath = Config.paths.art; art.getArt(name, options, function onFallbackArt(err, theArt) { if(err) { diff --git a/mods/connect.js b/mods/connect.js index 82f13f2e..fe5bf57a 100644 --- a/mods/connect.js +++ b/mods/connect.js @@ -4,7 +4,9 @@ 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 packageJson = require('../package.json'); + var util = require('util'); exports.moduleInfo = { @@ -15,17 +17,55 @@ exports.moduleInfo = { exports.entryPoint = entryPoint; -function entryPoint(client) { - /*var self = this; - this.client = client; - var term = this.client.term;*/ +function ansiQueryTermSizeIfNeeded(client) { + if(client.term.termHeight > 0 || client.term.termWidth > 0) { + return; + } + 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; + // + // 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.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 diff --git a/mods/matrix.js b/mods/matrix.js index 20d46b69..2f7851af 100644 --- a/mods/matrix.js +++ b/mods/matrix.js @@ -29,7 +29,8 @@ function entryPoint(client) { // :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) { - 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) { if(!err) {