2014-10-17 02:21:06 +00:00
|
|
|
/* jslint node: true */
|
2016-07-25 16:47:30 +00:00
|
|
|
/* eslint-disable no-console */
|
2014-10-17 02:21:06 +00:00
|
|
|
'use strict';
|
|
|
|
|
2016-02-03 04:35:59 +00:00
|
|
|
//var SegfaultHandler = require('segfault-handler');
|
|
|
|
//SegfaultHandler.registerHandler('enigma-bbs-segfault.log');
|
|
|
|
|
2014-10-17 02:21:06 +00:00
|
|
|
// ENiGMA½
|
2016-06-21 02:39:20 +00:00
|
|
|
const conf = require('./config.js');
|
|
|
|
const logger = require('./logger.js');
|
|
|
|
const database = require('./database.js');
|
2017-02-10 04:08:23 +00:00
|
|
|
const resolvePath = require('./misc_util.js').resolvePath;
|
2016-06-21 02:39:20 +00:00
|
|
|
|
2016-08-27 03:28:02 +00:00
|
|
|
// deps
|
2016-06-21 02:39:20 +00:00
|
|
|
const async = require('async');
|
|
|
|
const util = require('util');
|
|
|
|
const _ = require('lodash');
|
|
|
|
const mkdirs = require('fs-extra').mkdirs;
|
2017-05-20 03:20:19 +00:00
|
|
|
const fs = require('graceful-fs');
|
2016-09-29 03:54:25 +00:00
|
|
|
const paths = require('path');
|
2016-02-17 05:11:55 +00:00
|
|
|
|
|
|
|
// our main entry point
|
2017-05-11 03:29:04 +00:00
|
|
|
exports.main = main;
|
2014-10-29 11:30:20 +00:00
|
|
|
|
2016-06-21 02:39:20 +00:00
|
|
|
// object with various services we want to de-init/shutdown cleanly if possible
|
|
|
|
const initServices = {};
|
|
|
|
|
2018-04-11 01:53:04 +00:00
|
|
|
// only include bbs.js once @ startup; this should be fine
|
|
|
|
const COPYRIGHT = fs.readFileSync(paths.join(__dirname, '../LICENSE.TXT'), 'utf8').split(/\r?\n/g)[0];
|
|
|
|
|
|
|
|
const FULL_COPYRIGHT = `ENiGMA½ ${COPYRIGHT}`;
|
2017-06-11 00:29:00 +00:00
|
|
|
const HELP =
|
2018-04-11 01:53:04 +00:00
|
|
|
`${FULL_COPYRIGHT}
|
2017-02-10 04:08:23 +00:00
|
|
|
usage: main.js <args>
|
2017-11-25 22:45:19 +00:00
|
|
|
eg : main.js --config /enigma_install_path/config/
|
2017-02-10 04:08:23 +00:00
|
|
|
|
|
|
|
valid args:
|
|
|
|
--version : display version
|
|
|
|
--help : displays this help
|
2017-11-25 22:45:19 +00:00
|
|
|
--config PATH : override default config path
|
2017-02-10 04:08:23 +00:00
|
|
|
`;
|
|
|
|
|
|
|
|
function printHelpAndExit() {
|
|
|
|
console.info(HELP);
|
|
|
|
process.exit();
|
|
|
|
}
|
|
|
|
|
2017-05-11 03:29:04 +00:00
|
|
|
function main() {
|
2015-04-19 08:13:13 +00:00
|
|
|
async.waterfall(
|
|
|
|
[
|
|
|
|
function processArgs(callback) {
|
2017-02-10 04:08:23 +00:00
|
|
|
const argv = require('minimist')(process.argv.slice(2));
|
|
|
|
|
|
|
|
if(argv.help) {
|
|
|
|
printHelpAndExit();
|
2015-04-19 08:13:13 +00:00
|
|
|
}
|
|
|
|
|
2017-02-10 04:08:23 +00:00
|
|
|
const configOverridePath = argv.config;
|
|
|
|
|
|
|
|
return callback(null, configOverridePath || conf.getDefaultPath(), _.isString(configOverridePath));
|
2015-04-19 08:13:13 +00:00
|
|
|
},
|
|
|
|
function initConfig(configPath, configPathSupplied, callback) {
|
2017-11-25 22:45:19 +00:00
|
|
|
const configFile = configPath + 'config.hjson';
|
|
|
|
conf.init(resolvePath(configFile), function configInit(err) {
|
2015-04-19 08:13:13 +00:00
|
|
|
|
|
|
|
//
|
2017-06-11 00:29:00 +00:00
|
|
|
// If the user supplied a path and we can't read/parse it
|
2015-04-19 08:13:13 +00:00
|
|
|
// then it's a fatal error
|
|
|
|
//
|
2015-11-21 06:46:48 +00:00
|
|
|
if(err) {
|
2015-11-21 20:29:24 +00:00
|
|
|
if('ENOENT' === err.code) {
|
|
|
|
if(configPathSupplied) {
|
2017-11-25 22:45:19 +00:00
|
|
|
console.error('Configuration file does not exist: ' + configFile);
|
2015-11-21 20:29:24 +00:00
|
|
|
} else {
|
|
|
|
configPathSupplied = null; // make non-fatal; we'll go with defaults
|
|
|
|
}
|
2015-11-21 06:46:48 +00:00
|
|
|
} else {
|
|
|
|
console.error(err.toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
callback(err);
|
2015-04-19 08:13:13 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
function initSystem(callback) {
|
|
|
|
initialize(function init(err) {
|
|
|
|
if(err) {
|
|
|
|
console.error('Error initializing: ' + util.inspect(err));
|
|
|
|
}
|
2016-09-29 03:54:25 +00:00
|
|
|
return callback(err);
|
2015-04-19 08:13:13 +00:00
|
|
|
});
|
2017-06-11 00:29:00 +00:00
|
|
|
}
|
2015-04-19 08:13:13 +00:00
|
|
|
],
|
|
|
|
function complete(err) {
|
2016-09-29 03:54:25 +00:00
|
|
|
// note this is escaped:
|
|
|
|
fs.readFile(paths.join(__dirname, '../misc/startup_banner.asc'), 'utf8', (err, banner) => {
|
2018-04-11 01:53:04 +00:00
|
|
|
console.info(FULL_COPYRIGHT);
|
2017-06-11 00:29:00 +00:00
|
|
|
if(!err) {
|
2016-09-29 03:54:25 +00:00
|
|
|
console.info(banner);
|
2017-06-11 00:29:00 +00:00
|
|
|
}
|
2016-09-29 03:54:25 +00:00
|
|
|
console.info('System started!');
|
|
|
|
});
|
|
|
|
|
2016-02-17 05:11:55 +00:00
|
|
|
if(err) {
|
2016-03-27 06:19:31 +00:00
|
|
|
console.error('Error initializing: ' + util.inspect(err));
|
2015-04-19 08:13:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-06-21 02:39:20 +00:00
|
|
|
function shutdownSystem() {
|
2016-09-29 03:54:25 +00:00
|
|
|
const msg = 'Process interrupted. Shutting down...';
|
|
|
|
console.info(msg);
|
|
|
|
logger.log.info(msg);
|
2016-06-21 02:39:20 +00:00
|
|
|
|
|
|
|
async.series(
|
|
|
|
[
|
|
|
|
function closeConnections(callback) {
|
2017-06-23 04:19:34 +00:00
|
|
|
const ClientConns = require('./client_connections.js');
|
|
|
|
const activeConnections = ClientConns.getActiveConnections();
|
2016-06-21 02:39:20 +00:00
|
|
|
let i = activeConnections.length;
|
|
|
|
while(i--) {
|
|
|
|
activeConnections[i].term.write('\n\nServer is shutting down NOW! Disconnecting...\n\n');
|
2017-06-23 04:19:34 +00:00
|
|
|
ClientConns.removeClient(activeConnections[i]);
|
2016-06-21 02:39:20 +00:00
|
|
|
}
|
|
|
|
callback(null);
|
|
|
|
},
|
2016-10-25 03:49:45 +00:00
|
|
|
function stopListeningServers(callback) {
|
|
|
|
return require('./listening_server.js').shutdown( () => {
|
|
|
|
return callback(null); // ignore err
|
|
|
|
});
|
|
|
|
},
|
2016-06-21 02:39:20 +00:00
|
|
|
function stopEventScheduler(callback) {
|
|
|
|
if(initServices.eventScheduler) {
|
2016-06-21 03:05:47 +00:00
|
|
|
return initServices.eventScheduler.shutdown( () => {
|
2017-02-10 05:03:21 +00:00
|
|
|
return callback(null); // ignore err
|
2016-06-21 03:05:47 +00:00
|
|
|
});
|
2016-06-21 02:39:20 +00:00
|
|
|
} else {
|
|
|
|
return callback(null);
|
|
|
|
}
|
2016-06-21 03:05:47 +00:00
|
|
|
},
|
2016-10-25 03:49:45 +00:00
|
|
|
function stopFileAreaWeb(callback) {
|
2017-02-10 05:03:21 +00:00
|
|
|
require('./file_area_web.js').startup( () => {
|
|
|
|
return callback(null); // ignore err
|
2016-10-25 03:49:45 +00:00
|
|
|
});
|
|
|
|
},
|
2016-06-21 03:05:47 +00:00
|
|
|
function stopMsgNetwork(callback) {
|
|
|
|
require('./msg_network.js').shutdown(callback);
|
2017-06-11 00:29:00 +00:00
|
|
|
}
|
2016-06-21 02:39:20 +00:00
|
|
|
],
|
|
|
|
() => {
|
2016-09-29 03:54:25 +00:00
|
|
|
console.info('Goodbye!');
|
|
|
|
return process.exit();
|
2016-06-21 02:39:20 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-10-29 11:30:20 +00:00
|
|
|
function initialize(cb) {
|
|
|
|
async.series(
|
|
|
|
[
|
2015-11-06 23:14:30 +00:00
|
|
|
function createMissingDirectories(callback) {
|
|
|
|
async.each(Object.keys(conf.config.paths), function entry(pathKey, next) {
|
2016-03-29 04:07:21 +00:00
|
|
|
mkdirs(conf.config.paths[pathKey], function dirCreated(err) {
|
2015-11-06 23:14:30 +00:00
|
|
|
if(err) {
|
|
|
|
console.error('Could not create path: ' + conf.config.paths[pathKey] + ': ' + err.toString());
|
|
|
|
}
|
2016-09-05 03:36:26 +00:00
|
|
|
return next(err);
|
2015-11-06 23:14:30 +00:00
|
|
|
});
|
|
|
|
}, function dirCreationComplete(err) {
|
2016-09-05 03:36:26 +00:00
|
|
|
return callback(err);
|
2015-11-06 23:14:30 +00:00
|
|
|
});
|
|
|
|
},
|
2014-10-29 11:30:20 +00:00
|
|
|
function basicInit(callback) {
|
|
|
|
logger.init();
|
2016-07-20 03:23:41 +00:00
|
|
|
logger.log.info(
|
|
|
|
{ version : require('../package.json').version },
|
|
|
|
'**** ENiGMA½ Bulletin Board System Starting Up! ****');
|
2014-10-29 11:30:20 +00:00
|
|
|
|
2016-06-21 02:39:20 +00:00
|
|
|
process.on('SIGINT', shutdownSystem);
|
2016-09-14 03:44:35 +00:00
|
|
|
|
|
|
|
require('later').date.localTime(); // use local times for later.js/scheduling
|
2017-06-11 00:29:00 +00:00
|
|
|
|
2016-09-05 03:36:26 +00:00
|
|
|
return callback(null);
|
2017-06-11 00:29:00 +00:00
|
|
|
},
|
2014-10-29 11:30:20 +00:00
|
|
|
function initDatabases(callback) {
|
2016-09-05 03:36:26 +00:00
|
|
|
return database.initializeDatabases(callback);
|
2014-10-29 11:30:20 +00:00
|
|
|
},
|
2017-06-24 04:49:46 +00:00
|
|
|
function initMimeTypes(callback) {
|
2018-01-15 19:22:11 +00:00
|
|
|
return require('./mime_util.js').startup(callback);
|
2017-06-24 04:49:46 +00:00
|
|
|
},
|
2016-07-28 03:44:27 +00:00
|
|
|
function initStatLog(callback) {
|
2016-09-05 03:36:26 +00:00
|
|
|
return require('./stat_log.js').init(callback);
|
2015-10-18 02:03:51 +00:00
|
|
|
},
|
2014-10-29 11:30:20 +00:00
|
|
|
function initThemes(callback) {
|
|
|
|
// Have to pull in here so it's after Config init
|
2016-07-28 03:44:27 +00:00
|
|
|
require('./theme.js').initAvailableThemes(function onThemesInit(err, themeCount) {
|
2014-10-29 11:30:20 +00:00
|
|
|
logger.log.info({ themeCount : themeCount }, 'Themes initialized');
|
2016-09-05 03:36:26 +00:00
|
|
|
return callback(err);
|
2014-10-29 11:30:20 +00:00
|
|
|
});
|
2015-08-03 00:27:05 +00:00
|
|
|
},
|
2016-08-11 05:35:17 +00:00
|
|
|
function loadSysOpInformation(callback) {
|
2015-08-03 00:27:05 +00:00
|
|
|
//
|
2016-07-28 03:44:27 +00:00
|
|
|
// Copy over some +op information from the user DB -> system propertys.
|
|
|
|
// * Makes this accessible for MCI codes, easy non-blocking access, etc.
|
|
|
|
// * We do this every time as the op is free to change this information just
|
|
|
|
// like any other user
|
2017-06-11 00:29:00 +00:00
|
|
|
//
|
2017-02-18 20:21:18 +00:00
|
|
|
const User = require('./user.js');
|
2016-07-28 03:44:27 +00:00
|
|
|
|
|
|
|
async.waterfall(
|
|
|
|
[
|
|
|
|
function getOpUserName(next) {
|
2017-02-18 20:21:18 +00:00
|
|
|
return User.getUserName(1, next);
|
2016-07-28 03:44:27 +00:00
|
|
|
},
|
|
|
|
function getOpProps(opUserName, next) {
|
|
|
|
const propLoadOpts = {
|
|
|
|
names : [ 'real_name', 'sex', 'email_address', 'location', 'affiliation' ],
|
|
|
|
};
|
2017-02-18 20:21:18 +00:00
|
|
|
User.loadProperties(User.RootUserID, propLoadOpts, (err, opProps) => {
|
2016-07-28 03:44:27 +00:00
|
|
|
return next(err, opUserName, opProps);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
],
|
|
|
|
(err, opUserName, opProps) => {
|
|
|
|
const StatLog = require('./stat_log.js');
|
2015-08-03 00:27:05 +00:00
|
|
|
|
2016-07-28 03:44:27 +00:00
|
|
|
if(err) {
|
|
|
|
[ 'username', 'real_name', 'sex', 'email_address', 'location', 'affiliation' ].forEach(v => {
|
|
|
|
StatLog.setNonPeristentSystemStat(`sysop_${v}`, 'N/A');
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
opProps.username = opUserName;
|
|
|
|
|
|
|
|
_.each(opProps, (v, k) => {
|
2017-06-11 00:29:00 +00:00
|
|
|
StatLog.setNonPeristentSystemStat(`sysop_${k}`, v);
|
2016-07-28 03:44:27 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return callback(null);
|
2015-08-03 00:27:05 +00:00
|
|
|
}
|
2016-07-28 03:44:27 +00:00
|
|
|
);
|
2016-02-17 05:11:55 +00:00
|
|
|
},
|
2017-09-09 17:48:43 +00:00
|
|
|
function initFileAreaStats(callback) {
|
|
|
|
const getAreaStats = require('./file_base_area.js').getAreaStats;
|
|
|
|
getAreaStats( (err, stats) => {
|
|
|
|
if(!err) {
|
|
|
|
const StatLog = require('./stat_log.js');
|
|
|
|
StatLog.setNonPeristentSystemStat('file_base_area_stats', stats);
|
|
|
|
}
|
|
|
|
|
|
|
|
return callback(null);
|
|
|
|
});
|
|
|
|
},
|
2016-08-11 05:35:17 +00:00
|
|
|
function initMCI(callback) {
|
2016-09-05 03:36:26 +00:00
|
|
|
return require('./predefined_mci.js').init(callback);
|
2016-08-11 05:35:17 +00:00
|
|
|
},
|
2016-02-17 05:11:55 +00:00
|
|
|
function readyMessageNetworkSupport(callback) {
|
2017-06-11 00:29:00 +00:00
|
|
|
return require('./msg_network.js').startup(callback);
|
2016-06-20 03:09:45 +00:00
|
|
|
},
|
2017-06-23 04:19:34 +00:00
|
|
|
function readyEvents(callback) {
|
|
|
|
return require('./events.js').startup(callback);
|
|
|
|
},
|
2016-10-25 03:49:45 +00:00
|
|
|
function listenConnections(callback) {
|
|
|
|
return require('./listening_server.js').startup(callback);
|
|
|
|
},
|
2018-03-04 04:46:41 +00:00
|
|
|
function readyFileBaseArea(callback) {
|
|
|
|
return require('./file_base_area.js').startup(callback);
|
|
|
|
},
|
2016-10-25 03:49:45 +00:00
|
|
|
function readyFileAreaWeb(callback) {
|
|
|
|
return require('./file_area_web.js').startup(callback);
|
|
|
|
},
|
2017-02-27 04:28:05 +00:00
|
|
|
function readyPasswordReset(callback) {
|
|
|
|
const WebPasswordReset = require('./web_password_reset.js').WebPasswordReset;
|
|
|
|
return WebPasswordReset.startup(callback);
|
|
|
|
},
|
2016-06-20 03:09:45 +00:00
|
|
|
function readyEventScheduler(callback) {
|
|
|
|
const EventSchedulerModule = require('./event_scheduler.js').EventSchedulerModule;
|
2016-06-21 02:39:20 +00:00
|
|
|
EventSchedulerModule.loadAndStart( (err, modInst) => {
|
|
|
|
initServices.eventScheduler = modInst;
|
|
|
|
return callback(err);
|
|
|
|
});
|
2014-10-29 11:30:20 +00:00
|
|
|
}
|
|
|
|
],
|
|
|
|
function onComplete(err) {
|
2016-09-05 03:36:26 +00:00
|
|
|
return cb(err);
|
2014-10-29 11:30:20 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|