mirror of
https://github.com/openmhz/trunk-server.git
synced 2026-11-13 01:07:42 -05:00
First Commit
This commit is contained in:
386
backend/controllers/calls.js
Normal file
386
backend/controllers/calls.js
Normal file
@@ -0,0 +1,386 @@
|
||||
|
||||
var ObjectID = require('mongodb').ObjectID;
|
||||
var db = require('../db');
|
||||
var mongoose = require("mongoose");
|
||||
var Call = require("../models/call");
|
||||
var Star = require("../models/star");
|
||||
|
||||
var defaultNumResults = 50;
|
||||
|
||||
|
||||
var channels = {};
|
||||
|
||||
|
||||
function get_calls(query, numResults, res) {
|
||||
|
||||
var calls = [];
|
||||
var fields = {
|
||||
_id: true,
|
||||
talkgroupNum: true,
|
||||
path: true,
|
||||
name: true,
|
||||
time: true,
|
||||
srcList: true,
|
||||
star: true,
|
||||
len: true,
|
||||
url: true
|
||||
};
|
||||
|
||||
db.get().collection('calls', function(err, transCollection) {
|
||||
transCollection.find(query.filter, fields, function(err, cursor) {
|
||||
if (err) {
|
||||
console.warn("Error - get_calls() Could not find item " + err + " filter: " + query.filter);
|
||||
res.send(404, 'Sorry, we cannot find that!');
|
||||
return;
|
||||
}
|
||||
cursor.sort(query.sort_order).limit(numResults).each(function(err, item) {
|
||||
if (item) {
|
||||
call = {
|
||||
_id: item._id.toHexString(),
|
||||
talkgroupNum: item.talkgroupNum,
|
||||
url: item.url,
|
||||
filename: item.path + item.name,
|
||||
time: item.time,
|
||||
srcList: item.srcList,
|
||||
star: item.star,
|
||||
len: Math.round(item.len)
|
||||
};
|
||||
calls.push(call);
|
||||
} else {
|
||||
res.contentType('json');
|
||||
res.send(JSON.stringify({
|
||||
calls: calls,
|
||||
direction: query.direction
|
||||
}));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
function build_filter(filter_type, code, start_time, direction, shortName, numResults, starred, res) {
|
||||
var filter = {};
|
||||
var query = {};
|
||||
var FilterType = {
|
||||
All: 0,
|
||||
Talkgroup: 1,
|
||||
Group: 2,
|
||||
Unit: 3
|
||||
};
|
||||
/* removed to see if it helps queries
|
||||
if (starred) {
|
||||
filter.star = {
|
||||
$gt: 0
|
||||
};
|
||||
}*/
|
||||
|
||||
if (start_time) {
|
||||
var start = new Date(start_time);
|
||||
if (direction == 'newer') {
|
||||
filter.time = {
|
||||
$gt: start
|
||||
};
|
||||
} else {
|
||||
filter.time = {
|
||||
$lt: start
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
filter.len = {
|
||||
$gte: -1.0
|
||||
};*/
|
||||
|
||||
|
||||
var sort_order = {};
|
||||
if (direction == 'newer') {
|
||||
sort_order['time'] = 1;
|
||||
} else {
|
||||
sort_order['time'] = -1;
|
||||
}
|
||||
|
||||
// make sure the shortName for the system is included in the query
|
||||
filter.shortName = shortName;
|
||||
|
||||
query['direction'] = direction;
|
||||
query['sort_order'] = sort_order;
|
||||
|
||||
if (filter_type) {
|
||||
if ((filter_type == "group") && code && (code.indexOf(',') == -1)) {
|
||||
db.get().collection("groups", function(err, groupCollection) {
|
||||
if (err || !groupCollection) {
|
||||
console.warn("[" + shortName + "] Error - build_filter() Group Collection does not exist " + err);
|
||||
res.contentType('json');
|
||||
res.send(JSON.stringify( {
|
||||
message: 'That Group ID doesnt exist.'
|
||||
}));
|
||||
return;
|
||||
}
|
||||
groupCollection.findOne({
|
||||
'shortName': shortName,
|
||||
'_id': ObjectID.createFromHexString(code)
|
||||
}, function(err, group) {
|
||||
if (err) {
|
||||
console.warn("[" + shortName + "] Error - build_filter() Group ID does not exist " + err);
|
||||
res.contentType('json');
|
||||
res.send(JSON.stringify( {
|
||||
message: 'That Group ID doesnt exist.'
|
||||
}));
|
||||
} else if (!group) {
|
||||
console.warn("[" + shortName + "] Error - build_filter() group is null " + err);
|
||||
res.contentType('json');
|
||||
res.send(JSON.stringify({
|
||||
message: 'That Group ID doesnt exist.'
|
||||
}));
|
||||
} else{
|
||||
filter.talkgroupNum = {
|
||||
$in: group.talkgroups
|
||||
};
|
||||
query['filter'] = filter;
|
||||
|
||||
get_calls(query, numResults, res);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
if ((filter_type == "talkgroup") || (filter_type == "group")) {
|
||||
if (code) {
|
||||
var codeArray = code.split(',').map(function(item) {
|
||||
return parseInt(item, 10);
|
||||
});
|
||||
filter.talkgroupNum = {
|
||||
$in: codeArray
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (filter_type == "unit") {
|
||||
if (code) {
|
||||
var codeArray = code.split(',').map(function(item) {
|
||||
return parseInt(item, 10);
|
||||
});
|
||||
filter.srcListv = {
|
||||
$in: codeArray
|
||||
};
|
||||
}
|
||||
}
|
||||
query['filter'] = filter;
|
||||
|
||||
get_calls(query, numResults, res);
|
||||
}
|
||||
} else {
|
||||
query['filter'] = filter;
|
||||
get_calls(query, numResults, res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exports.get_card = function(req, res) {
|
||||
var objectId = req.params.id;
|
||||
try {
|
||||
var o_id = ObjectID.createFromHexString(objectId);
|
||||
} catch (err) {
|
||||
console.warn("Error - /card/:id generating ObjectID " + err);
|
||||
res.status(500);
|
||||
res.send(JSON.stringify({
|
||||
error: err,
|
||||
"_id": objectId
|
||||
}));
|
||||
return;
|
||||
}
|
||||
db.get().collection('calls', function(err, transCollection) {
|
||||
transCollection.findOne({
|
||||
'_id': o_id
|
||||
},
|
||||
function(err, item) {
|
||||
//console.log(util.inspect(item));
|
||||
if (item) {
|
||||
var time = new Date(item.time);
|
||||
var timeString = time.toLocaleTimeString("en-US");
|
||||
var dateString = time.toDateString();
|
||||
res.render('card', {
|
||||
item: item,
|
||||
channel: channels[item.talkgroupNum],
|
||||
time: timeString,
|
||||
date: dateString
|
||||
});
|
||||
} else {
|
||||
console.warn("Error - /card/:id Could not find Item " + err);
|
||||
res.send(404, 'Sorry, we cannot find that!');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function package_call(item) {
|
||||
var time = new Date(item.time);
|
||||
var timeString = time.toLocaleTimeString("en-US");
|
||||
var dateString = time.toDateString();
|
||||
call = {
|
||||
_id: item._id.toHexString(),
|
||||
shortName: item.shortName,
|
||||
talkgroupNum: item.talkgroupNum,
|
||||
filename: item.path + item.name,
|
||||
url: item.url,
|
||||
time: item.time,
|
||||
timeString: timeString,
|
||||
dateString: dateString,
|
||||
path: item.path,
|
||||
name: item.name,
|
||||
freq: item.freq,
|
||||
srcList: item.srcList,
|
||||
freqList: item.freqList,
|
||||
star: item.star,
|
||||
len: Math.round(item.len)
|
||||
};
|
||||
return call;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
exports.add_star = function(req, res, next) {
|
||||
var objectId = req.params.id;
|
||||
try {
|
||||
var o_id = ObjectID.createFromHexString(objectId);
|
||||
} catch (err) {
|
||||
console.warn("[" + req.params.shortName + "] Error - /:shortName/call/:id generating ObjectID " + err);
|
||||
res.status(500);
|
||||
res.send(JSON.stringify({
|
||||
success: false,
|
||||
message: err,
|
||||
"_id": objectId
|
||||
}));
|
||||
return;
|
||||
}
|
||||
Call.findOneAndUpdate({ _id: objectId }, { $inc: { star: 1 } }, {new: true },function(err, item) {
|
||||
if (err) {
|
||||
res.status(500);
|
||||
res.send(JSON.stringify({
|
||||
success: false,
|
||||
message: err,
|
||||
"_id": objectId
|
||||
}));
|
||||
} else {
|
||||
var call = package_call(item);
|
||||
req.call = call;
|
||||
res.send(JSON.stringify({
|
||||
success: true,
|
||||
call: call
|
||||
}));
|
||||
next();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
exports.get_call = function(req, res) {
|
||||
var objectId = req.params.id;
|
||||
try {
|
||||
var o_id = ObjectID.createFromHexString(objectId);
|
||||
} catch (err) {
|
||||
console.warn("[" + req.params.shortName + "] Error - /:shortName/call/:id generating ObjectID " + err);
|
||||
res.status(500);
|
||||
res.send(JSON.stringify({
|
||||
success: false,
|
||||
error: err,
|
||||
"_id": objectId
|
||||
}));
|
||||
return;
|
||||
}
|
||||
db.get().collection('calls', function(err, transCollection) {
|
||||
transCollection.findOne({
|
||||
'_id': o_id
|
||||
},
|
||||
function(err, item) {
|
||||
if (item) {
|
||||
var call = package_call(item);
|
||||
res.contentType('json');
|
||||
res.send(JSON.stringify({
|
||||
success: true,
|
||||
call: call})
|
||||
);
|
||||
|
||||
} else {
|
||||
console.warn("[" + req.params.shortName + "] Error - /:shortName/call/:id Could not find item " + err + " ID: " + objectId);
|
||||
res.status(404);
|
||||
res.send(JSON.stringify({
|
||||
success: false,
|
||||
error: err,
|
||||
"_id": objectId
|
||||
}));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
exports.get_latest_calls = function(req, res) {
|
||||
var filter_code = req.query["filter-code"];
|
||||
var filter_type = req.query["filter-type"];
|
||||
var starred = req.query["filter-starred"] === 'true'?true:false;
|
||||
var short_name = req.params.shortName.toLowerCase();
|
||||
//console.log("[" + short_name + "] Latest - Call Get Filter code: " + filter_code + " Filter Type: " + filter_type );
|
||||
|
||||
build_filter(filter_type, filter_code, null, 'older', short_name, 1, starred, res);
|
||||
}
|
||||
|
||||
|
||||
exports.get_next_calls = function(req, res) {
|
||||
var filter_code = req.query["filter-code"];
|
||||
var filter_type = req.query["filter-type"];
|
||||
var starred = req.query["filter-starred"] === 'true'?true:false;
|
||||
var start_time = parseInt(req.query["time"]);
|
||||
var short_name = req.params.shortName.toLowerCase();
|
||||
//console.log("[" + short_name + "] Next Calls - time: " + start_time + " Filter code: " + filter_code + " Filter Type: " + filter_type);
|
||||
|
||||
build_filter(filter_type, filter_code, start_time, 'newer', short_name, 1, starred, res);
|
||||
}
|
||||
|
||||
exports.get_newer_calls = function(req, res) {
|
||||
var filter_code = req.query["filter-code"];
|
||||
var filter_type = req.query["filter-type"];
|
||||
var starred = req.query["filter-starred"] === 'true'?true:false;
|
||||
var start_time = parseInt(req.query["time"]);
|
||||
var short_name = req.params.shortName.toLowerCase();
|
||||
//console.log("[" + short_name + "] Newer Calls - time: " + start_time + " Filter code: " + filter_code + " Filter Type: " + filter_type );
|
||||
|
||||
build_filter(filter_type, filter_code, start_time, 'newer', short_name, defaultNumResults, starred, res);
|
||||
}
|
||||
|
||||
exports.get_older_calls = function(req, res) {
|
||||
var filter_code = req.query["filter-code"];
|
||||
var filter_type = req.query["filter-type"];
|
||||
var starred = req.query["filter-starred"] === 'true'?true:false;
|
||||
var start_time = parseInt(req.query["time"]);
|
||||
var short_name = req.params.shortName.toLowerCase();
|
||||
//console.log("[" + short_name + "] Older Calls - time: " + start_time + " Filter code: " + filter_code + " Filter Type: " + filter_type);
|
||||
|
||||
build_filter(filter_type, filter_code, start_time, 'older', short_name, defaultNumResults, starred, res);
|
||||
}
|
||||
|
||||
|
||||
//Delete this after I fix the iPhone app
|
||||
exports.get_iphone_calls = function(req, res) {
|
||||
var filter_code = req.query["filter-code"];
|
||||
var filter_type = req.query["filter-type"];
|
||||
var starred = req.query["filter-starred"] === 'true'?true:false;
|
||||
var start_time = parseInt(req.params.time);
|
||||
var short_name = req.params.shortName.toLowerCase();
|
||||
//console.log("[" + short_name + "] iPhone Newer Calls - time: " + start_time + " Filter code: " + filter_code + " Filter Type: " + filter_type);
|
||||
|
||||
build_filter(filter_type, filter_code, start_time, 'older', short_name, defaultNumResults, starred, res);
|
||||
}
|
||||
|
||||
exports.get_calls = function(req, res) {
|
||||
var filter_code = req.query["filter-code"];
|
||||
var filter_type = req.query["filter-type"];
|
||||
var starred = req.query["filter-starred"] === 'true'?true:false;
|
||||
var short_name = req.params.shortName.toLowerCase();
|
||||
//console.log("[" + short_name + "] Inital Calls - Call Get Filter code: " + filter_code + " Filter Type: " + filter_type);
|
||||
|
||||
build_filter(filter_type, filter_code, null, 'older', short_name, defaultNumResults, starred, res);
|
||||
}
|
||||
12
backend/controllers/groups.js
Normal file
12
backend/controllers/groups.js
Normal file
@@ -0,0 +1,12 @@
|
||||
var db = require('../db');
|
||||
|
||||
exports.get_groups = function(req, res) {
|
||||
db.get().collection('groups', function(err, grp_coll) {
|
||||
grp_coll.find({
|
||||
'shortName': req.params.shortName.toLowerCase()
|
||||
}).toArray(function(err, grp_results) {
|
||||
res.contentType('json');
|
||||
res.send(JSON.stringify(grp_results));
|
||||
});
|
||||
});
|
||||
}
|
||||
146
backend/controllers/sources.js
Normal file
146
backend/controllers/sources.js
Normal file
@@ -0,0 +1,146 @@
|
||||
var sources = {};
|
||||
var pendingSources = {};
|
||||
var mongo = require('mongodb');
|
||||
var ObjectID = require('mongodb').ObjectID;
|
||||
mongo.BSONPure = require('bson').BSONPure;
|
||||
var BSON = mongo.BSONPure;
|
||||
|
||||
|
||||
function getPendingSources(shortName, callback) {
|
||||
var sources = [];
|
||||
var count = 0;
|
||||
db.get().collection('pending_sources', function(err, collection) {
|
||||
collection.find({
|
||||
'shortName': shortName
|
||||
}).count(function(err, total) {
|
||||
var cursor = collection.find({
|
||||
'shortName': shortName
|
||||
});
|
||||
cursor.each(function(err, item) {
|
||||
|
||||
if (item != null) {
|
||||
|
||||
var sourceColl = db.collection('source_names');
|
||||
|
||||
sourceColl.find({
|
||||
'sourceId': item.sourceId,
|
||||
'shortName': shortName
|
||||
}).toArray(function(err, existingSources) {
|
||||
|
||||
var source = {
|
||||
objectId: item._id.toHexString(),
|
||||
sourceId: item.sourceId,
|
||||
name: item.name,
|
||||
codeName: item.codeName,
|
||||
callId: item.callId,
|
||||
time: item.time,
|
||||
existingSources: existingSources
|
||||
};
|
||||
sources.push(source);
|
||||
count++;
|
||||
if (count == total) {
|
||||
callback(sources);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function insertPendingSource(shortName, sourceItem, res) {
|
||||
db.get().collection('pending_sources', function(err, sourceNameCollection) {
|
||||
sourceNameCollection.insert(sourceItem, function(err, result) {
|
||||
if (err) {
|
||||
console.warn(err.message);
|
||||
res.status(404);
|
||||
res.send({
|
||||
error: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
getPendingSources(shortName, function(sources) {
|
||||
|
||||
console.log("sending: " + util.inspect(sources));
|
||||
|
||||
res.send(JSON.stringify({
|
||||
sources: sources,
|
||||
source: sourceItem,
|
||||
result: result.result
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function updatePendingSource(shortName, sourceItem, filter, res) {
|
||||
db.get().collection('pending_sources', function(err, sourceNameCollection) {
|
||||
sourceNameCollection.updateOne(filter, sourceItem, {
|
||||
upsert: true
|
||||
}, function(err, result) {
|
||||
if (err) {
|
||||
console.warn(err.message);
|
||||
res.status(404);
|
||||
res.send({
|
||||
error: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
getPendingSources(shortName, function(sources) {
|
||||
res.send(JSON.stringify({
|
||||
sources: sources,
|
||||
source: sourceItem,
|
||||
result: result.result
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
app.post('/:shortName/pending_sources', function(req, res) {
|
||||
|
||||
|
||||
res.contentType('json');
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
if (req.body) {
|
||||
var sourceId = req.body.sourceId;
|
||||
if (!isNaN(sourceId) && (sourceId > 0)) {
|
||||
var filter = {};
|
||||
var name = req.body.name;
|
||||
var codeName = req.body.codeName;
|
||||
var call = req.body.call;
|
||||
var time = new Date();
|
||||
|
||||
if (name) {
|
||||
name = name.replace(/[^\w\s]/gi, '');
|
||||
}
|
||||
if (codeName) {
|
||||
codeName = codeName.replace(/[^\w]/gi, '');
|
||||
}
|
||||
var sourceItem = {
|
||||
sourceId: sourceId,
|
||||
name: name,
|
||||
codeName: codeName,
|
||||
time: time
|
||||
};
|
||||
|
||||
if (call) {
|
||||
sourceItem.call = new BSON.ObjectID(call);
|
||||
}
|
||||
|
||||
if (name && codeName) {
|
||||
|
||||
if (req.body.objectId) {
|
||||
filter._id = ObjectID.createFromHexString(req.body.objectId);
|
||||
updatePendingSource(req.params.shortName.toLowerCase(), sourceItem, filter, res);
|
||||
} else {
|
||||
insertPendingSource(req.params.shortName.toLowerCase(), sourceItem, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
95
backend/controllers/stats.js
Normal file
95
backend/controllers/stats.js
Normal file
@@ -0,0 +1,95 @@
|
||||
|
||||
var db = require('../db');
|
||||
var schedule = require('node-schedule');
|
||||
var sysStats = require("../sys_stats");
|
||||
|
||||
exports.init_stats = function() {
|
||||
sysStats.initStats();
|
||||
}
|
||||
|
||||
exports.get_errors = function(req, res) {
|
||||
var short_name = req.params.shortName.toLowerCase();
|
||||
|
||||
var start = new Date();
|
||||
start.setHours(start.getHours() - 1);
|
||||
var collection = db.get().collection("calls");
|
||||
collection.aggregate([{
|
||||
$match: {
|
||||
time: {
|
||||
$gte: start
|
||||
},
|
||||
shortName: short_name
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"$unwind": "$freqList"
|
||||
},
|
||||
{
|
||||
"$project": {
|
||||
"freqList": 1,
|
||||
"errorRatio": {
|
||||
$cond: [{
|
||||
$eq: ["$freqList.len", 0]
|
||||
}, 0, {
|
||||
"$multiply": [{
|
||||
"$divide": ["$freqList.error", "$freqList.len"]
|
||||
}, 100]
|
||||
}]
|
||||
},
|
||||
"time": "$time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"$group": {
|
||||
"_id": "$freqList.freq",
|
||||
"values": {
|
||||
"$push": {
|
||||
"time": "$time",
|
||||
"errors": "$errorRatio",
|
||||
"spikes": "$freqList.spikes"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
$sort: {
|
||||
_id: -1
|
||||
}
|
||||
}
|
||||
], function(err, results) {
|
||||
if (err) {
|
||||
console.warn("Error with error stats: " + util.inspect(req.params) + " err: " + err);
|
||||
res.status(500);
|
||||
res.send("Error with error stats: " + util.inspect(req.params) + " err: " + err);
|
||||
} else {
|
||||
res.contentType('json');
|
||||
res.send(JSON.stringify(results));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
exports.get_stats = function(req, res) {
|
||||
var short_name = req.params.shortName.toLowerCase();
|
||||
|
||||
var callHistory = sysStats.callHistory(short_name);
|
||||
var tgHistory = sysStats.tgHistory(short_name);
|
||||
var errorTotals = sysStats.errorTotals(short_name);
|
||||
if (callHistory && tgHistory) {
|
||||
res.contentType('json');
|
||||
res.send(JSON.stringify({
|
||||
callHistory: callHistory,
|
||||
tgHistory: tgHistory,
|
||||
errorTotals: errorTotals
|
||||
}));
|
||||
} else {
|
||||
console.log("ShortName didn't exist for stats: " + util.inspect(req.params));
|
||||
res.status(500);
|
||||
res.send("ShortName didn't exist for stats");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var statSched = schedule.scheduleJob('*/15 * * * *', function() {
|
||||
sysStats.shiftStats();
|
||||
});
|
||||
51
backend/controllers/systems.js
Normal file
51
backend/controllers/systems.js
Normal file
@@ -0,0 +1,51 @@
|
||||
var mongoose = require("mongoose");
|
||||
var User = require("../models/user");
|
||||
var System = require("../models/system");
|
||||
|
||||
exports.get_systems = function (req, res) {
|
||||
System.find().populate('userId', "screenName").
|
||||
exec(function (err, results) {
|
||||
if (err) {
|
||||
console.error("Error - get_systems: " + err.message);
|
||||
res.json({
|
||||
success: false,
|
||||
message: err
|
||||
});
|
||||
return;
|
||||
}
|
||||
var systemList = [];
|
||||
for (var result in results) {
|
||||
|
||||
var clientCount = 0;
|
||||
if (req.systemClients.hasOwnProperty(results[result].shortName)) {
|
||||
clientCount = req.systemClients[results[result].shortName];
|
||||
}
|
||||
var system = {
|
||||
name: results[result].name,
|
||||
shortName: results[result].shortName,
|
||||
systemType: results[result].systemType,
|
||||
county: results[result].count,
|
||||
country: results[result].country,
|
||||
city: results[result].city,
|
||||
state: results[result].state,
|
||||
active: results[result].active,
|
||||
callAvg: results[result].callAvg,
|
||||
description: results[result].description,
|
||||
planType: results[result].planType,
|
||||
clientCount: clientCount
|
||||
}
|
||||
if (results[result].showScreenName && results[result].userId) {
|
||||
system.screenName = results[result].userId.screenName
|
||||
} else {
|
||||
system.screenName = null;
|
||||
}
|
||||
systemList.push(system);
|
||||
}
|
||||
res.contentType('json');
|
||||
res.send(JSON.stringify({
|
||||
success: true,
|
||||
systems: systemList
|
||||
}));
|
||||
});
|
||||
|
||||
}
|
||||
18
backend/controllers/talkgroups.js
Normal file
18
backend/controllers/talkgroups.js
Normal file
@@ -0,0 +1,18 @@
|
||||
var db = require('../db');
|
||||
|
||||
exports.get_talkgroups = function(req, res) {
|
||||
db.get().collection('talkgroups', function(err, tg_coll) {
|
||||
tg_coll.find({
|
||||
'shortName': req.params.shortName.toLowerCase()
|
||||
}).toArray(function(err, tg_results) {
|
||||
var talkgroups = {};
|
||||
for (var tg in tg_results) {
|
||||
talkgroups[tg_results[tg].num] = tg_results[tg];
|
||||
}
|
||||
res.contentType('json');
|
||||
res.send(JSON.stringify({
|
||||
talkgroups: talkgroups
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
277
backend/controllers/uploads.js
Normal file
277
backend/controllers/uploads.js
Normal file
@@ -0,0 +1,277 @@
|
||||
var db = require('../db');
|
||||
var mkdirp = require('mkdirp');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var sysStats = require("../sys_stats");
|
||||
var probe = require('node-ffprobe');
|
||||
var mongoose = require("mongoose");
|
||||
var System = require("../models/system");
|
||||
var Talkgroup = require("../models/talkgroup");
|
||||
var Group = require("../models/group");
|
||||
var Call = require("../models/call");
|
||||
var secrets = require("../config/secrets");
|
||||
var util = require("util")
|
||||
var config = require('../config/config.json');
|
||||
|
||||
var media_server = process.env['MEDIA_SERVER'] != null ? process.env['MEDIA_SERVER'] : 'https://media.openmhz.com';
|
||||
var s3_endpoint = process.env['S3_ENDPOINT'] != null ? process.env['S3_ENDPOINT'] : 's3.us-west-1.wasabisys.com';
|
||||
var s3_profile = process.env['S3_PROFILE'] != null ? process.env['S3_PROFILE'] : 'wasabi-account';
|
||||
|
||||
const wasabi = require('aws-sdk');
|
||||
|
||||
const wasabiEndpoint = new wasabi.Endpoint(s3_endpoint);
|
||||
var wasabiCredentials = new wasabi.SharedIniFileCredentials({
|
||||
profile: s3_profile
|
||||
});
|
||||
wasabi.config.credentials = wasabiCredentials;
|
||||
const wasabiS3 = new wasabi.S3({
|
||||
endpoint: wasabiEndpoint,
|
||||
maxRetries: 0
|
||||
});
|
||||
|
||||
async function callLength(file) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
probe(file, function(err, probeData) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(Math.round(probeData.format.duration));
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
exports.upload = function(req, res, next) {
|
||||
process.nextTick(function() {
|
||||
|
||||
|
||||
|
||||
/** When using the "single"
|
||||
data come in "req.file" regardless of the attribute "name". **/
|
||||
var tmp_path = req.file.path;
|
||||
|
||||
/** The original name of the uploaded file
|
||||
stored in the variable "originalname". **/
|
||||
var target_path = 'uploads/' + req.file.originalname;
|
||||
|
||||
if (!req.file && (path.extname(req.file.originalname)) != '.m4a') {
|
||||
console.warn("[" + req.params.shortName + "] Error file name is wrong or file does not exist");
|
||||
res.status(500);
|
||||
res.send("Error, invalid filename:\n");
|
||||
return;
|
||||
}
|
||||
var shortName = req.params.shortName.toLowerCase();
|
||||
var apiKey = req.body.api_key;
|
||||
|
||||
System.findOne({
|
||||
'shortName': shortName
|
||||
}, async function(err, item) {
|
||||
|
||||
if (err) {
|
||||
console.warn("[" + req.params.shortName + "] Error /:shortName/upload - Error: " + err);
|
||||
res.status(500);
|
||||
res.send("Error, invalid shotName:\n" + err);
|
||||
return;
|
||||
}
|
||||
if (item === null) {
|
||||
console.warn("[" + req.params.shortName + "] Error /:shortName/upload ShortName does not exist");
|
||||
res.status(500);
|
||||
res.send("ShortName does not exist: " + shortName + "\n");
|
||||
return;
|
||||
}
|
||||
if (apiKey != item.key) {
|
||||
console.warn("[" + req.params.shortName + "] Error /:shortName/upload API Key Mismatch - Provided key: " + apiKey);
|
||||
res.status(500);
|
||||
res.send("API Keys do not match!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
var talkgroupNum = parseInt(req.body.talkgroup_num);
|
||||
var freq = parseFloat(req.body.freq);
|
||||
var time = new Date(parseInt(req.body.start_time) * 1000);
|
||||
var stopTime = new Date();
|
||||
if (req.body.stop_time) {
|
||||
var stopTime = new Date(parseInt(req.body.stop_time) * 1000);
|
||||
}
|
||||
var startTime = req.body.start_time;
|
||||
var emergency = parseInt(req.body.emergency);
|
||||
|
||||
|
||||
// Add in an API Key check
|
||||
|
||||
try {
|
||||
|
||||
var srcList = JSON.parse(req.body.source_list);
|
||||
|
||||
// Mongoose does not allow 'errors' to be used in the Schema for call. need to rename to error.
|
||||
var badFreqList = JSON.parse(req.body.freq_list);
|
||||
var freqList = badFreqList.map(obj =>{
|
||||
|
||||
obj.error = obj.errors;
|
||||
delete obj.errors;
|
||||
return obj;
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
var srcList = [];
|
||||
var freqList = [];
|
||||
console.warn("[" + req.params.shortName + "] Error /:shortName/upload Parsing Source/Freq List - Error: " + err);
|
||||
|
||||
res.status(500);
|
||||
res.send("Error parsing sourcelist " + err);
|
||||
}
|
||||
|
||||
var base_path = config.mediaDirectory;
|
||||
var local_path = "/" + shortName + "/" + time.getFullYear() + "/" + (time.getMonth() + 1) + "/" + time.getDate() + "/";
|
||||
var target_file = base_path + local_path + path.basename(req.file.originalname);
|
||||
var object_key = "media/" + shortName + "-" + talkgroupNum + "-" + startTime + ".m4a";
|
||||
//var endpoint = 'https://s3.amazonaws.com/openmhz/';
|
||||
//var endpoint = 'https://s3.wasabisys.com/openmhz/';
|
||||
var endpoint = s3_endpoint;
|
||||
var bucket = 'openmhz'
|
||||
//var url = 'https://openmhz.nyc3.cdn.digitaloceanspaces.com/' + object_key;
|
||||
|
||||
var url = endpoint + object_key;
|
||||
//var url = 'https://s3.wasabisys.com/openmhz/' + object_key;
|
||||
//var url = 'https://s3.amazonaws.com/openmhz/' + object_key;
|
||||
var objectStore = true;
|
||||
if (item.plan && (item.plan.type == "pro")) {
|
||||
url = media_server + local_path + talkgroupNum + "-" + startTime + ".m4a";
|
||||
objectStore = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
var call = new Call({
|
||||
shortName: shortName,
|
||||
talkgroupNum: talkgroupNum,
|
||||
objectKey: object_key,
|
||||
endpoint: endpoint,
|
||||
bucket: bucket,
|
||||
time: time,
|
||||
name: talkgroupNum + "-" + startTime + ".m4a",
|
||||
freq: freq,
|
||||
url: url,
|
||||
emergency: emergency,
|
||||
path: local_path,
|
||||
srcList: srcList,
|
||||
freqList: freqList,
|
||||
len: -1
|
||||
});
|
||||
|
||||
try {
|
||||
if (req.body.call_length) {
|
||||
call.len = parseInt(req.body.call_length);
|
||||
} else {
|
||||
call.len = (stopTime - time)/1000; //await callLength(req.file.path);
|
||||
}
|
||||
res.status(200).end();
|
||||
|
||||
|
||||
if (!objectStore) {
|
||||
mkdirp.sync(base_path + local_path, function(err) {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
var src = fs.createReadStream(req.file.path);
|
||||
var dest = fs.createWriteStream(target_file);
|
||||
dest.on('unpipe', (src) => {
|
||||
src.end();
|
||||
dest.end();
|
||||
});
|
||||
src.pipe(dest);
|
||||
src.unpipe()
|
||||
src.on('error', function(err) {
|
||||
console.warn("[" + call.shortName + "] Error /:shortName/upload copying to location - Error: " + err + " Read: " + req.file.path + " Target: " + target_file);
|
||||
fs.unlink(req.file.path, (err) => {
|
||||
if (err)
|
||||
console.log("[" + call.shortName + "] error deleting: " + req.file.path);
|
||||
});
|
||||
res.contentType('json');
|
||||
res.send(JSON.stringify({
|
||||
success: false,
|
||||
error: "Upload failed"
|
||||
}));
|
||||
});
|
||||
src.on('end', function() {
|
||||
fs.unlink(req.file.path);
|
||||
});
|
||||
} else {
|
||||
//var spacesSrc = fs.createReadStream(req.file.path);
|
||||
//var awsSrc = fs.createReadStream(req.file.path);
|
||||
var wasabiSrc = fs.createReadStream(req.file.path);
|
||||
|
||||
// call S3 to retrieve upload file to specified bucket
|
||||
|
||||
/* var spacesParams = {Bucket: 'openmhz', Key: object_key, Body: spacesSrc, ACL: 'public-read'};
|
||||
// call S3 to retrieve upload file to specified bucket
|
||||
spacesS3.upload (spacesParams, function (err, data) {
|
||||
//fs.unlink(req.file.path);
|
||||
if (err) {
|
||||
console.log("Spaces Error", err);
|
||||
}
|
||||
});*/
|
||||
/*
|
||||
var awsParams = {Bucket: 'openmhz', Key: object_key, Body: awsSrc, ACL: 'public-read'};
|
||||
|
||||
awsS3.upload (awsParams, function (err, data) {
|
||||
fs.unlink(req.file.path);
|
||||
if (err) {
|
||||
console.log("AWS Error", err);
|
||||
}
|
||||
});*/
|
||||
|
||||
var wasabiParams = {
|
||||
Bucket: 'openmhz-west',
|
||||
Key: object_key,
|
||||
Body: wasabiSrc,
|
||||
ACL: 'public-read'
|
||||
};
|
||||
|
||||
|
||||
var options = {partSize: 10 * 1024 * 1024, queueSize: 1};
|
||||
/*var upload = new wasabiS3.ManagedUpload({
|
||||
leavePartsOnError: true,
|
||||
partSize: 10 * 1024 * 1024, queueSize: 1,
|
||||
params: wasabiParams
|
||||
});*/
|
||||
wasabiS3.upload(wasabiParams, options, function(err, data) {
|
||||
wasabiSrc.destroy();
|
||||
fs.unlink(req.file.path, (err) => {
|
||||
if (err) {
|
||||
console.log("[" + call.shortName + "]error deleting: " + req.file.path);
|
||||
}
|
||||
call.save();
|
||||
sysStats.addCall(call.toObject());
|
||||
|
||||
// we only want to notify clients if the clip is longer than 1 second.
|
||||
if (call.len >= 1) {
|
||||
req.call = call.toObject();
|
||||
next();
|
||||
}
|
||||
});
|
||||
if (err) {
|
||||
console.log("[" + call.shortName + "] " + call.name + " - content-length: " + req.headers['content-length'] + " Wasabi Error", err);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn("[" + call.shortName + "] Upload Error: " + err + " Filename: " + call.name + " content-length: " + req.headers['content-length']);
|
||||
res.status(500);
|
||||
sysStats.addError(call.toObject());
|
||||
res.contentType('json');
|
||||
res.send(JSON.stringify({
|
||||
success: false,
|
||||
error: "FFProbe"
|
||||
}));
|
||||
fs.unlink(req.file.path, (err) => {
|
||||
if (err)
|
||||
console.log("error deleting: " + req.file.path);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user