User interrupts & node module ready to rock. ...maybe with bugs?

This commit is contained in:
Bryan Ashby 2018-11-30 23:20:44 -07:00
parent d9238ee6a5
commit fe44f2c4d6
9 changed files with 198 additions and 68 deletions

View file

@ -29,9 +29,15 @@ exports.MenuModule = class MenuModule extends PluginModule {
this.menuConfig.config = this.menuConfig.config || {};
this.cls = _.get(this.menuConfig.config, 'cls', Config().menus.cls);
this.viewControllers = {};
this.interrupt = (_.get(this.menuConfig.config, 'interrupt', MenuModule.InterruptTypes.Queued)).toLowerCase();
}
// *initial* Interruptible state for this menu
this.disableInterruption();
static get InterruptTypes() {
return {
Never : 'never',
Queued : 'queued',
Realtime : 'realtime',
};
}
enter() {
@ -55,7 +61,7 @@ exports.MenuModule = class MenuModule extends PluginModule {
async.series(
[
function beforeArtInterrupt(callback) {
return self.toggleInterruptionAndDisplayQueued(callback);
return self.displayQueuedInterruptions(callback);
},
function beforeDisplayArt(callback) {
return self.beforeArt(callback);
@ -166,60 +172,45 @@ exports.MenuModule = class MenuModule extends PluginModule {
// nothing in base
}
neverInterruptable() {
return this.menuConfig.config.Interruptible === 'never';
}
enableInterruption() {
if(!this.neverInterruptable()) {
this.Interruptible = true;
}
}
disableInterruption() {
if(!this.neverInterruptable()) {
this.Interruptible = false;
}
}
toggleInterruptionAndDisplayQueued(cb) {
this.enableInterruption();
this.displayQueuedInterruptions( () => {
this.disableInterruption();
return cb(null);
});
}
displayQueuedInterruptions(cb) {
if(true !== this.Interruptible) {
if(MenuModule.InterruptTypes.Never === this.interrupt) {
return cb(null);
}
let opts = { cls : true }; // clear screen for first message
async.whilst(
() => this.client.interruptQueue.hasItems(),
next => this.client.interruptQueue.displayNext(next),
next => {
this.client.interruptQueue.displayNext(opts, err => {
opts = {};
return next(err);
});
},
err => {
return cb(err);
}
)
);
}
attemptInterruptNow(interruptItem, cb) {
if(true !== this.Interruptible) {
if(MenuModule.InterruptTypes.Realtime !== this.interrupt) {
return cb(null, false); // don't eat up the item; queue for later
}
//
// Default impl: clear screen -> standard display -> reload menu
//
this.client.interruptQueue.displayWithItem(Object.assign({}, interruptItem, { cls : true }), err => {
if(err) {
return cb(err, false);
}
this.reload(err => {
return cb(err, err ? false : true);
this.client.interruptQueue.displayWithItem(
Object.assign({}, interruptItem, { cls : true }),
err => {
if(err) {
return cb(err, false);
}
this.reload(err => {
return cb(err, err ? false : true);
});
});
});
}
getSaveState() {
@ -308,7 +299,7 @@ exports.MenuModule = class MenuModule extends PluginModule {
} else {
return this.prevMenu(cb);
}
}
};
if(_.has(this.menuConfig, 'runtime.autoNext') && true === this.menuConfig.runtime.autoNext) {
if(this.hasNextTimeout()) {
@ -318,8 +309,6 @@ exports.MenuModule = class MenuModule extends PluginModule {
} else {
return gotoNextMenu();
}
} else {
this.enableInterruption();
}
}

View file

@ -2,16 +2,16 @@
'use strict';
// ENiGMA½
const { MenuModule } = require('./menu_module.js');
const { Errors } = require('./enig_error.js');
const { MenuModule } = require('./menu_module.js');
const {
getActiveConnectionList,
getConnectionByNodeId,
} = require('./client_connections.js');
const UserInterruptQueue = require('./user_interrupt_queue.js');
const { getThemeArt } = require('./theme.js');
const { pipeToAnsi } = require('./color_codes.js');
const stringFormat = require('./string_format.js');
} = require('./client_connections.js');
const UserInterruptQueue = require('./user_interrupt_queue.js');
const { getThemeArt } = require('./theme.js');
const { pipeToAnsi } = require('./color_codes.js');
const stringFormat = require('./string_format.js');
const { renderStringLength } = require('./string_util.js');
// deps
const series = require('async/series');
@ -47,23 +47,27 @@ exports.getModule = class NodeMessageModule extends MenuModule {
this.menuMethods = {
sendMessage : (formData, extraArgs, cb) => {
const nodeId = this.nodeList[formData.value.node].node; // index from from -> node!
const message = formData.value.message;
const message = _.get(formData.value, 'message', '').trim();
if(0 === renderStringLength(message)) {
return this.prevMenu(cb);
}
this.createInterruptItem(message, (err, interruptItem) => {
if(-1 === nodeId) {
// ALL nodes
UserInterruptQueue.queueGlobalOtherActive(interruptItem, this.client);
UserInterruptQueue.queue(interruptItem, { omit : this.client });
} else {
const conn = getConnectionByNodeId(nodeId);
if(conn) {
UserInterruptQueue.queueGlobal(interruptItem, [ conn ]);
UserInterruptQueue.queue(interruptItem, { clients : conn } );
}
}
return this.prevMenu(cb);
});
},
}
};
}
mciReady(mciData, cb) {
@ -123,12 +127,14 @@ exports.getModule = class NodeMessageModule extends MenuModule {
}
createInterruptItem(message, cb) {
const dateTimeFormat = this.config.dateTimeFormat || this.client.currentTheme.helpers.getDateTimeFormat();
const textFormatObj = {
fromUserName : this.client.user.username,
fromRealName : this.client.user.properties.real_name,
fromNodeId : this.client.node,
message : message,
timestamp : moment(),
timestamp : moment().format(dateTimeFormat),
};
const messageFormat =
@ -208,4 +214,4 @@ exports.getModule = class NodeMessageModule extends MenuModule {
}
this.updateCustomViewTextsWithFilter('sendMessage', MciViewIds.sendMessage.customRangeStart, node);
}
}
};

View file

@ -19,18 +19,26 @@ module.exports = class UserInterruptQueue
this.queue = [];
}
static queueGlobal(interruptItem, connections) {
connections.forEach(conn => {
conn.interruptQueue.queueItem(interruptItem);
static queue(interruptItem, opts) {
opts = opts || {};
if(!opts.clients) {
let omitNodes = [];
if(Array.isArray(opts.omit)) {
omitNodes = opts.omit;
} else if(opts.omit) {
omitNodes = [ opts.omit ];
}
omitNodes = omitNodes.map(n => _.isNumber(n) ? n : n.node);
opts.clients = getActiveConnections(true).filter(ac => !omitNodes.includes(ac.node));
}
if(!Array.isArray(opts.clients)) {
opts.clients = [ opts.clients ];
}
opts.clients.forEach(c => {
c.interruptQueue.queueItem(interruptItem);
});
}
// common shortcut: queue global, all active clients minus |client|
static queueGlobalOtherActive(interruptItem, client) {
const otherConnections = getActiveConnections(true).filter(ac => ac.node !== client.node);
return UserInterruptQueue.queueGlobal(interruptItem, otherConnections );
}
queueItem(interruptItem) {
if(!_.isString(interruptItem.contents) && !_.isString(interruptItem.text)) {
return;
@ -52,12 +60,17 @@ module.exports = class UserInterruptQueue
return this.queue.length > 0;
}
displayNext(cb) {
displayNext(options, cb) {
if(!cb && _.isFunction(options)) {
cb = options;
options = {};
}
const interruptItem = this.queue.pop();
if(!interruptItem) {
return cb(null);
}
Object.assign(interruptItem, options);
return interruptItem ? this.displayWithItem(interruptItem, cb) : cb(null);
}