switched everything over to Mongoose

This commit is contained in:
Luke Berndt
2023-04-10 22:51:57 -04:00
parent 0062c404bf
commit 6fbd97bbb6
9 changed files with 211 additions and 259 deletions

View File

@@ -2,7 +2,6 @@ var path = require("path");
var express = require("express"); var express = require("express");
var bodyParser = require("body-parser"); var bodyParser = require("body-parser");
var cookie_domain = process.env['REACT_APP_COOKIE_DOMAIN'] != null ? process.env['REACT_APP_COOKIE_DOMAIN'] : '.openmhz.com'; //'https://s3.amazonaws.com/robotastic';
var backend_server = process.env['REACT_APP_BACKEND_SERVER'] != null ? process.env['REACT_APP_BACKEND_SERVER'] : 'https://api.openmhz.com'; var backend_server = process.env['REACT_APP_BACKEND_SERVER'] != null ? process.env['REACT_APP_BACKEND_SERVER'] : 'https://api.openmhz.com';
var frontend_server = process.env['REACT_APP_FRONTEND_SERVER'] != null ? process.env['REACT_APP_FRONTEND_SERVER'] : 'https://openmhz.com'; var frontend_server = process.env['REACT_APP_FRONTEND_SERVER'] != null ? process.env['REACT_APP_FRONTEND_SERVER'] : 'https://openmhz.com';
var socket_server = process.env['REACT_APP_SOCKET_SERVER'] != null ? process.env['REACT_APP_SOCKET_SERVER'] : 'wss://socket.openmhz.com'; //'https://s3.amazonaws.com/robotastic'; var socket_server = process.env['REACT_APP_SOCKET_SERVER'] != null ? process.env['REACT_APP_SOCKET_SERVER'] : 'wss://socket.openmhz.com'; //'https://s3.amazonaws.com/robotastic';

View File

@@ -1,15 +0,0 @@
/** Important **/
/** You should not be committing this file to GitHub **/
/** Repeat: DO! NOT! COMMIT! THIS! FILE! TO! YOUR! REPO! **/
var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost';
var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : 27017;
var mongoUrl = 'mongodb://' + host + ':' + port + '/scanner';
const secrets = {
db: mongoUrl,
sessionSecret: "letthisbeyoursecret"
}
module.exports = secrets

View File

