Merge branch 'master' of ssh://numinibsd/git/base/enigma-bbs
This commit is contained in:
commit
21ed9dc777
73
core/bbs.js
73
core/bbs.js
|
@ -5,22 +5,22 @@
|
||||||
//SegfaultHandler.registerHandler('enigma-bbs-segfault.log');
|
//SegfaultHandler.registerHandler('enigma-bbs-segfault.log');
|
||||||
|
|
||||||
// ENiGMA½
|
// ENiGMA½
|
||||||
let conf = require('./config.js');
|
const conf = require('./config.js');
|
||||||
let logger = require('./logger.js');
|
const logger = require('./logger.js');
|
||||||
let miscUtil = require('./misc_util.js');
|
const database = require('./database.js');
|
||||||
let database = require('./database.js');
|
const clientConns = require('./client_connections.js');
|
||||||
let clientConns = require('./client_connections.js');
|
|
||||||
|
|
||||||
let paths = require('path');
|
const async = require('async');
|
||||||
let async = require('async');
|
const util = require('util');
|
||||||
let util = require('util');
|
const _ = require('lodash');
|
||||||
let _ = require('lodash');
|
const mkdirs = require('fs-extra').mkdirs;
|
||||||
let assert = require('assert');
|
|
||||||
let mkdirs = require('fs-extra').mkdirs;
|
|
||||||
|
|
||||||
// our main entry point
|
// our main entry point
|
||||||
exports.bbsMain = bbsMain;
|
exports.bbsMain = bbsMain;
|
||||||
|
|
||||||
|
// object with various services we want to de-init/shutdown cleanly if possible
|
||||||
|
const initServices = {};
|
||||||
|
|
||||||
function bbsMain() {
|
function bbsMain() {
|
||||||
async.waterfall(
|
async.waterfall(
|
||||||
[
|
[
|
||||||
|
@ -84,6 +84,39 @@ function bbsMain() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shutdownSystem() {
|
||||||
|
logger.log.info('Process interrupted, shutting down...');
|
||||||
|
|
||||||
|
async.series(
|
||||||
|
[
|
||||||
|
function closeConnections(callback) {
|
||||||
|
const activeConnections = clientConns.getActiveConnections();
|
||||||
|
let i = activeConnections.length;
|
||||||
|
while(i--) {
|
||||||
|
activeConnections[i].term.write('\n\nServer is shutting down NOW! Disconnecting...\n\n');
|
||||||
|
clientConns.removeClient(activeConnections[i]);
|
||||||
|
}
|
||||||
|
callback(null);
|
||||||
|
},
|
||||||
|
function stopEventScheduler(callback) {
|
||||||
|
if(initServices.eventScheduler) {
|
||||||
|
return initServices.eventScheduler.shutdown( () => {
|
||||||
|
callback(null); // ignore err
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return callback(null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function stopMsgNetwork(callback) {
|
||||||
|
require('./msg_network.js').shutdown(callback);
|
||||||
|
}
|
||||||
|
],
|
||||||
|
() => {
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function initialize(cb) {
|
function initialize(cb) {
|
||||||
async.series(
|
async.series(
|
||||||
[
|
[
|
||||||
|
@ -102,18 +135,7 @@ function initialize(cb) {
|
||||||
function basicInit(callback) {
|
function basicInit(callback) {
|
||||||
logger.init();
|
logger.init();
|
||||||
|
|
||||||
process.on('SIGINT', function onSigInt() {
|
process.on('SIGINT', shutdownSystem);
|
||||||
logger.log.info('Process interrupted, shutting down...');
|
|
||||||
|
|
||||||
var activeConnections = clientConns.getActiveConnections();
|
|
||||||
var i = activeConnections.length;
|
|
||||||
while(i--) {
|
|
||||||
activeConnections[i].term.write('\n\nServer is shutting down NOW! Disconnecting...\n\n');
|
|
||||||
clientConns.removeClient(activeConnections[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
process.exit();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Init some extensions
|
// Init some extensions
|
||||||
require('string-format').extend(String.prototype, require('./string_util.js').stringFormatExtensions);
|
require('string-format').extend(String.prototype, require('./string_util.js').stringFormatExtensions);
|
||||||
|
@ -172,7 +194,10 @@ function initialize(cb) {
|
||||||
},
|
},
|
||||||
function readyEventScheduler(callback) {
|
function readyEventScheduler(callback) {
|
||||||
const EventSchedulerModule = require('./event_scheduler.js').EventSchedulerModule;
|
const EventSchedulerModule = require('./event_scheduler.js').EventSchedulerModule;
|
||||||
EventSchedulerModule.loadAndStart(callback);
|
EventSchedulerModule.loadAndStart( (err, modInst) => {
|
||||||
|
initServices.eventScheduler = modInst;
|
||||||
|
return callback(err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
function onComplete(err) {
|
function onComplete(err) {
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const events = require('events');
|
const events = require('events');
|
||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const pty = require('ptyw.js');
|
const pty = require('ptyw.js');
|
||||||
const decode = require('iconv-lite').decode;
|
const decode = require('iconv-lite').decode;
|
||||||
|
@ -80,6 +79,10 @@ function Door(client, exeInfo) {
|
||||||
return cb(null);
|
return cb(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.doorExited = function() {
|
||||||
|
self.emit('finished');
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
require('util').inherits(Door, events.EventEmitter);
|
require('util').inherits(Door, events.EventEmitter);
|
||||||
|
@ -90,7 +93,7 @@ Door.prototype.run = function() {
|
||||||
this.prepareSocketIoServer( (err, sockServer) => {
|
this.prepareSocketIoServer( (err, sockServer) => {
|
||||||
if(err) {
|
if(err) {
|
||||||
this.client.log.warn( { error : err.toString() }, 'Failed executing door');
|
this.client.log.warn( { error : err.toString() }, 'Failed executing door');
|
||||||
return self.emit('finished');
|
return self.doorExited();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expand arg strings, e.g. {dropFile} -> DOOR32.SYS
|
// Expand arg strings, e.g. {dropFile} -> DOOR32.SYS
|
||||||
|
@ -140,7 +143,7 @@ Door.prototype.run = function() {
|
||||||
|
|
||||||
door.removeAllListeners();
|
door.removeAllListeners();
|
||||||
|
|
||||||
self.emit('finished');
|
return self.doorExited();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,8 @@ const Log = require('./logger.js').log;
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const later = require('later');
|
const later = require('later');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const pty = require('ptyw.js');
|
||||||
|
const gaze = require('gaze');
|
||||||
|
|
||||||
exports.getModule = EventSchedulerModule;
|
exports.getModule = EventSchedulerModule;
|
||||||
exports.EventSchedulerModule = EventSchedulerModule; // allow for loadAndStart
|
exports.EventSchedulerModule = EventSchedulerModule; // allow for loadAndStart
|
||||||
|
@ -101,8 +103,8 @@ class ScheduledEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
executeAction(cb) {
|
executeAction(reason, cb) {
|
||||||
Log.info( { eventName : this.name, action : this.action }, 'Executing scheduled action...');
|
Log.info( { eventName : this.name, action : this.action, reason : reason }, 'Executing scheduled event action...');
|
||||||
|
|
||||||
if('method' === this.action.type) {
|
if('method' === this.action.type) {
|
||||||
const modulePath = path.join(__dirname, '../', this.action.location); // enigma-bbs base + supplied location (path/file.js')
|
const modulePath = path.join(__dirname, '../', this.action.location); // enigma-bbs base + supplied location (path/file.js')
|
||||||
|
@ -112,7 +114,7 @@ class ScheduledEvent {
|
||||||
if(err) {
|
if(err) {
|
||||||
Log.debug(
|
Log.debug(
|
||||||
{ error : err.toString(), eventName : this.name, action : this.action },
|
{ error : err.toString(), eventName : this.name, action : this.action },
|
||||||
'Error while performing scheduled event action');
|
'Error performing scheduled event action');
|
||||||
}
|
}
|
||||||
|
|
||||||
return cb(err);
|
return cb(err);
|
||||||
|
@ -125,7 +127,24 @@ class ScheduledEvent {
|
||||||
return cb(e);
|
return cb(e);
|
||||||
}
|
}
|
||||||
} else if('execute' === this.action.type) {
|
} else if('execute' === this.action.type) {
|
||||||
// :TODO: implement execute!
|
const opts = {
|
||||||
|
// :TODO: cwd
|
||||||
|
name : this.name,
|
||||||
|
cols : 80,
|
||||||
|
rows : 24,
|
||||||
|
env : process.env,
|
||||||
|
};
|
||||||
|
|
||||||
|
const proc = pty.spawn(this.action.what, this.action.args, opts);
|
||||||
|
|
||||||
|
proc.once('exit', exitCode => {
|
||||||
|
if(exitCode) {
|
||||||
|
Log.warn(
|
||||||
|
{ eventName : this.name, action : this.action, exitCode : exitCode },
|
||||||
|
'Bad exit code while performing scheduled event action');
|
||||||
|
}
|
||||||
|
return cb(exitCode ? new Error(`Bad exit code while performing scheduled event action: ${exitCode}`) : null);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,14 +159,14 @@ function EventSchedulerModule(options) {
|
||||||
const self = this;
|
const self = this;
|
||||||
this.runningActions = new Set();
|
this.runningActions = new Set();
|
||||||
|
|
||||||
this.performAction = function(schedEvent) {
|
this.performAction = function(schedEvent, reason) {
|
||||||
if(self.runningActions.has(schedEvent.name)) {
|
if(self.runningActions.has(schedEvent.name)) {
|
||||||
return; // already running
|
return; // already running
|
||||||
}
|
}
|
||||||
|
|
||||||
self.runningActions.add(schedEvent.name);
|
self.runningActions.add(schedEvent.name);
|
||||||
|
|
||||||
schedEvent.executeAction( () => {
|
schedEvent.executeAction(reason, () => {
|
||||||
self.runningActions.delete(schedEvent.name);
|
self.runningActions.delete(schedEvent.name);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -169,14 +188,14 @@ EventSchedulerModule.loadAndStart = function(cb) {
|
||||||
|
|
||||||
const modInst = new mod.getModule();
|
const modInst = new mod.getModule();
|
||||||
modInst.startup( err => {
|
modInst.startup( err => {
|
||||||
return cb(err);
|
return cb(err, modInst);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
EventSchedulerModule.prototype.startup = function(cb) {
|
EventSchedulerModule.prototype.startup = function(cb) {
|
||||||
|
|
||||||
this.eventTimers = [];
|
this.eventTimers = [];
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
if(this.moduleConfig && _.has(this.moduleConfig, 'events')) {
|
if(this.moduleConfig && _.has(this.moduleConfig, 'events')) {
|
||||||
|
@ -192,7 +211,7 @@ EventSchedulerModule.prototype.startup = function(cb) {
|
||||||
|
|
||||||
Log.debug(
|
Log.debug(
|
||||||
{
|
{
|
||||||
evetnName : schedEvent.name,
|
eventName : schedEvent.name,
|
||||||
schedule : this.moduleConfig.events[schedEvent.name].schedule,
|
schedule : this.moduleConfig.events[schedEvent.name].schedule,
|
||||||
action : schedEvent.action,
|
action : schedEvent.action,
|
||||||
},
|
},
|
||||||
|
@ -201,11 +220,20 @@ EventSchedulerModule.prototype.startup = function(cb) {
|
||||||
|
|
||||||
if(schedEvent.schedule.sched) {
|
if(schedEvent.schedule.sched) {
|
||||||
this.eventTimers.push(later.setInterval( () => {
|
this.eventTimers.push(later.setInterval( () => {
|
||||||
self.performAction(schedEvent);
|
self.performAction(schedEvent, 'Schedule');
|
||||||
}, schedEvent.schedule.sched));
|
}, schedEvent.schedule.sched));
|
||||||
}
|
}
|
||||||
|
|
||||||
// :TODO: handle watchfile -> performAction
|
if(schedEvent.schedule.watchFile) {
|
||||||
|
gaze(schedEvent.schedule.watchFile, (err, watcher) => {
|
||||||
|
// :TODO: should track watched files & stop watching @ shutdown
|
||||||
|
watcher.on('all', (watchEvent, watchedPath) => {
|
||||||
|
if(schedEvent.schedule.watchFile === watchedPath) {
|
||||||
|
self.performAction(schedEvent, `Watch file: ${watchedPath}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +244,6 @@ EventSchedulerModule.prototype.shutdown = function(cb) {
|
||||||
if(this.eventTimers) {
|
if(this.eventTimers) {
|
||||||
this.eventTimers.forEach( et => et.clear() );
|
this.eventTimers.forEach( et => et.clear() );
|
||||||
}
|
}
|
||||||
|
|
||||||
cb(null);
|
cb(null);
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
let loadModulesForCategory = require('./module_util.js').loadModulesForCategory;
|
let loadModulesForCategory = require('./module_util.js').loadModulesForCategory;
|
||||||
|
|
||||||
// standard/deps
|
// standard/deps
|
||||||
let async = require('async');
|
let async = require('async');
|
||||||
|
|
||||||
exports.startup = startup
|
exports.startup = startup;
|
||||||
exports.shutdown = shutdown;
|
exports.shutdown = shutdown;
|
||||||
exports.recordMessage = recordMessage;
|
exports.recordMessage = recordMessage;
|
||||||
|
|
||||||
|
@ -36,12 +36,19 @@ function startup(cb) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function shutdown() {
|
function shutdown(cb) {
|
||||||
msgNetworkModules.forEach(mod => {
|
async.each(
|
||||||
mod.shutdown();
|
msgNetworkModules,
|
||||||
});
|
(msgNetModule, next) => {
|
||||||
|
msgNetModule.shutdown( () => {
|
||||||
msgNetworkModules = [];
|
return next();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
msgNetworkModules = [];
|
||||||
|
return cb(null);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function recordMessage(message, cb) {
|
function recordMessage(message, cb) {
|
||||||
|
|
|
@ -11,7 +11,6 @@ let async = require('async');
|
||||||
let assert = require('assert');
|
let assert = require('assert');
|
||||||
let paths = require('path');
|
let paths = require('path');
|
||||||
let _ = require('lodash');
|
let _ = require('lodash');
|
||||||
let net = require('net');
|
|
||||||
let mkdirs = require('fs-extra').mkdirs;
|
let mkdirs = require('fs-extra').mkdirs;
|
||||||
|
|
||||||
// :TODO: This should really be a system module... needs a little work to allow for such
|
// :TODO: This should really be a system module... needs a little work to allow for such
|
||||||
|
@ -20,8 +19,6 @@ exports.getModule = AbracadabraModule;
|
||||||
|
|
||||||
let activeDoorNodeInstances = {};
|
let activeDoorNodeInstances = {};
|
||||||
|
|
||||||
let doorInstances = {}; // name -> { count : <instCount>, { <nodeNum> : <inst> } }
|
|
||||||
|
|
||||||
exports.moduleInfo = {
|
exports.moduleInfo = {
|
||||||
name : 'Abracadabra',
|
name : 'Abracadabra',
|
||||||
desc : 'External BBS Door Module',
|
desc : 'External BBS Door Module',
|
||||||
|
@ -166,6 +163,18 @@ function AbracadabraModule(options) {
|
||||||
const doorInstance = new door.Door(self.client, exeInfo);
|
const doorInstance = new door.Door(self.client, exeInfo);
|
||||||
|
|
||||||
doorInstance.once('finished', () => {
|
doorInstance.once('finished', () => {
|
||||||
|
//
|
||||||
|
// Try to clean up various settings such as scroll regions that may
|
||||||
|
// have been set within the door
|
||||||
|
//
|
||||||
|
self.client.term.rawWrite(
|
||||||
|
ansi.normal() +
|
||||||
|
ansi.goto(self.client.term.termHeight, self.client.term.termWidth) +
|
||||||
|
ansi.setScrollRegion() +
|
||||||
|
ansi.goto(self.client.term.termHeight, 0) +
|
||||||
|
'\r\n\r\n'
|
||||||
|
);
|
||||||
|
|
||||||
self.prevMenu();
|
self.prevMenu();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue