mirror of
https://github.com/bckelley/cgm-remote-monitor.git
synced 2026-08-24 03:14:12 -05:00
@@ -96,16 +96,22 @@ function create (env, ctx) {
|
||||
app.set('view engine', 'ejs');
|
||||
// this allows you to render .html files as templates in addition to .ejs
|
||||
app.engine('html', require('ejs').renderFile);
|
||||
app.engine('appcache', require('ejs').renderFile);
|
||||
app.set("views", path.join(__dirname, "views/"));
|
||||
|
||||
let cacheBuster = 'developmentMode';
|
||||
let lastModified = new Date();
|
||||
let busterPath = '/tmp/cacheBusterToken';
|
||||
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
if (fs.existsSync(process.cwd() + '/tmp/cacheBusterToken')) {
|
||||
cacheBuster = fs.readFileSync(process.cwd() + '/tmp/cacheBusterToken').toString().trim();
|
||||
} else {
|
||||
cacheBuster = fs.readFileSync(__dirname + '/tmp/cacheBusterToken').toString().trim();
|
||||
}
|
||||
busterPath = process.cwd() + busterPath;
|
||||
} else {
|
||||
busterPath = __dirname + busterPath;
|
||||
}
|
||||
|
||||
if (fs.existsSync(busterPath)) {
|
||||
cacheBuster = fs.readFileSync(busterPath).toString().trim();
|
||||
var stats = fs.statSync(busterPath);
|
||||
lastModified = stats.mtime;
|
||||
}
|
||||
app.locals.cachebuster = cacheBuster;
|
||||
|
||||
@@ -116,6 +122,9 @@ function create (env, ctx) {
|
||||
|
||||
app.get("/sw.js", (req, res) => {
|
||||
res.setHeader('Content-Type', 'application/javascript');
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
res.setHeader('Last-Modified', lastModified.toUTCString());
|
||||
}
|
||||
res.send(ejs.render(fs.readFileSync(
|
||||
require.resolve(`${__dirname}/views/service-worker.js`),
|
||||
{ encoding: 'utf-8' }),
|
||||
@@ -268,10 +277,6 @@ function create (env, ctx) {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
maxAge = 1;
|
||||
console.log('Development environment detected, setting static file cache age to 1 second');
|
||||
|
||||
app.get('/nightscout.appcache', function(req, res) {
|
||||
res.sendStatus(404);
|
||||
});
|
||||
}
|
||||
|
||||
var staticFiles = express.static(env.static_files, {
|
||||
|
||||
@@ -15,6 +15,8 @@ var levels = require('../levels');
|
||||
var times = require('../times');
|
||||
var receiveDData = require('./receiveddata');
|
||||
|
||||
var brushing = false;
|
||||
|
||||
var client = {};
|
||||
|
||||
$('#loadingMessageText').html('Connecting to server');
|
||||
@@ -421,6 +423,12 @@ client.load = function load (serverSettings, callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (brushing) {
|
||||
return;
|
||||
}
|
||||
|
||||
brushing = true;
|
||||
|
||||
// default to most recent focus period
|
||||
var brushExtent = client.dataExtent();
|
||||
brushExtent[0] = new Date(brushExtent[1].getTime() - client.focusRangeMS);
|
||||
@@ -605,6 +613,8 @@ client.load = function load (serverSettings, callback) {
|
||||
var top = (client.bottomOfPills() + 5);
|
||||
$('#chartContainer').css({ top: top + 'px', height: $(window).height() - top - 10 });
|
||||
container.removeClass('loading');
|
||||
|
||||
brushing = false;
|
||||
}
|
||||
|
||||
function sgvToColor (sgv) {
|
||||
|
||||
+6
-1
@@ -9,5 +9,10 @@
|
||||
"MMOL_TO_MGDL": 18,
|
||||
"ONE_DAY" : 86400000,
|
||||
"TWO_DAYS" : 172800000,
|
||||
"FIFTEEN_MINUTES": 900000
|
||||
"FIFTEEN_MINUTES": 900000,
|
||||
"THIRTY_MINUTES": 1800000,
|
||||
"ONE_HOUR": 3600000,
|
||||
"THREE_HOURS": 10800000,
|
||||
"FOUR_HOURS": 14400000,
|
||||
"SIX_HOURS": 21600000
|
||||
}
|
||||
|
||||
+33
-13
@@ -38,7 +38,7 @@ const findLatestMills = (data) => {
|
||||
|
||||
function mergeProcessSort(oldData, newData, ageLimit) {
|
||||
|
||||
processForRuntime(newData);
|
||||
processForRuntime(newData);
|
||||
|
||||
var filtered = _.filter(newData, function hasId(object) {
|
||||
const hasId = !_.isEmpty(object._id);
|
||||
@@ -46,13 +46,30 @@ function mergeProcessSort(oldData, newData, ageLimit) {
|
||||
return isFresh && hasId;
|
||||
});
|
||||
|
||||
const merged = _.unionWith(oldData, filtered, function(a, b) {
|
||||
return a._id == b._id;
|
||||
});
|
||||
// Merge old and new data, preferring the new objects
|
||||
|
||||
let merged = [];
|
||||
if (oldData && filtered) {
|
||||
merged = filtered; // Start with the new / updated data
|
||||
for (let i = 0; i < oldData.length; i++) {
|
||||
const oldElement = oldData[i];
|
||||
let found = false;
|
||||
for (let j = 0; j < filtered.length; j++) {
|
||||
if (oldElement._id == filtered[j]._id) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) merged.push(oldElement); // Merge old object in, if it wasn't found in the new data
|
||||
}
|
||||
} else {
|
||||
merged = filtered;
|
||||
}
|
||||
|
||||
return _.sortBy(merged, function(item) {
|
||||
return item.mills;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function init(env, ctx) {
|
||||
@@ -78,13 +95,17 @@ function init(env, ctx) {
|
||||
}
|
||||
ddata.lastUpdated = opts.lastUpdated;
|
||||
|
||||
const convertIds = (obj) => {
|
||||
const normalizeTreatments = (obj) => {
|
||||
Object.keys(obj).forEach(key => {
|
||||
if (typeof obj[key] === 'object' && obj[key]) {
|
||||
if (obj[key].hasOwnProperty('_id')) {
|
||||
obj[key]._id = obj[key]._id.toString();
|
||||
const element = obj[key];
|
||||
if (element.hasOwnProperty('_id')) {
|
||||
element._id = element._id.toString();
|
||||
}
|
||||
convertIds(obj[key]);
|
||||
if (element.hasOwnProperty('amount') && !element.hasOwnProperty('absolute')) {
|
||||
element.absolute = Number(element.amount);
|
||||
}
|
||||
normalizeTreatments(obj[key]);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -93,18 +114,17 @@ function init(env, ctx) {
|
||||
|
||||
// convert all IDs to strings, as these are not used after load
|
||||
|
||||
convertIds(ddata);
|
||||
normalizeTreatments(ddata);
|
||||
|
||||
ddata.treatments = _.uniq(ddata.treatments, false, function(item) {
|
||||
return item._id;
|
||||
});
|
||||
|
||||
//sort treatments so the last is the most recent
|
||||
/*
|
||||
|
||||
ddata.treatments = _.sortBy(ddata.treatments, function(item) {
|
||||
return item.mills;
|
||||
});
|
||||
*/
|
||||
|
||||
fitTreatmentsToBGCurve(ddata, env, ctx);
|
||||
if (err) {
|
||||
@@ -150,7 +170,7 @@ function init(env, ctx) {
|
||||
function loadEntries(ddata, ctx, callback) {
|
||||
|
||||
const withFrame = ddata.page && ddata.page.frame;
|
||||
const loadPeriod = ddata.sgvs && ddata.sgvs.length > 0 && !withFrame ? constants.FIFTEEN_MINUTES : constants.TWO_DAYS;
|
||||
const loadPeriod = ddata.sgvs && ddata.sgvs.length > 0 && !withFrame ? constants.ONE_HOUR : constants.TWO_DAYS;
|
||||
const latestEntry = ddata.sgvs && ddata.sgvs.length > 0 ? findLatestMills(ddata.sgvs) : ddata.lastUpdated;
|
||||
|
||||
var dateRange = {
|
||||
@@ -289,7 +309,7 @@ function loadTreatments(ddata, ctx, callback) {
|
||||
// Load 2.5 days to cover last 48 hours including overlapping temp boluses or temp targets for first load
|
||||
// Subsequently load at least 15 minutes of data, but if latest entry is older than 15 minutes, load until that entry
|
||||
|
||||
const loadPeriod = ddata.treatments && ddata.treatments.length > 0 && !withFrame ? constants.FIFTEEN_MINUTES : longLoad;
|
||||
const loadPeriod = ddata.treatments && ddata.treatments.length > 0 && !withFrame ? constants.SIX_HOURS : longLoad;
|
||||
const latestEntry = ddata.treatments && ddata.treatments.length > 0 ? findLatestMills(ddata.treatments) : ddata.lastUpdated;
|
||||
const loadTime = Math.min(ddata.lastUpdated - loadPeriod, latestEntry);
|
||||
|
||||
|
||||
@@ -103,9 +103,9 @@ function init (env, ctx, server) {
|
||||
|
||||
function emitData (delta) {
|
||||
if (lastData.cals) {
|
||||
console.log(LOG_WS + 'running websocket.emitData', ctx.ddata.lastUpdated);
|
||||
// console.log(LOG_WS + 'running websocket.emitData', ctx.ddata.lastUpdated);
|
||||
if (lastProfileSwitch !== ctx.ddata.lastProfileFromSwitch) {
|
||||
console.log(LOG_WS + 'profile switch detected OLD: ' + lastProfileSwitch + ' NEW: ' + ctx.ddata.lastProfileFromSwitch);
|
||||
// console.log(LOG_WS + 'profile switch detected OLD: ' + lastProfileSwitch + ' NEW: ' + ctx.ddata.lastProfileFromSwitch);
|
||||
delta.status = status(ctx.ddata.profiles);
|
||||
lastProfileSwitch = ctx.ddata.lastProfileFromSwitch;
|
||||
}
|
||||
@@ -457,7 +457,7 @@ function init (env, ctx, server) {
|
||||
socket.emit('dataUpdate', data);
|
||||
}
|
||||
}
|
||||
console.log(LOG_WS + 'Authetication ID: ', socket.client.id, ' client: ', clientType, ' history: ' + history);
|
||||
// console.log(LOG_WS + 'Authetication ID: ', socket.client.id, ' client: ', clientType, ' history: ' + history);
|
||||
if (callback) {
|
||||
callback(socketAuthorization);
|
||||
}
|
||||
@@ -471,7 +471,7 @@ function init (env, ctx, server) {
|
||||
socket.on('nsping', function ping (message, callback) {
|
||||
var clientTime = message.mills;
|
||||
timeDiff = new Date().getTime() - clientTime;
|
||||
console.log(LOG_WS + 'Ping from client ID: ',socket.client.id, ' client: ', clientType, ' timeDiff: ', (timeDiff/1000).toFixed(1) + 'sec');
|
||||
// console.log(LOG_WS + 'Ping from client ID: ',socket.client.id, ' client: ', clientType, ' timeDiff: ', (timeDiff/1000).toFixed(1) + 'sec');
|
||||
if (callback) {
|
||||
callback({ result: 'pong', mills: new Date().getTime(), authorization: socketAuthorization });
|
||||
}
|
||||
@@ -480,14 +480,14 @@ function init (env, ctx, server) {
|
||||
}
|
||||
|
||||
websocket.update = function update ( ) {
|
||||
console.log(LOG_WS + 'running websocket.update');
|
||||
// console.log(LOG_WS + 'running websocket.update');
|
||||
if (lastData.sgvs) {
|
||||
var delta = calcData(lastData, ctx.ddata);
|
||||
if (delta.delta) {
|
||||
console.log('lastData full size', JSON.stringify(lastData).length,'bytes');
|
||||
if (delta.sgvs) { console.log('patientData update size', JSON.stringify(delta).length,'bytes'); }
|
||||
// console.log('lastData full size', JSON.stringify(lastData).length,'bytes');
|
||||
// if (delta.sgvs) { console.log('patientData update size', JSON.stringify(delta).length,'bytes'); }
|
||||
emitData(delta);
|
||||
} else { console.log('delta calculation indicates no new data is present'); }
|
||||
}; // else { console.log('delta calculation indicates no new data is present'); }
|
||||
}
|
||||
lastData = ctx.ddata.clone();
|
||||
};
|
||||
|
||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nightscout",
|
||||
"version": "14.0.1",
|
||||
"version": "14.0.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nightscout",
|
||||
"version": "14.0.1",
|
||||
"version": "14.0.2",
|
||||
"description": "Nightscout acts as a web-based CGM (Continuous Glucose Montinor) to allow multiple caregivers to remotely view a patients glucose data in realtime.",
|
||||
"license": "AGPL-3.0",
|
||||
"author": "Nightscout Team",
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
"info": {
|
||||
"title": "Nightscout API",
|
||||
"description": "Own your DData with the Nightscout API",
|
||||
"version": "14.0.1",
|
||||
"version": "14.0.2",
|
||||
"license": {
|
||||
"name": "AGPL 3",
|
||||
"url": "https://www.gnu.org/licenses/agpl.txt"
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ servers:
|
||||
info:
|
||||
title: Nightscout API
|
||||
description: Own your DData with the Nightscout API
|
||||
version: 14.0.1
|
||||
version: 14.0.2
|
||||
license:
|
||||
name: AGPL 3
|
||||
url: 'https://www.gnu.org/licenses/agpl.txt'
|
||||
|
||||
Reference in New Issue
Block a user