From d8f745b95154bb0d61a061dd926a670912454bb2 Mon Sep 17 00:00:00 2001 From: markcor11 Date: Tue, 28 Jan 2020 16:06:07 +0000 Subject: [PATCH 1/4] Set duration of collection Signed-off-by: markcor11 --- AUTHORS.md | 1 + lib/collections.route.js | 97 ++++++++++++++++++++++++++++++++++++---- package.json | 6 ++- 3 files changed, 93 insertions(+), 11 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index e1733ca..b7503f5 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -3,3 +3,4 @@ Authors ordered by first contribution: - Toby Corbin (https://github.com/tobespc) - Richard Waller (https://github.com/rwalle61) + - Mark Cornaia (https://github.com/markcor11) diff --git a/lib/collections.route.js b/lib/collections.route.js index cdac120..eace4e0 100644 --- a/lib/collections.route.js +++ b/lib/collections.route.js @@ -16,11 +16,14 @@ 'use strict'; const express = require('express'); - +const fs = require('fs-extra'); +const os = require('os'); +const path = require('path'); +const {promisify} = require('util'); const Collection = require('./classes/collections'); - const router = express.Router(); let collections = []; +const METRICSFILE_PREFIX = path.join(os.tmpdir(), 'appmetrics-collection'); /** * Routes @@ -46,6 +49,40 @@ router.get('/:id', function(req, res) { }); }); +// Retrieve the saved collection +router.get('/:id/stashed', function(req, res) { + const collectionID = req.params.id; + const readJSONAsync = promisify(fs.readJSON); + const tempFilePath = `${METRICSFILE_PREFIX}_${collectionID}.json`; + // Find index of collection + let foundIndex = findIndexInCollection(collectionID); + + if (foundIndex == -1) { + res.status(404).send({status: 'error', message: 'Unable to find collection'}); + return; + } + + readJSONAsync(tempFilePath, {encoding: 'utf8'}).then(contents => { + // delete the collection + if (foundIndex > -1) { + getCollection(req, res, function(i) { + collections.splice(i, 1); + }); + } + + // delete tmp file + fs.unlink(tempFilePath, (err) => { + if (err) { + console.error(`Unable to delete temp file from ${tempFilePath}`); + } + }); + + res.status(200).send(contents); + }).catch(error => { + res.status(500).send({status: 'error', message: error.message}); + }); +}); + router.put('/:id', function(req, res) { getCollection(req, res, function(i) { collections[i].reset(); @@ -60,6 +97,21 @@ router.delete('/:id', function(req, res) { }); }); +// Start recording for :seconds +router.post('/:seconds', function(req, res) { + let seconds = req.params.seconds; + let col = new Collection(); + collections.push(col); + setTimeout(stashRecordedCollection, seconds * 1000, collections, col.collection.id); + res.status(201); + let colUrl = 'collections/' + col.collection.id; + res.header('Location', colUrl); + let json = {}; + json.uri = colUrl; + res.json(json); +}); + +// Start recording until stopped router.post('', function(req, res) { let col = new Collection(); collections.push(col); @@ -71,6 +123,28 @@ router.post('', function(req, res) { res.json(json); }); +// Save the recorded collection to a temp file +function stashRecordedCollection(collections, collectionID) { + console.log(`Save recorded collection ${collectionID}`); + let foundIndex = findIndexInCollection(collectionID); + + if (foundIndex != -1) { + let col = collections[foundIndex].collection; + col.time.data.end = new Date().getTime(); + const writeFileAsync = promisify(fs.writeFile); + writeFileAsync(`${METRICSFILE_PREFIX}_${collectionID}.json`, JSON.stringify(col)) + .then(() => { + console.log('Collection Saved'); + }) + .catch(err => { + console.log('Requested collection cannot be accessed', err); + }); + } else { + console.log('Unable to find collection'); + } +} + + /** * Function to send a collection to the user using the API Will either return a * 200 code if successful or a 400 if not @@ -84,13 +158,7 @@ router.post('', function(req, res) { */ function getCollection(req, res, cb) { let id = req.params.id; - let index = -1; - // Don't assume that the list will match up to ids - for (var i = 0; i < collections.length; i++) { - if (collections[i].collection.id == id) { - index = i; - } - } + let index = findIndexInCollection(id); if (index != -1) { try { let col = collections[index].collection; @@ -129,6 +197,17 @@ function updateCollections(type, data) { } }; +function findIndexInCollection(id) { + let foundIndex = -1; + for (var i = 0; i < collections.length; i++) { + if (collections[i].collection.id == id) { + foundIndex = i; + break; + } + } + return foundIndex; +} + module.exports = { router, updateCollections, diff --git a/package.json b/package.json index ed04576..df16636 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "dependencies": { "appmetrics": "^5.0.0", "debug": "^2.6.0", - "express": "^4.14.1" + "express": "^4.14.1", + "os": "^0.1.1", + "path": "^0.12.7" }, "devDependencies": { "appmetrics-dash": "^5.3.0", @@ -22,7 +24,7 @@ "request": "^2.79.0", "serve-favicon": "^2.3.2", "socket.io": "^2.3.0", - "strong-error-handler": "^1.2.1", + "strong-error-handler": "^3.4.0", "tap": "^14.9.1" }, "scripts": { From 4451cd40e722d835b8953ab2de7e17706e076c92 Mon Sep 17 00:00:00 2001 From: markcor11 Date: Tue, 4 Feb 2020 12:21:57 +0000 Subject: [PATCH 2/4] Add features route Signed-off-by: markcor11 --- lib/collections.route.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/collections.route.js b/lib/collections.route.js index eace4e0..b0de37e 100644 --- a/lib/collections.route.js +++ b/lib/collections.route.js @@ -43,6 +43,14 @@ router.get('/', function(req, res) { res.status(200).json(json); }); +// Features route +router.get('/features', function(req, res) { + const features = { + timedMetrics: true + }; + res.status(200).json(features); +}); + router.get('/:id', function(req, res) { getCollection(req, res, function(i) { res.status(200).json(collections[i].collection); From a6d560b2731b1a71e8eb3eb36bd4565eb1884fcd Mon Sep 17 00:00:00 2001 From: markcor11 Date: Wed, 5 Feb 2020 11:06:34 +0000 Subject: [PATCH 3/4] Send metrics back as JSON Signed-off-by: markcor11 --- lib/collections.route.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/collections.route.js b/lib/collections.route.js index b0de37e..514bc43 100644 --- a/lib/collections.route.js +++ b/lib/collections.route.js @@ -85,7 +85,7 @@ router.get('/:id/stashed', function(req, res) { } }); - res.status(200).send(contents); + res.status(200).json(contents); }).catch(error => { res.status(500).send({status: 'error', message: error.message}); }); From f0b749f2c9f508872e36e9ddb45c0f1bed04cbf2 Mon Sep 17 00:00:00 2001 From: markcor11 Date: Fri, 7 Feb 2020 15:29:34 +0000 Subject: [PATCH 4/4] Add tests Signed-off-by: markcor11 --- test/test-collections-routes.js | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/test/test-collections-routes.js b/test/test-collections-routes.js index 0e2e073..f719732 100644 --- a/test/test-collections-routes.js +++ b/test/test-collections-routes.js @@ -235,6 +235,61 @@ tap.test('GET collections', function(t) { }); }); +// Test to GET features available +tap.test('GET collections features', function(t) { + const options = { + url: base + '/appmetrics/api/v1/collections/features', + method: 'GET' + }; + debug('request %j', options); + request(options, function(err, res, body) { + t.ifError(err); + let json = JSON.parse(body); + t.equal(json.timedMetrics, true); + t.equal(res.statusCode, 200); + t.end(); + }); +}); + +// Test creating a new timed collection +tap.test('POST new timed collection for 3 seconds', function(t) { + const options = { + url: base + '/appmetrics/api/v1/collections/3', + method: 'POST' + }; + debug('request %j', options); + request(options, function(err, res, body) { + t.ifError(err); + t.equal(res.statusCode, 201); + t.equal(body, '{"uri":"collections/2"}'); + t.end(); + }); +}); + +// Test that the stashed metrics are available +tap.test('GET stashed collection', function(t) { + // wait for 5 seconds + const sleeptime = 5 * 1000; + setTimeout(function(){ + const options = { + url: base + '/appmetrics/api/v1/collections/2/stashed', + method: 'GET' + }; + debug('request %j', options); + request(options, function(err, res, body) { + t.ifError(err); + let json = JSON.parse(body); + t.equal(json.id, 2); + t.equal(res.statusCode, 200); + const diff = json.time.data.end - json.time.data.start; + if (diff <= 0 || diff > 4) { + t.end(); + } + }); + }, sleeptime); +}); + + tap.test('stop', function(t) { server.close(t.end); });