enigma-bbs/core/wfc.js

304 lines
10 KiB
JavaScript
Raw Normal View History

2020-07-14 03:08:25 +00:00
// ENiGMA½
const { MenuModule } = require('./menu_module');
2020-11-10 02:40:55 +00:00
const { getActiveConnectionList } = require('./client_connections');
const StatLog = require('./stat_log');
const SysProps = require('./system_property');
2020-12-08 02:52:54 +00:00
const UserProps = require('./user_property');
2020-11-28 05:35:03 +00:00
const Log = require('./logger');
const Config = require('./config.js').get;
2020-11-10 02:40:55 +00:00
2020-09-25 21:41:21 +00:00
// deps
const async = require('async');
const _ = require('lodash');
2020-11-10 04:32:34 +00:00
const moment = require('moment');
2020-11-28 05:35:03 +00:00
const bunyan = require('bunyan');
2020-09-25 21:41:21 +00:00
2020-07-14 03:08:25 +00:00
exports.moduleInfo = {
name : 'WFC',
desc : 'Semi-Traditional Waiting For Caller',
author : 'NuSkooler',
};
2020-09-25 21:41:21 +00:00
const FormIds = {
main : 0,
};
const MciViewIds = {
main : {
2020-11-10 02:40:55 +00:00
nodeStatus : 1,
quickLogView : 2,
2020-09-25 21:41:21 +00:00
customRangeStart : 10,
}
};
// Secure + 2FA + root user + 'wfc' group.
const DefaultACS = 'SCAF2ID1GM[wfc]';
2022-05-04 16:25:59 +00:00
const MainStatRefreshTimeMs = 5000; // 5s
2020-09-25 21:41:21 +00:00
2020-07-14 03:08:25 +00:00
exports.getModule = class WaitingForCallerModule extends MenuModule {
constructor(options) {
super(options);
this.config = Object.assign({}, _.get(options, 'menuConfig.config'), { extraArgs : options.extraArgs });
2020-09-25 21:41:21 +00:00
this.config.acs = this.config.acs || DefaultACS;
if (!this.config.acs.includes('SC')) {
2020-11-10 02:40:55 +00:00
this.config.acs = 'SC' + this.config.acs; // secure connection at the very least
2020-09-25 21:41:21 +00:00
}
}
mciReady(mciData, cb) {
super.mciReady(mciData, err => {
if (err) {
return cb(err);
}
async.series(
[
(callback) => {
return this.prepViewController('main', FormIds.main, mciData.menu, callback);
},
2020-11-28 05:35:03 +00:00
(callback) => {
const quickLogView = this.viewControllers.main.getView(MciViewIds.main.quickLogView);
if (!quickLogView) {
return callback(null);
}
2020-12-08 02:52:54 +00:00
const logLevel = this.config.quickLogLevel || // WFC specific
_.get(Config(), 'logging.rotatingFile.level') || // ...or system setting
'info'; // ...or default to info
2020-11-28 05:35:03 +00:00
this.logRingBuffer = new bunyan.RingBuffer({ limit : quickLogView.dimens.height || 24 });
Log.log.addStream({
name : 'wfc-ringbuffer',
type : 'raw',
level : logLevel,
stream : this.logRingBuffer
});
return callback(null);
},
2020-11-10 04:32:34 +00:00
(callback) => {
2020-12-08 02:52:54 +00:00
return this._refreshAll(callback);
2020-11-10 02:40:55 +00:00
}
2020-09-25 21:41:21 +00:00
],
err => {
2020-11-28 05:35:03 +00:00
if (!err) {
this._startRefreshing();
}
2020-09-25 21:41:21 +00:00
return cb(err);
}
);
});
2020-07-14 03:08:25 +00:00
}
2020-11-10 02:40:55 +00:00
enter() {
this.client.stopIdleMonitor();
super.enter();
}
2020-11-28 05:35:03 +00:00
leave() {
_.remove(Log.log.streams, stream => {
return stream.name === 'wfc-ringbuffer';
});
2020-11-28 05:35:03 +00:00
this._stopRefreshing();
this.client.startIdleMonitor();
2020-11-28 05:35:03 +00:00
super.leave();
}
_startRefreshing() {
this.mainRefreshTimer = setInterval( () => {
this._refreshAll();
2022-05-04 16:25:59 +00:00
}, MainStatRefreshTimeMs);
2020-11-28 05:35:03 +00:00
}
_stopRefreshing() {
if (this.mainRefreshTimer) {
clearInterval(this.mainRefreshTimer);
delete this.mainRefreshTimer;
}
}
_refreshAll(cb) {
async.series(
[
(callback) => {
return this._refreshStats(callback);
},
(callback) => {
return this._refreshNodeStatus(callback);
},
(callback) => {
return this._refreshQuickLog(callback);
2020-12-08 02:52:54 +00:00
},
(callback) => {
this.updateCustomViewTextsWithFilter(
'main',
MciViewIds.main.customRangeStart,
this.stats
);
return callback(null);
2020-11-28 05:35:03 +00:00
}
],
err => {
if (cb) {
return cb(err);
}
}
);
}
2020-11-10 02:40:55 +00:00
_refreshStats(cb) {
const fileAreaStats = StatLog.getSystemStat(SysProps.FileBaseAreaStats) || {};
const sysMemStats = StatLog.getSystemStat(SysProps.SystemMemoryStats) || {};
const sysLoadStats = StatLog.getSystemStat(SysProps.SystemLoadStats) || {};
2020-12-08 02:52:54 +00:00
const lastLoginStats = StatLog.getSystemStat(SysProps.LastLogin);
const now = moment();
2020-11-10 02:40:55 +00:00
this.stats = {
2020-11-10 04:32:34 +00:00
// Date/Time
2020-12-08 02:52:54 +00:00
nowDate : now.format(this.getDateFormat()),
nowTime : now.format(this.getTimeFormat()),
now : now.format(this._dateTimeFormat('now')),
2020-11-10 04:32:34 +00:00
// Current process (our Node.js service)
2020-11-22 19:25:19 +00:00
processUptimeSeconds : process.uptime(),
2020-11-10 04:32:34 +00:00
2020-11-10 02:40:55 +00:00
// Totals
2020-11-22 19:25:19 +00:00
totalCalls : StatLog.getSystemStatNum(SysProps.LoginCount),
totalPosts : StatLog.getSystemStatNum(SysProps.MessageTotalCount),
totalUsers : StatLog.getSystemStatNum(SysProps.TotalUserCount),
2020-11-22 19:25:19 +00:00
totalFiles : fileAreaStats.totalFiles || 0,
totalFileBytes : fileAreaStats.totalFileBytes || 0,
// totalUploads :
// totalUploadBytes :
// totalDownloads :
// totalDownloadBytes :
// Today's Stats
callsToday : StatLog.getSystemStatNum(SysProps.LoginsToday),
postsToday : StatLog.getSystemStatNum(SysProps.MessagesToday),
2020-12-08 02:52:54 +00:00
uploadsToday : StatLog.getSystemStatNum(SysProps.FileUlTodayCount),
uploadBytesToday : StatLog.getSystemStatNum(SysProps.FileUlTodayBytes),
downloadsToday : StatLog.getSystemStatNum(SysProps.FileDlTodayCount),
downloadsBytesToday : StatLog.getSystemStatNum(SysProps.FileDlTodayBytes),
newUsersToday : StatLog.getSystemStatNum(SysProps.NewUsersTodayCount),
2020-11-22 19:25:19 +00:00
// Current
2020-12-08 02:52:54 +00:00
currentUserName : this.client.user.username,
currentUserRealName : this.client.user.getProperty(UserProps.RealName) || this.client.user.username,
lastLoginUserName : lastLoginStats.userName,
lastLoginRealName : lastLoginStats.realName,
lastLoginDate : moment(lastLoginStats.timestamp).format(this.getDateFormat()),
lastLoginTime : moment(lastLoginStats.timestamp).format(this.getTimeFormat()),
lastLogin : moment(lastLoginStats.timestamp).format(this._dateTimeFormat('lastLogin')),
2020-11-10 02:40:55 +00:00
totalMemoryBytes : sysMemStats.totalBytes || 0,
freeMemoryBytes : sysMemStats.freeBytes || 0,
systemAvgLoad : sysLoadStats.average || 0,
systemCurrentLoad : sysLoadStats.current || 0,
2020-11-10 04:32:34 +00:00
};
2020-11-28 05:35:03 +00:00
return cb(null);
2020-11-10 02:40:55 +00:00
}
_refreshNodeStatus(cb) {
const nodeStatusView = this.getView('main', MciViewIds.main.nodeStatus);
if (!nodeStatusView) {
return cb(null);
}
const nodeStatusItems = getActiveConnectionList(false)
.slice(0, nodeStatusView.dimens.height)
.map(ac => {
// Handle pre-authenticated
if (!ac.authenticated) {
ac.text = ac.userName = '*Pre Auth*';
ac.action = 'Logging In';
}
2020-11-10 02:40:55 +00:00
return Object.assign(ac, {
timeOn : _.upperFirst((ac.timeOn || moment.duration(0)).humanize()), // make friendly
});
2020-11-10 02:40:55 +00:00
});
nodeStatusView.setItems(nodeStatusItems);
nodeStatusView.redraw();
return cb(null);
}
2020-11-28 05:35:03 +00:00
_refreshQuickLog(cb) {
const quickLogView = this.viewControllers.main.getView(MciViewIds.main.quickLogView);
if (!quickLogView) {
return cb(null);
}
const records = this.logRingBuffer.records;
if (records.length === 0) {
return cb(null);
}
const hasChanged = this.lastLogTime !== records[records.length - 1].time;
this.lastLogTime = records[records.length - 1].time;
if (!hasChanged) {
return cb(null);
}
const quickLogTimestampFormat =
this.config.quickLogTimestampFormat ||
2020-11-28 05:35:03 +00:00
this.getDateTimeFormat('short');
const levelIndicators = this.config.quickLogLevelIndicators ||
{
trace : 'T',
debug : 'D',
info : 'I',
warn : 'W',
error : 'E',
fatal : 'F',
};
2020-11-28 05:35:03 +00:00
const makeLevelIndicator = (level) => {
return levelIndicators[level] || '?';
};
const quickLogLevelMessagePrefixes = this.config.quickLogLevelMessagePrefixes || {};
const prefixMssage = (message, level) => {
const prefix = quickLogLevelMessagePrefixes[level] || '';
return `${prefix}${message}`;
2020-11-28 05:35:03 +00:00
};
const logItems = records.map(rec => {
const level = bunyan.nameFromLevel[rec.level];
2020-11-28 05:35:03 +00:00
return {
timestamp : moment(rec.time).format(quickLogTimestampFormat),
level : rec.level,
levelIndicator : makeLevelIndicator(level),
nodeId : rec.nodeId || '*',
2020-11-28 05:35:03 +00:00
sessionId : rec.sessionId || '',
message : prefixMssage(rec.msg, level),
2020-11-28 05:35:03 +00:00
};
});
quickLogView.setItems(logItems);
quickLogView.redraw();
return cb(null);
}
2020-12-08 02:52:54 +00:00
_dateTimeFormat(element) {
const format = this.config[`${element}DateTimeFormat`];
return format || this.getDateFormat();
}
2020-07-14 03:08:25 +00:00
};