Merge branch 'master' into donate

This commit is contained in:
Luke Berndt
2024-02-22 22:12:49 -05:00
committed by GitHub
23 changed files with 2997 additions and 281 deletions

View File

@@ -0,0 +1,23 @@
// tracing.js
'use strict';
const { HoneycombSDK } = require('@honeycombio/opentelemetry-node');
const {
getNodeAutoInstrumentations,
} = require('@opentelemetry/auto-instrumentations-node');
// uses the HONEYCOMB_API_KEY and OTEL_SERVICE_NAME environment variables
const sdk = new HoneycombSDK({
sampleRate: 5,
instrumentations: [
getNodeAutoInstrumentations({
// we recommend disabling fs autoinstrumentation since it can be noisy
// and expensive during startup
'@opentelemetry/instrumentation-fs': {
enabled: false,
},
}),
],
});
sdk.start();

View File

@@ -2,7 +2,7 @@
const { ObjectId } = require('mongodb');
var { callModel: Call } = require("../models/call");
const Group = require("../models/group");
const opentelemetry = require('@opentelemetry/api');
var defaultNumResults = 50;
var channels = {};

View File

@@ -1,10 +1,12 @@
var path = require('path');
var fs = require('fs');
const opentelemetry = require('@opentelemetry/api');
var sysStats = require("../sys_stats");
var System = require("../models/system");
var Talkgroup = require("../models/talkgroup");
var { callModel: Call } = require("../models/call");
const { PutObjectCommand, S3Client } = require("@aws-sdk/client-s3");
const { fromIni } = require("@aws-sdk/credential-providers");
@@ -18,183 +20,236 @@ const client = new S3Client({
credentials: fromIni({ profile: s3_profile }),
endpoint: s3_endpoint,
region: s3_region,
maxAttempts: 1
maxAttempts: 3
});
exports.upload = async function (req, res, next) {
process.nextTick( async () => {
if (!req.file || ((path.extname(req.file.originalname) != '.m4a') && (path.extname(req.file.originalname) != '.mp3'))) {
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;
let item = null;
try {
item = await System.findOne({ 'shortName': shortName }, ["key", "ignoreUnknownTalkgroup"]);
} catch (err) {
console.warn("[" + req.params.shortName + "] Error /:shortName/upload - Error: " + err);
res.status(500);
res.send("Error, invalid shotName:\n" + err);
return;
}
process.nextTick(async () => {
if (!req.file || ((path.extname(req.file.originalname) != '.m4a') && (path.extname(req.file.originalname) != '.mp3'))) {
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;
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);
if (!item) {
console.info("[" + 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;
}
let errorCount = parseInt(req.body.error_count);
let spikeCount = parseInt(req.body.spike_count);
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);
if (Number.isNaN(errorCount)) {
errorCount = 0;
}
if (Number.isNaN(spikeCount)) {
spikeCount = 0;
}
// Blocking sensitive talkgroups
if ((shortName == "hennearmer") && ((talkgroupNum == 3421) || (talkgroupNum == 3423))) {
res.status(200).end();
return;
}
try {
var srcList = JSON.parse(req.body.source_list);
} catch (err) {
var srcList = [];
console.warn("[" + req.params.shortName + "] Error /:shortName/upload Parsing Source/Freq List - Error: " + err);
res.status(500);
res.send("Error parsing sourcelist " + err);
return;
}
let item = null;
const span = opentelemetry.trace.getActiveSpan();
span.setAttribute('call.shortName', shortName);
span.setAttribute('call.talkgroupNum', talkgroupNum);
span.setAttribute('call.startTime', startTime);
if (item.ignoreUnknownTalkgroup == true) {
talkgroupExists = await Talkgroup.exists({
'shortName': shortName,
'num': talkgroupNum
// Validate that the system exists and the API key is correct
try {
item = await System.findOne({ 'shortName': shortName }, ["key", "ignoreUnknownTalkgroup"]);
} catch (err) {
span.setStatus({
code: opentelemetry.SpanStatusCode.ERROR,
message: "Error /:shortName/upload - Error: " + err,
});
console.warn("[" + req.params.shortName + "] Error /:shortName/upload - Error: " + err);
res.status(500);
res.send("Error, invalid shortName:\n" + err);
return;
}
if (!item) {
span.setStatus({
code: opentelemetry.SpanStatusCode.ERROR,
message: "Error /:shortName/upload API Key Mismatch - Provided key: " + apiKey,
});
console.info("[" + 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) {
span.setStatus({
code: opentelemetry.SpanStatusCode.ERROR,
message: "Error /:shortName/upload API Key Mismatch - Provided key: " + apiKey,
});
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;
}
// Blocking sensitive talkgroups
if ((shortName == "hennearmer") && ((talkgroupNum == 3421) || (talkgroupNum == 3423))) {
span.setStatus({
code: opentelemetry.SpanStatusCode.ERROR,
message: "Sensitive Talkgroup",
});
res.status(200).end();
return;
}
if (item.ignoreUnknownTalkgroup == true) {
talkgroupExists = await Talkgroup.exists({
'shortName': shortName,
'num': talkgroupNum
});
if (!talkgroupExists) {
try {
fs.unlinkSync(req.file.path)
//file removed
} catch (err) {
console.log("[" + call.shortName + "] error deleting: " + req.file.path);
}
res.status(500);
res.send("Talkgroup does not exist, skipping.\n");
span.setStatus({
code: opentelemetry.SpanStatusCode.ERROR,
message: "Ignore Unknown Talkgroup Set - Talkgroup does not exist: " + talkgroupNum + " ShortName: " + shortName,
});
return;
}
}
// Add in an API Key check
res.status(200).end();
var local_path = "/" + shortName + "/" + time.getFullYear() + "/" + (time.getMonth() + 1) + "/" + time.getDate() + "/";
var object_key = "media/" + shortName + "-" + talkgroupNum + "-" + startTime + path.extname(req.file.originalname);
var endpoint = s3_endpoint;
var bucket = s3_bucket;
var url = s3_endpoint + "/" + s3_bucket + "/" + object_key;
var call = new Call({
shortName: shortName,
talkgroupNum: talkgroupNum,
objectKey: object_key,
endpoint: endpoint,
bucket: bucket,
time: time,
name: talkgroupNum + "-" + startTime + ".m4a",
freq: freq,
errorCount: errorCount,
spikeCount: spikeCount,
url: url,
emergency: emergency,
path: local_path,
srcList: srcList,
len: -1
});
if (!talkgroupExists) {
try {
fs.unlinkSync(req.file.path)
//file removed
} catch (err) {
console.log("[" + call.shortName + "] error deleting: " + req.file.path);
try {
if (req.body.call_length) {
call.len = parseFloat(req.body.call_length);
} else {
call.len = (stopTime - time) / 1000;
}
res.status(500);
res.send("Talkgroup does not exist, skipping.\n");
} catch (err) {
console.error(err);
}
let fileContent;
try {
fileContent = fs.readFileSync(req.file.path);
//s3Src = fs.createReadStream(req.file.path);
} catch (err) {
span.setStatus({
code: opentelemetry.SpanStatusCode.ERROR,
message: "Unable to open file: " + req.file.path + " Error: " + err,
});
console.error("[" + call.shortName + "] Unable to open file: " + req.file.path + " Error: " + err);
return;
}
}
// Add in an API Key check
const command = new PutObjectCommand({
Bucket: s3_bucket,
Key: object_key,
Body: fileContent,
ACL: 'public-read'
});
let errorCount = parseInt(req.body.error_count);
let spikeCount = parseInt(req.body.spike_count);
try {
await client.send(command);
if (Number.isNaN(errorCount)) {
errorCount = 0;
}
if (Number.isNaN(spikeCount)) {
spikeCount = 0;
}
try {
var srcList = JSON.parse(req.body.source_list);
} catch (err) {
var srcList = [];
console.warn("[" + req.params.shortName + "] Error /:shortName/upload Parsing Source/Freq List - Error: " + err);
res.status(500);
res.send("Error parsing sourcelist " + err);
return;
}
res.status(200).end();
var local_path = "/" + shortName + "/" + time.getFullYear() + "/" + (time.getMonth() + 1) + "/" + time.getDate() + "/";
var object_key = "media/" + shortName + "-" + talkgroupNum + "-" + startTime + path.extname(req.file.originalname);
var endpoint = s3_endpoint;
var bucket = s3_bucket;
var url = s3_endpoint + "/" + s3_bucket + "/" + object_key;
var call = new Call({
shortName: shortName,
talkgroupNum: talkgroupNum,
objectKey: object_key,
endpoint: endpoint,
bucket: bucket,
time: time,
name: talkgroupNum + "-" + startTime + ".m4a",
freq: freq,
errorCount: errorCount,
spikeCount: spikeCount,
url: url,
emergency: emergency,
path: local_path,
srcList: srcList,
len: -1
});
try {
if (req.body.call_length) {
call.len = parseFloat(req.body.call_length);
} else {
call.len = (stopTime - time) / 1000;
} catch (err) {
span.setStatus({
code: opentelemetry.SpanStatusCode.ERROR,
message: "Upload Error: " + err + " Filename: " + call.name + " content-length: " + req.headers['content-length'] + " Key: " + object_key + " Bucket: " + s3_bucket,
});
console.warn("[" + call.shortName + "] Upload Error: " + err + " Filename: " + call.name + " content-length: " + req.headers['content-length'] + " Key: " + object_key + " Bucket: " + s3_bucket);
/*res.status(500);
sysStats.addError(call.toObject());
res.contentType('json');
res.status(500);
res.send(JSON.stringify({
success: false,
error: "File Upload"
}));*/
}
} catch (err) {
console.error(err);
}
let fileContent;
try {
fileContent = fs.readFileSync(req.file.path);
//s3Src = fs.createReadStream(req.file.path);
} catch (err) {
console.error("[" + call.shortName + "] Unable to open file: " + req.file.path + " Error: " + err);
return;
}
const command = new PutObjectCommand({
Bucket: s3_bucket,
Key: object_key,
Body: fileContent,
ACL: 'public-read'
});
try {
await client.send(command);
await 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();
try {
await 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();
}
} catch (err) {
console.warn("[" + call.shortName + "] Error saving call: " + err);
span.setStatus({
code: opentelemetry.SpanStatusCode.ERROR,
message: "Error saving call: " + err,
});
/*res.status(500);
sysStats.addError(call.toObject());
res.contentType('json');
res.status(500);
res.send(JSON.stringify({
success: false,
error: "File Upload"
}));*/
}
} catch (err) {
console.warn("[" + call.shortName + "] Upload Error: " + err + " Filename: " + call.name + " content-length: " + req.headers['content-length'] + " Key: " + object_key + " Bucket: " + s3_bucket);
/*res.status(500);
sysStats.addError(call.toObject());
res.contentType('json');
res.status(500);
res.send(JSON.stringify({
success: false,
error: "File Upload"
}));*/
}
try {
fs.unlinkSync(req.file.path);
} catch (err) {
console.warn("There was an Error uploading an deleting: " + req.file.path);
};
});
}

View File

@@ -1,4 +1,4 @@
const tracing = require("./agents/honeycomb-tracing");
var express = require("express");
var configureExpress = require("./config/express");

2631
backend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,9 @@
"@aws-sdk/client-s3": "^3.309.0",
"@aws-sdk/credential-provider-process": "^3.306.0",
"@aws-sdk/credential-providers": "^3.309.0",
"@honeycombio/opentelemetry-node": "^0.6.1",
"@opentelemetry/api": "^1.7.0",
"@opentelemetry/auto-instrumentations-node": "^0.41.0",
"adm-zip": "^0.5.10",
"aws-sdk": "^2.1353",
"axios": "1.3.5",
@@ -22,12 +25,12 @@
"ffprobe-static": "3.1.0",
"find-remove": "4.1.0",
"get-folder-size": "^4.0.0",
"node-mailjet": "6.0.2",
"mkdirp": "^2.1.6",
"mongodb": "5.2.0",
"mongoose": "7.0.3",
"multer": "1.3.0",
"node-ffprobe": "https://github.com/ListenerApproved/node-ffprobe",
"node-mailjet": "6.0.2",
"node-schedule": "2.1.1",
"passport": "0.6.0",
"passport-local": "1.0.0",

View File

@@ -10,10 +10,7 @@ var spots = (24 * 60) / timePeriod; // the number of spots needed to keep track
async function updateActiveSystems() {
// Go through all of the Systems
for await (let item of System.find()) {
// go through all the systems
// if you have recieved some calls during that last period, make the system active