@@ -1,16 +1,12 @@
const { ObjectId } = require('mongodb'); const { ObjectId } = require('mongodb');
var db = require('../db');
var mongoose = require("mongoose");
var { callModel: Call } = require("../models/call"); var { callModel: Call } = require("../models/call");
var Star = require("../models/star"); const Group = require("../models/group");
var defaultNumResults = 50; var defaultNumResults = 50;
var channels = {}; var channels = {};
async function get_calls(query, numResults, res) { async function get_calls(query, numResults, res) {
var calls = []; var calls = [];
@@ -27,12 +23,9 @@ async function get_calls(query, numResults, res) {
url: true url: true
}; };
const transCollection = db.get().collection('calls');
const sort = { length: -1 }; const sort = { length: -1 };
try { try {
let cursor = transCollection.find(query.filter, fields).sort(sort).limit(numResults); for await (const item of Call.find(query.filter, fields).sort(sort).limit(numResults)) {
await cursor.forEach(function (item) {
call = { call = {
_id: item._id.toHexString(), _id: item._id.toHexString(),
talkgroupNum: item.talkgroupNum, talkgroupNum: item.talkgroupNum,
@@ -45,8 +38,7 @@ async function get_calls(query, numResults, res) {
len: Math.round(item.len) len: Math.round(item.len)
}; };
calls.push(call); calls.push(call);
}
});
res.contentType('json'); res.contentType('json');
res.send(JSON.stringify({ res.send(JSON.stringify({
@@ -105,13 +97,10 @@ async function build_filter(filter_type, code, start_time, direction, shortName,
if (filter_type) { if (filter_type) {
if ((filter_type == "group") && code && (code.indexOf(',') == -1)) { if ((filter_type == "group") && code && (code.indexOf(',') == -1)) {
const groupCollection = db.get().collection("groups");
const group = await groupCollection.findOne({ const group = await Group.findOne({ 'shortName': shortName, '_id': ObjectId.createFromHexString(code)}).exec();
'shortName': shortName,
'_id': ObjectId.createFromHexString(code)
});
if (!group) { if (!group) {
console.warn("[" + shortName + "] Error - build_filter() group is null " + err); console.warn("[" + shortName + "] Error - build_filter() group is null " + err);
res.contentType('json'); res.contentType('json');
@@ -173,8 +162,8 @@ exports.get_card = async function (req, res) {
})); }));
return; return;
} }
const transCollection = db.get().collection('calls');
const item = await transCollection.findOne({ '_id': o_id }); const item = await Call.findById(o_id).exec();
//console.log(util.inspect(item)); //console.log(util.inspect(item));
if (item) { if (item) {
@@ -297,8 +286,7 @@ exports.get_call = async function (req, res) {
})); }));
return; return;
} }
const transCollection = db.get().collection('calls'); const item = await Call.findById(o_id).exec();
const item = await transCollection.findOne({ '_id': o_id });
if (item) { if (item) {
var call = package_call(item); var call = package_call(item);

View File

@@ -1,10 +1,7 @@
var db = require('../db'); const Group = require("../models/group");
exports.get_groups = async function (req, res) { exports.get_groups = async function (req, res) {
const grp_results = await Group.find({ shortName: req.params.shortName.toLowerCase()}).sort("position").exec();
const grp_coll = db.get().collection('groups');
const cursor = grp_coll.find({ 'shortName': req.params.shortName.toLowerCase() });
const grp_results = await cursor.toArray();
res.contentType('json'); res.contentType('json');
res.send(JSON.stringify(grp_results)); res.send(JSON.stringify(grp_results));

View File

@@ -1,9 +1,7 @@
var db = require('../db'); const Talkgroup = require("../models/talkgroup");
exports.get_talkgroups = async function (req, res) { exports.get_talkgroups = async function (req, res) {
const tg_coll = db.get().collection('talkgroups'); const tg_results = await Talkgroup.find({ 'shortName': req.params.shortName.toLowerCase()})
const cursor = tg_coll.find({ 'shortName': req.params.shortName.toLowerCase() })
const tg_results = await cursor.toArray();
var talkgroups = {}; var talkgroups = {};
for (var tg in tg_results) { for (var tg in tg_results) {
talkgroups[tg_results[tg].num] = tg_results[tg]; talkgroups[tg_results[tg].num] = tg_results[tg];

View File

@@ -1,11 +1,8 @@
var MongoClient = require('mongodb').MongoClient; var MongoClient = require('mongodb').MongoClient;
var config = require('./config/config.json');
var test = require('assert');
var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost'; var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost';
var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : 27017; var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : 27017;
var dbUser = process.env['MONGO_TRUNK_FRONTEND_USER'] != null ? process.env['MONGO_TRUNK_FRONTEND_USER'] : null;
var dbPass = process.env['MONGO_TRUNK_FRONTEND_PASS'] != null ? process.env['MONGO_TRUNK_FRONTEND_PASS'] : null;
var state = { var state = {
db: null, db: null,

View File

@@ -1,9 +1,5 @@
var express = require("express"); var express = require("express");
var passport = require("passport");
var util = require("util");
var secrets = require("./config/secrets");
var configureExpress = require("./config/express"); var configureExpress = require("./config/express");
var calls = require("./controllers/calls"); var calls = require("./controllers/calls");
@@ -17,9 +13,8 @@ var config = require('./config/config.json');
var mongoose = require("mongoose"); var mongoose = require("mongoose");
const { ObjectId } = require('mongodb'); const { ObjectId } = require('mongodb');
var db = require('./db'); const Group = require("./models/group");
var System = require("./models/system");
var multer = require('multer'); var multer = require('multer');
// ------------------------------------------- // -------------------------------------------
@@ -51,9 +46,13 @@ configureExpress(app)
// ------------------------------------------- // -------------------------------------------
var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost';
var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : 27017;
var mongoUrl = 'mongodb://' + host + ':' + port + '/scanner';
const connect = () => { const connect = () => {
mongoose.connect(secrets.db).then((result) => { // Successfully connected mongoose.connect(mongoUrl).then((result) => { // Successfully connected
console.log("connected to Mongo"); console.log("connected to Mongo");
}) })
.catch((err) => { .catch((err) => {
@@ -258,32 +257,18 @@ io.sockets.on('connection', function (client) {
clients[client.id].talkgroupNums = []; clients[client.id].talkgroupNums = [];
clients[client.id].timestamp = new Date(); clients[client.id].timestamp = new Date();
if ((data.filterType == "group") && (data.filterCode.indexOf(',') == -1)) { if ((data.filterType == "group") && (data.filterCode.indexOf(',') == -1)) {
const groupCollection = db.get().collection("groups");
if (!groupCollection) {
console.error("Error - unable to open groups collection: " + err);
delete clients[client.id];
return;
}
if (!ObjectId.isValid(data.filterCode)) { if (!ObjectId.isValid(data.filterCode)) {
console.error("Error - Socket - Invalid Group ID: " + data.filterCode); console.error("Error - Socket - Invalid Group ID: " + data.filterCode);
delete clients[client.id]; delete clients[client.id];
return; return;
} }
let group;
try { const group = await Group.findOne({ 'shortName': data.shortName.toLowerCase(), '_id': ObjectId.createFromHexString(data.filterCode) });
group = await groupCollection.findOne({
'shortName': data.shortName.toLowerCase(), if (group) {
'_id': ObjectId.createFromHexString(data.filterCode)
});
} catch (err) {
console.warn("[" + data.shortName.toLowerCase() + "] Error - WebSocket Group ID not Found! Error: " + err + " Group ID: " + data.filterCode);
delete clients[client.id];
return;
}
if (group && clients[client.id]) {
clients[client.id].talkgroupNums = group.talkgroups; clients[client.id].talkgroupNums = group.talkgroups;
} else { } else {
console.error("Error - Socket: Invalid group or Client: " + data.filterCode + " Shortname: " + data.shortName + " ClientID: " + client.id); console.error("Error - Socket: Invalid group " + data.filterCode + " Shortname: " + data.shortName + " ClientID: " + client.id);
delete clients[client.id]; delete clients[client.id];
return; return;
} }
@@ -309,24 +294,14 @@ io.sockets.on('connection', function (client) {
}); });
//console.log("stats: " + util.inspect(call_stats));
// Connect to Mongo on start stats.init_stats();
db.connect(function (err) {
server.listen(app.get("port"), (err) => {
if (err) { if (err) {
console.log('Unable to connect to Mongo.') console.err(err.stack)
process.exit(1)
} else { } else {
stats.init_stats(); console.log(`App listening on port ${app.get("port")} [${process.env.NODE_ENV} mode]`)
server.listen(app.get("port"), (err) => {
if (err) {
console.err(err.stack)
} else {
console.log(`App listening on port ${app.get("port")} [${process.env.NODE_ENV} mode]`)
}
})
} }
}) })

View File

@@ -0,0 +1,27 @@
var mongoose = require('mongoose');
let decodeErrorSchema = mongoose.Schema({
errorHistory: [Number],
spikeHistory: [Number],
})
let talkgroupStatsSchema = mongoose.Schema({
callCountHistory: [Number],
callAvgLenHistory: [Number]
})
var systemStatSchema = mongoose.Schema({
callTotals: [Number],
uploadErrors: [Number],
decodeErrorsFreq: {
type: Map,
of: decodeErrorSchema
},
talkgroupStats: {
type: Map,
of: talkgroupStatsSchema
},
shortName: String
}, { collection: 'system_stats' });
module.exports = mongoose.model('SystemStat', systemStatSchema);

View File

@@ -1,76 +1,65 @@
var util = require("util"); var util = require("util");
var db = require('./db'); var db = require('./db');
const SystemStat = require("./models/system_stat");
var System = require("./models/system");
var talkgroupStats = {}; var talkgroupStats = {};
var callTotals = {}; var callTotals = {};
var uploadErrors = {}; var uploadErrors = {};
let decodeErrorsFreq = {}; let decodeErrorsFreq = {};
const timePeriod = 15; // in minutes const timePeriod = 15; // in minutes
var spots = (24*60) / timePeriod; // the number of spots needed to keep track of 24 hours of stats var spots = (24 * 60) / timePeriod; // the number of spots needed to keep track of 24 hours of stats
async function updateActiveSystems() { async function updateActiveSystems() {
// Go through all of the Systems // Go through all of the Systems
const sysCollection = db.get().collection('systems');
var cursor = sysCollection.find();
await cursor.forEach(function(item) {
// go through all the systems
// if you have recieved some calls during that last period, make the system active
if ((callTotals[item.shortName] != undefined) && (callTotals[item.shortName][0] > 0)) {
const active = true;
const callAvg = callTotals[item.shortName][0] / timePeriod;
const query = { shortName: item.shortName};
const update = { $set: {"active": active,"callAvg": callAvg,"lastActive": new Date() }};
const options = {upsert: true};
sysCollection.updateOne(query, update, options); for await (const item of System.find()) {
// go through all the systems
} else { // if you have recieved some calls during that last period, make the system active
const query = { shortName: item.shortName}; if ((callTotals[item.shortName] != undefined) && (callTotals[item.shortName][0] > 0)) {
const update = { $set: {"active": false, "callAvg": 0}}; item.active = true;
const options = {upsert: true}; item.callAvg = callTotals[item.shortName][0] / timePeriod;
item.lastActive = new Date();
await item.Save();
} else {
item.active = false;
item.callAvg = 0;
await item.save();
}
sysCollection.updateOne(query, update, options); };
}
});
} }
exports.initStats = async function() { exports.initStats = async function () {
// get the System Stats collection // get the System Stats collection
db.get().createCollection("system_stats").catch((err)=>{console.log("System Stats collection is ready")});
const statsCollection = db.get().collection('system_stats');
var cursor = statsCollection.find();
// go through each of the Systems in Stats for await (const item of SystemStat.find()) {
await cursor.forEach(function(item) { // Talkgroup Stats
if (item.talkgroupStats != undefined) {
// Talkgroup Stats talkgroupStats[item.shortName] = item.talkgroupStats;
if (item.talkgroupStats != undefined) { }
talkgroupStats[item.shortName] = item.talkgroupStats;
}
// Decode Errors // Decode Errors
if (item.decodeErrorsFreq != undefined) { if (item.decodeErrorsFreq != undefined) {
decodeErrorsFreq[item.shortName] = item.decodeErrorsFreq; decodeErrorsFreq[item.shortName] = item.decodeErrorsFreq;
} }
// Upload Error Totals // Upload Error Totals
if (item.uploadErrors != undefined) { if (item.uploadErrors != undefined) {
uploadErrors[item.shortName] = item.uploadErrors; uploadErrors[item.shortName] = item.uploadErrors;
} }
if (item.callTotals != undefined) { if (item.callTotals != undefined) {
callTotals[item.shortName] = item.callTotals; callTotals[item.shortName] = item.callTotals;
} }
}); };
} }
// keeps track of the number of calls that get uploaded with an audio file // keeps track of the number of calls that get uploaded with an audio file
exports.addError = function(call) { exports.addError = function (call) {
// if there is no Array associated with the system. // if there is no Array associated with the system.
if (uploadErrors[call.shortName] == undefined) { if (uploadErrors[call.shortName] == undefined) {
@@ -85,10 +74,7 @@ exports.addError = function(call) {
} }
// Keeps track of the number of calls for each talkgroup for a system // Keeps track of the number of calls for each talkgroup for a system
exports.addCall = function(call) { exports.addCall = function (call) {
// if you haven't started keeping track of stats for the System yet // if you haven't started keeping track of stats for the System yet
if (talkgroupStats[call.shortName] == undefined) { if (talkgroupStats[call.shortName] == undefined) {
talkgroupStats[call.shortName] = {}; talkgroupStats[call.shortName] = {};
@@ -139,147 +125,147 @@ exports.addCall = function(call) {
// This gets called when a Time Period is up // This gets called when a Time Period is up
exports.shiftStats = async function() { exports.shiftStats = async function () {
const statsCollection = db.get().collection('system_stats');
// for all the systems in Error Stats
for (var shortName in uploadErrors) {
if (uploadErrors.hasOwnProperty(shortName)) {
// Update the DB with Error Stats and Error Totals // for all the systems in Error Stats
const query = { shortName: shortName}; for (var shortName in uploadErrors) {
const update = { $set: { "uploadErrors": uploadErrors[shortName]}}; if (uploadErrors.hasOwnProperty(shortName)) {
const options = {upsert: true};
statsCollection.updateOne(query, update, options); // Update the DB with Error Stats and Error Totals
// move everything back one after updating const query = { shortName: shortName };
for (var j = spots - 1; j > 0; j--) { const update = { $set: { "uploadErrors": uploadErrors[shortName] } };
uploadErrors[shortName][j] = uploadErrors[shortName][j - 1]; const options = { upsert: true };
}
// reset the first spot back to 0, so you can count the next period await SystemStat.updateOne(query, update, options);
uploadErrors[shortName][0] = 0; // move everything back one after updating
for (var j = spots - 1; j > 0; j--) {
uploadErrors[shortName][j] = uploadErrors[shortName][j - 1];
} }
// reset the first spot back to 0, so you can count the next period
uploadErrors[shortName][0] = 0;
} }
}
// for each system in decodeErrorsFreq
for (let shortName in decodeErrorsFreq) {
// if the system is in decodeErrorsFreq // for each system in decodeErrorsFreq
if (decodeErrorsFreq.hasOwnProperty(shortName)) { for (let shortName in decodeErrorsFreq) {
var sysErrors = decodeErrorsFreq[shortName];
// for each freq in that systems stats // if the system is in decodeErrorsFreq
for (var freqNum in sysErrors ) { if (decodeErrorsFreq.hasOwnProperty(shortName)) {
if (sysErrors.hasOwnProperty(freqNum)) { var sysErrors = decodeErrorsFreq[shortName];
var freqErrors = sysErrors[freqNum];
// move the history for that freq back // for each freq in that systems stats
for (let j = spots - 1; j > 0; j--) { for (var freqNum in sysErrors) {
let i = j - 1; if (sysErrors.hasOwnProperty(freqNum)) {
freqErrors.errorHistory[j] = freqErrors.errorHistory[i]; var freqErrors = sysErrors[freqNum];
freqErrors.spikeHistory[j] = freqErrors.spikeHistory[i];
}
if (freqErrors.totalLen > 0) { // move the history for that freq back
freqErrors.errorHistory[0] = (freqErrors.errors / freqErrors.totalLen); for (let j = spots - 1; j > 0; j--) {
freqErrors.spikeHistory[0] = (freqErrors.spikes / freqErrors.totalLen); let i = j - 1;
} else { freqErrors.errorHistory[j] = freqErrors.errorHistory[i];
freqErrors.errorHistory[0] = 0; freqErrors.spikeHistory[j] = freqErrors.spikeHistory[i];
freqErrors.spikeHistory[0] = 0; }
}
freqErrors.totalLen = 0; if (freqErrors.totalLen > 0) {
freqErrors.errors = 0; freqErrors.errorHistory[0] = (freqErrors.errors / freqErrors.totalLen);
freqErrors.spikes = 0; freqErrors.spikeHistory[0] = (freqErrors.spikes / freqErrors.totalLen);
} else {
freqErrors.errorHistory[0] = 0;
freqErrors.spikeHistory[0] = 0;
}
freqErrors.totalLen = 0;
freqErrors.errors = 0;
freqErrors.spikes = 0;
}
}
const query = { shortName: shortName };
const update = { $set: { "decodeErrorsFreq": decodeErrorsFreq[shortName] } };
const options = { upsert: true };
await SystemStat.updateOne(query, update, options);
}
}
// for each system in talkgroupStats
for (let shortName in talkgroupStats) {
let callTotal = 0;
// if the system is in stats
if (talkgroupStats.hasOwnProperty(shortName)) {
var sysTalkgroupStats = talkgroupStats[shortName];
// for each talkgroup in that systems stats
for (var talkgroupNum in sysTalkgroupStats) {
if (sysTalkgroupStats.hasOwnProperty(talkgroupNum)) {
var tg = sysTalkgroupStats[talkgroupNum];
var tgHistoryTotal = 0;
// move the history for that talkgroup back
for (let j = spots - 1; j > 0; j--) {
let i = j - 1;
tgHistoryTotal += tg.callCountHistory[i];
tg.callCountHistory[j] = tg.callCountHistory[i];
tg.callAvgLenHistory[j] = tg.callAvgLenHistory[i];
}
// add to the total for that group
callTotal += tg.calls;
// figure out the history for current period in the history for this talkgroup;
tg.callCountHistory[0] = tg.calls;
tgHistoryTotal += tg.calls;
if (tg.calls > 0) {
tg.callAvgLenHistory[0] = Math.floor(tg.totalLen / tg.calls);
} else {
tg.callAvgLenHistory[0] = 0;
}
tg.calls = 0;
tg.totalLen = 0;
if (tgHistoryTotal == 0) {
// there has been no recent activity on this talkgroup. remove it from the stats.
delete stat[talkgroupNum];
} }
} }
const query = { shortName: shortName};
const update = { $set: { "decodeErrorsFreq": decodeErrorsFreq[shortName]}};
const options = {upsert: true};
statsCollection.updateOne(query, update, options);
} }
}
// figure out call totals for this shortName/Sys
// for each system in talkgroupStats if (callTotals[shortName] == undefined) {
for (let shortName in talkgroupStats) { callTotals[shortName] = new Array();
let callTotal = 0; for (var j = 0; j < spots; j++) {
callTotals[shortName][j] = 0;
// if the system is in stats
if (talkgroupStats.hasOwnProperty(shortName)) {
var sysTalkgroupStats = talkgroupStats[shortName];
// for each talkgroup in that systems stats
for (var talkgroupNum in sysTalkgroupStats ) {
if (sysTalkgroupStats.hasOwnProperty(talkgroupNum)) {
var tg = sysTalkgroupStats[talkgroupNum];
var tgHistoryTotal = 0;
// move the history for that talkgroup back
for (let j = spots - 1; j > 0; j--) {
let i = j - 1;
tgHistoryTotal += tg.callCountHistory[i];
tg.callCountHistory[j] = tg.callCountHistory[i];
tg.callAvgLenHistory[j] = tg.callAvgLenHistory[i];
}
// add to the total for that group
callTotal += tg.calls;
// figure out the history for current period in the history for this talkgroup;
tg.callCountHistory[0] = tg.calls;
tgHistoryTotal += tg.calls;
if (tg.calls > 0) {
tg.callAvgLenHistory[0] = Math.floor(tg.totalLen / tg.calls);
} else {
tg.callAvgLenHistory[0] = 0;
}
tg.calls = 0;
tg.totalLen = 0;
if (tgHistoryTotal ==0 ) {
// there has been no recent activity on this talkgroup. remove it from the stats.
delete stat[talkgroupNum];
}
}
} }
// figure out call totals for this shortName/Sys
if (callTotals[shortName] == undefined) {
callTotals[shortName] = new Array();
for (var j = 0; j < spots; j++) {
callTotals[shortName][j] = 0;
}
}
for (var j = spots - 1; j > 0; j--) {
callTotals[shortName][j] = callTotals[shortName][j - 1];
}
callTotals[shortName][0] = callTotal;
const query = { shortName: shortName};
const update = { $set: { "talkgroupStats": talkgroupStats[shortName], "callTotals": callTotals[shortName] }};
const options = {upsert: true};
statsCollection.updateOne(query, update, options);
} }
for (var j = spots - 1; j > 0; j--) {
callTotals[shortName][j] = callTotals[shortName][j - 1];
}
callTotals[shortName][0] = callTotal;
const query = { shortName: shortName };
const update = { $set: { "talkgroupStats": talkgroupStats[shortName], "callTotals": callTotals[shortName] } };
const options = { upsert: true };
await SystemStat.updateOne(query, update, options);
} }
}
updateActiveSystems(); updateActiveSystems();
} }
exports.callTotals = function(shortName) { exports.callTotals = function (shortName) {
return callTotals[shortName]; return callTotals[shortName];
} }
exports.talkgroupStats = function(shortName) { exports.talkgroupStats = function (shortName) {
return talkgroupStats[shortName]; return talkgroupStats[shortName];
} }
exports.uploadErrors = function(shortName) { exports.uploadErrors = function (shortName) {
return uploadErrors[shortName]; return uploadErrors[shortName];
} }
exports.decodeErrorsFreq = function(shortName) { exports.decodeErrorsFreq = function (shortName) {
return decodeErrorsFreq[shortName]; return decodeErrorsFreq[shortName];
} }