mirror of
https://github.com/bckelley/cgm-remote-monitor.git
synced 2026-08-24 03:14:12 -05:00
236 lines
7.0 KiB
JavaScript
236 lines
7.0 KiB
JavaScript
'use strict';
|
|
|
|
var consts = require('../../constants');
|
|
var es = require('event-stream');
|
|
var sgvdata = require('sgvdata');
|
|
|
|
/**********\
|
|
* Entries
|
|
\**********/
|
|
function configure (app, wares, core) {
|
|
var entries = core.entries;
|
|
var express = require('express'),
|
|
api = express.Router( )
|
|
;
|
|
|
|
// invoke common middleware
|
|
api.use(wares.sendJSONStatus);
|
|
// text body types get handled as raw buffer stream
|
|
api.use(wares.bodyParser.raw());
|
|
// json body types get handled as parsed json
|
|
api.use(wares.bodyParser.json());
|
|
// shortcut to use extension to specify output content-type
|
|
// api.use(require('express-extension-to-accept')([
|
|
api.use(wares.extensions([
|
|
'json', 'svg', 'csv', 'txt', 'png', 'html', 'tsv'
|
|
]));
|
|
// also support url-encoded content-type
|
|
api.use(wares.bodyParser.urlencoded({ extended: true }));
|
|
|
|
function force_typed_data (opts) {
|
|
function sync (data, next) {
|
|
if (data.type != opts.type) {
|
|
console.warn('BAD DATA TYPE, setting', data.type, 'to', opts.type);
|
|
data.type = opts.type;
|
|
}
|
|
next(null, data);
|
|
}
|
|
return es.map(sync);
|
|
}
|
|
|
|
// Middleware to format any response involving entries.
|
|
function format_entries (req, res, next) {
|
|
var type_params = {
|
|
type: (req.query && req.query.find && req.query.find.type
|
|
&& req.query.find.type != req.params.model)
|
|
? req.query.find.type : req.params.model
|
|
};
|
|
var output = es.readArray(res.entries || [ ]);
|
|
if (res.entries_err) {
|
|
return res.sendJSONStatus(res, consts.HTTP_INTERNAL_ERROR, 'Mongo Error', res.entries_err);
|
|
}
|
|
return res.format({
|
|
text: function ( ) {
|
|
es.pipeline(output, sgvdata.format( ), res);
|
|
},
|
|
json: function ( ) {
|
|
es.pipeline(output, force_typed_data(type_params), entries.map( ), es.writeArray(function (err, out) {
|
|
res.json(out);
|
|
}));
|
|
}
|
|
});
|
|
}
|
|
|
|
// middleware to process "uploads" of sgv data
|
|
function insert_entries (req, res, next) {
|
|
// list of incoming records
|
|
var incoming = [ ];
|
|
// Potentially a single json encoded body.
|
|
// This can happen from either an url-encoded or json content-type.
|
|
if ('date' in req.body) {
|
|
// add it to the incoming list
|
|
incoming.push(req.body);
|
|
}
|
|
// potentially a list of json entries
|
|
if (req.body.length) {
|
|
// add them to the list
|
|
incoming = incoming.concat(req.body);
|
|
}
|
|
|
|
/*
|
|
* inputs -> <ReadableStream>
|
|
* in node, pipe is the most interoperable interface
|
|
* inputs returns a readable stream representing all the potential
|
|
* records from the HTTP body.
|
|
* Most content-types are handled by express middeware.
|
|
* However, text/* types are given to us as a raw buffer, this
|
|
* function switches between these two variants to find the
|
|
* correct input stream.
|
|
* stream, so use svgdata to handle those.
|
|
* The inputs stream always emits sgv json objects.
|
|
*/
|
|
function inputs ( ) {
|
|
var input;
|
|
// handle all text types
|
|
if (req.is('text/*')) {
|
|
// re-use the svgdata parsing stream
|
|
input = es.pipeline(req, sgvdata.parse( ));
|
|
return input;
|
|
}
|
|
// use established list
|
|
return es.readArray(incoming);
|
|
}
|
|
|
|
// return a writable persistent storage stream
|
|
function persist (fn) {
|
|
if (req.persist_entries) {
|
|
// store everything
|
|
return entries.persist(fn);
|
|
}
|
|
// support a preview mode, just lint everything
|
|
return es.pipeline(entries.map( ), es.writeArray(fn));
|
|
}
|
|
|
|
// store results and move to the next middleware
|
|
function done (err, result) {
|
|
res.entries = result;
|
|
res.entries_err = err;
|
|
return next( );
|
|
}
|
|
|
|
// pipe everything to persistent storage
|
|
// when finished, pass to the next piece of middleware
|
|
es.pipeline(inputs( ), persist(done));
|
|
}
|
|
|
|
function prepReqModel(req, model) {
|
|
var find = { };
|
|
switch (model) {
|
|
case 'treatments':
|
|
case 'devicestatus':
|
|
//TODO: profiles not working now, maybe profiles are special
|
|
//case 'profiles':
|
|
req.model = core[model];
|
|
break;
|
|
|
|
case 'meter':
|
|
case 'mbg':
|
|
find.type = 'mbg';
|
|
req.model = core.entries;
|
|
break;
|
|
case 'cal':
|
|
find.type = 'cal';
|
|
req.model = core.entries;
|
|
break;
|
|
case 'sensor':
|
|
find.type = 'sensor';
|
|
req.model = core.entries;
|
|
break;
|
|
case 'sgv':
|
|
find.type = 'sgv';
|
|
req.model = core.entries;
|
|
break;
|
|
default:
|
|
req.model = core.entries;
|
|
break;
|
|
}
|
|
|
|
if (!req.query.find) {
|
|
req.query.find = find;
|
|
} else {
|
|
req.query.find.type = find.type;
|
|
}
|
|
}
|
|
|
|
api.param('model', function (req, res, next, model) {
|
|
prepReqModel(req, model);
|
|
next( );
|
|
});
|
|
|
|
api.get('/entries/current', function(req, res, next) {
|
|
//assume sgv
|
|
req.params.model = 'sgv';
|
|
entries.list({count: 1}, function(err, records) {
|
|
res.entries = records;
|
|
res.entries_err = err;
|
|
return next( );
|
|
});
|
|
}, format_entries);
|
|
|
|
// Fetch one entry by id
|
|
api.get('/entries/:id', function(req, res, next) {
|
|
var ID_PATTERN = /^[a-f\d]{24}$/;
|
|
if (ID_PATTERN.test(req.params.id)) {
|
|
//assume sgv
|
|
req.params.model = 'sgv';
|
|
entries.getEntry(req.params.id, function(err, entry) {
|
|
res.entries = [entry];
|
|
res.entries_err = err;
|
|
next();
|
|
});
|
|
} else {
|
|
//TODO: /entries/:id is blocking /entries/:model
|
|
req.params.model = req.params.id;
|
|
prepReqModel(req, req.params.model);
|
|
query_models(req, res, next);
|
|
}
|
|
}, format_entries);
|
|
|
|
api.get('/entries/:model', query_models, format_entries);
|
|
api.get('/entries', query_models, format_entries);
|
|
|
|
|
|
function query_models (req, res, next) {
|
|
// If "?count=" is present, use that number to decided how many to return.
|
|
if (!req.model) {
|
|
req.model = core.entries;
|
|
}
|
|
var query = req.query;
|
|
if (!query.count) { query.count = 10 }
|
|
req.model.list(query, function(err, entries) {
|
|
res.entries = entries;
|
|
res.entries_err = err;
|
|
return next( );
|
|
});
|
|
}
|
|
|
|
|
|
// Allow previewing your post content, just echos everything you
|
|
// posted back out.
|
|
api.post('/entries/preview', function (req, res, next) {
|
|
req.persist_entries = false;
|
|
next( );
|
|
}, insert_entries, format_entries);
|
|
|
|
if (app.enabled('api')) {
|
|
// Create and store new sgv entries
|
|
api.post('/entries/', wares.verifyAuthorization, function (req, res, next) {
|
|
req.persist_entries = true;
|
|
next( );
|
|
}, insert_entries, format_entries);
|
|
}
|
|
|
|
return api;
|
|
}
|
|
module.exports = configure;
|