Skip to content

Commit 9315b06

Browse files
authored
Merge pull request #6135 from nightscout/dev
Nightscout 14.0.5 Liquorice
2 parents 6d6cf31 + 4ba636d commit 9315b06

23 files changed

+383
-255
lines changed

app.js

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,25 @@ function create (env, ctx) {
132132
));
133133
});
134134

135+
// Allow static resources to be cached for week
136+
var maxAge = 7 * 24 * 60 * 60 * 1000;
137+
138+
if (process.env.NODE_ENV === 'development') {
139+
maxAge = 1;
140+
console.log('Development environment detected, setting static file cache age to 1 second');
141+
}
142+
143+
var staticFiles = express.static(env.static_files, {
144+
maxAge
145+
});
146+
147+
// serve the static content
148+
app.use(staticFiles);
149+
135150
if (ctx.bootErrors && ctx.bootErrors.length > 0) {
136-
app.get('*', require('./lib/server/booterror')(ctx));
151+
const bootErrorView = require('./lib/server/booterror')(env, ctx);
152+
bootErrorView.setLocals(app.locals);
153+
app.get('*', bootErrorView);
137154
return app;
138155
}
139156

@@ -256,36 +273,6 @@ function create (env, ctx) {
256273
res.sendFile(__dirname + '/swagger.yaml');
257274
});
258275

259-
/* // FOR DEBUGGING MEMORY LEEAKS
260-
if (env.settings.isEnabled('dumps')) {
261-
var heapdump = require('heapdump');
262-
app.get('/api/v2/dumps/start', function(req, res) {
263-
var path = new Date().toISOString() + '.heapsnapshot';
264-
path = path.replace(/:/g, '-');
265-
console.info('writing dump to', path);
266-
heapdump.writeSnapshot(path);
267-
res.send('wrote dump to ' + path);
268-
});
269-
}
270-
*/
271-
272-
// app.get('/package.json', software);
273-
274-
// Allow static resources to be cached for week
275-
var maxAge = 7 * 24 * 60 * 60 * 1000;
276-
277-
if (process.env.NODE_ENV === 'development') {
278-
maxAge = 1;
279-
console.log('Development environment detected, setting static file cache age to 1 second');
280-
}
281-
282-
var staticFiles = express.static(env.static_files, {
283-
maxAge
284-
});
285-
286-
// serve the static content
287-
app.use(staticFiles);
288-
289276
// API docs
290277

291278
const swaggerUi = require('swagger-ui-express');

env.js

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,20 @@ var env = {
1414
settings: require('./lib/settings')()
1515
};
1616

17+
var shadowEnv;
18+
1719
// Module to constrain all config and environment parsing to one spot.
1820
// See README.md for info about all the supported ENV VARs
1921
function config ( ) {
22+
23+
// Assume users will typo whitespaces into keys and values
24+
25+
shadowEnv = {};
26+
27+
Object.keys(process.env).forEach((key, index) => {
28+
shadowEnv[_trim(key)] = _trim(process.env[key]);
29+
});
30+
2031
env.PORT = readENV('PORT', 1337);
2132
env.HOSTNAME = readENV('HOSTNAME', null);
2233
env.IMPORT_CONFIG = readENV('IMPORT_CONFIG', null);
@@ -122,7 +133,7 @@ function updateSettings() {
122133
});
123134

124135
//should always find extended settings last
125-
env.extendedSettings = findExtendedSettings(process.env);
136+
env.extendedSettings = findExtendedSettings(shadowEnv);
126137

127138
if (!readENVTruthy('TREATMENTS_AUTH', true)) {
128139
env.settings.authDefaultRoles = env.settings.authDefaultRoles || "";
@@ -132,10 +143,10 @@ function updateSettings() {
132143

133144
function readENV(varName, defaultValue) {
134145
//for some reason Azure uses this prefix, maybe there is a good reason
135-
var value = process.env['CUSTOMCONNSTR_' + varName]
136-
|| process.env['CUSTOMCONNSTR_' + varName.toLowerCase()]
137-
|| process.env[varName]
138-
|| process.env[varName.toLowerCase()];
146+
var value = shadowEnv['CUSTOMCONNSTR_' + varName]
147+
|| shadowEnv['CUSTOMCONNSTR_' + varName.toLowerCase()]
148+
|| shadowEnv[varName]
149+
|| shadowEnv[varName.toLowerCase()];
139150

140151
if (varName == 'DISPLAY_UNITS') {
141152
if (value && value.toLowerCase().includes('mmol')) {
@@ -162,7 +173,7 @@ function findExtendedSettings (envs) {
162173
extended.devicestatus = {};
163174
extended.devicestatus.advanced = true;
164175
extended.devicestatus.days = 1;
165-
if(process.env['DEVICESTATUS_DAYS'] && process.env['DEVICESTATUS_DAYS'] == '2') extended.devicestatus.days = 1;
176+
if(shadowEnv['DEVICESTATUS_DAYS'] && shadowEnv['DEVICESTATUS_DAYS'] == '2') extended.devicestatus.days = 1;
166177

167178
function normalizeEnv (key) {
168179
return key.toUpperCase().replace('CUSTOMCONNSTR_', '');

lib/data/dataloader.js

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
const _ = require('lodash');
44
const async = require('async');
5-
const times = require('../times');
65
const fitTreatmentsToBGCurve = require('./treatmenttocurve');
76
const constants = require('../constants');
87

@@ -144,8 +143,11 @@ function init(env, ctx) {
144143
done(err, result);
145144
}
146145

147-
// clear treatments to the base set, we're going to merge from multiple queries
148-
ddata.treatments = []; // ctx.cache.treatments ? _.cloneDeep(ctx.cache.treatments) : [];
146+
// clear data we'll get from the cache
147+
148+
ddata.treatments = [];
149+
ddata.devicestatus = [];
150+
ddata.entries = [];
149151

150152
ddata.dbstats = {};
151153

@@ -196,11 +198,8 @@ function loadEntries(ddata, ctx, callback) {
196198

197199
if (!err && results) {
198200

199-
const ageFilter = ddata.lastUpdated - constants.TWO_DAYS;
200201
const r = ctx.ddata.processRawDataForRuntime(results);
201-
ctx.cache.insertData('entries', r, ageFilter);
202-
203-
const currentData = ctx.cache.getData('entries').reverse();
202+
const currentData = ctx.cache.insertData('entries', r).reverse();
204203

205204
const mbgs = [];
206205
const sgvs = [];
@@ -324,12 +323,11 @@ function loadTreatments(ddata, ctx, callback) {
324323

325324
ctx.treatments.list(tq, function(err, results) {
326325
if (!err && results) {
327-
const ageFilter = ddata.lastUpdated - longLoad;
328-
const r = ctx.ddata.processRawDataForRuntime(results);
329326

330-
// update cache
331-
ctx.cache.insertData('treatments', r, ageFilter);
332-
ddata.treatments = ctx.ddata.idMergePreferNew(ddata.treatments, ctx.cache.getData('treatments'));
327+
// update cache and apply to runtime data
328+
const r = ctx.ddata.processRawDataForRuntime(results);
329+
const currentData = ctx.cache.insertData('treatments', r);
330+
ddata.treatments = ctx.ddata.idMergePreferNew(ddata.treatments, currentData);
333331
}
334332

335333
callback();
@@ -361,7 +359,6 @@ function loadProfileSwitchTreatments(ddata, ctx, callback) {
361359
ctx.treatments.list(tq, function(err, results) {
362360
if (!err && results) {
363361
ddata.treatments = mergeProcessSort(ddata.treatments, results);
364-
//mergeToTreatments(ddata, results);
365362
}
366363

367364
// Store last profile switch
@@ -418,7 +415,6 @@ function loadLatestSingle(ddata, ctx, dataType, callback) {
418415
ctx.treatments.list(tq, function(err, results) {
419416
if (!err && results) {
420417
ddata.treatments = mergeProcessSort(ddata.treatments, results);
421-
//mergeToTreatments(ddata, results);
422418
}
423419
callback();
424420
});
@@ -473,16 +469,12 @@ function loadDeviceStatus(ddata, env, ctx, callback) {
473469

474470
ctx.devicestatus.list(opts, function(err, results) {
475471
if (!err && results) {
476-
// ctx.cache.devicestatus = mergeProcessSort(ctx.cache.devicestatus, results, ageFilter);
477472

478-
const ageFilter = ddata.lastUpdated - longLoad;
473+
// update cache and apply to runtime data
479474
const r = ctx.ddata.processRawDataForRuntime(results);
480-
ctx.cache.insertData('devicestatus', r, ageFilter);
481-
482-
const res = ctx.cache.getData('devicestatus');
475+
const currentData = ctx.cache.insertData('devicestatus', r);
483476

484-
const res2 = _.map(res, function eachStatus(result) {
485-
//result.mills = new Date(result.created_at).getTime();
477+
const res2 = _.map(currentData, function eachStatus(result) {
486478
if ('uploaderBattery' in result) {
487479
result.uploader = {
488480
battery: result.uploaderBattery
@@ -492,7 +484,7 @@ function loadDeviceStatus(ddata, env, ctx, callback) {
492484
return result;
493485
});
494486

495-
ddata.devicestatus = mergeProcessSort(ddata.devicestatus, res2, ageFilter);
487+
ddata.devicestatus = mergeProcessSort(ddata.devicestatus, res2);
496488
} else {
497489
ddata.devicestatus = [];
498490
}

lib/data/ddata.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@ function init () {
3232

3333
Object.keys(obj).forEach(key => {
3434
if (typeof obj[key] === 'object' && obj[key]) {
35-
if (obj[key].hasOwnProperty('_id')) {
35+
if (Object.prototype.hasOwnProperty.call(obj[key], '_id')) {
3636
obj[key]._id = obj[key]._id.toString();
3737
}
38-
if (obj[key].hasOwnProperty('created_at') && !obj[key].hasOwnProperty('mills')) {
38+
if (Object.prototype.hasOwnProperty.call(obj[key], 'created_at')
39+
&& !Object.prototype.hasOwnProperty.call(obj[key], 'mills')) {
3940
obj[key].mills = new Date(obj[key].created_at).getTime();
4041
}
41-
if (obj[key].hasOwnProperty('sysTime') && !obj[key].hasOwnProperty('mills')) {
42+
if (Object.prototype.hasOwnProperty.call(obj[key], 'sysTime')
43+
&& !Object.prototype.hasOwnProperty.call(obj[key], 'mills')) {
4244
obj[key].mills = new Date(obj[key].sysTime).getTime();
4345
}
4446
}

lib/profilefunctions.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ function init (profileData) {
6161
// preprocess the timestamps to seconds for a couple orders of magnitude faster operation
6262
profile.preprocessProfileOnLoad = function preprocessProfileOnLoad (container) {
6363
_.each(container, function eachValue (value) {
64+
65+
if (value === null) return;
66+
6467
if (Object.prototype.toString.call(value) === '[object Array]') {
6568
profile.preprocessProfileOnLoad(value);
6669
}

lib/server/booterror.js

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,46 @@
11
'use strict';
22

3+
const express = require('express');
4+
const path = require('path');
35
var _ = require('lodash');
46

5-
var head = '<!DOCTYPE html><html><head><title>Nightscout - Boot Error</title></head><body><h1>Nightscout - Boot Error</h1><dl>';
6-
var tail = '</dl></body></html>';
7+
function bootError(env, ctx) {
78

8-
function bootError(ctx) {
9+
const app = new express();
10+
let locals = {};
11+
12+
app.set('view engine', 'ejs');
13+
app.engine('html', require('ejs').renderFile);
14+
app.set("views", path.join(__dirname, "../../views/"));
15+
16+
app.get('*', (req, res, next) => {
17+
18+
if (req.url.includes('images')) return next();
919

10-
return function pageHandler (req, res) {
1120
var errors = _.map(ctx.bootErrors, function (obj) {
12-
obj.err = _.pick(obj.err, Object.getOwnPropertyNames(obj.err));
13-
return '<dt>' + obj.desc + '</dt><dd>' + JSON.stringify(obj.err).replace(/\\n/g, '<br/>') + '</dd>';
21+
22+
let message;
23+
24+
if (typeof obj.err === 'string' || obj.err instanceof String) {
25+
message = obj.err;
26+
} else {
27+
message = JSON.stringify(_.pick(obj.err, Object.getOwnPropertyNames(obj.err)));
28+
}
29+
return '<dt>' + obj.desc + '</dt><dd>' + message.replace(/\\n/g, '<br/>') + '</dd>';
1430
}).join(' ');
1531

16-
res.set('Content-Type', 'text/html');
17-
res.send(head + errors + tail);
32+
res.render('error.html', {
33+
errors,
34+
locals
35+
});
36+
37+
});
1838

39+
app.setLocals = function (_locals) {
40+
locals = _locals;
1941
}
42+
43+
return app;
2044
}
2145

2246
module.exports = bootError;

lib/server/bootevent.js

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,25 @@ function boot (env, language) {
9595
}
9696
}
9797

98+
function checkSettings (ctx, next) {
99+
100+
ctx.bootErrors = ctx.bootErrors || [];
101+
102+
console.log('Checking settings');
103+
104+
if (!env.storageURI) {
105+
ctx.bootErrors.push({'desc': 'Mandatory setting missing',
106+
err: 'MONGODB_URI setting is missing, cannot connect to database'});
107+
}
108+
109+
if (!env.api_secret) {
110+
ctx.bootErrors.push({'desc': 'Mandatory setting missing',
111+
err: 'API_SECRET setting is missing, cannot enable REST API'});
112+
}
113+
114+
next();
115+
}
116+
98117
function setupStorage (ctx, next) {
99118

100119
if (hasBootErrors(ctx)) {
@@ -107,7 +126,6 @@ function boot (env, language) {
107126
if (err) {
108127
throw err;
109128
}
110-
111129
ctx.store = store;
112130
console.log('OpenAPS Storage system ready');
113131
next();
@@ -116,14 +134,18 @@ function boot (env, language) {
116134
//TODO assume mongo for now, when there are more storage options add a lookup
117135
require('../storage/mongo-storage')(env, function ready(err, store) {
118136
// FIXME, error is always null, if there is an error, the index.js will throw an exception
137+
if (err) {
138+
console.info('ERROR CONNECTING TO MONGO', err);
139+
ctx.bootErrors = ctx.bootErrors || [ ];
140+
ctx.bootErrors.push({'desc': 'Unable to connect to Mongo', err: err});
141+
}
119142
console.log('Mongo Storage system ready');
120143
ctx.store = store;
121-
122144
next();
123145
});
124146
}
125147
} catch (err) {
126-
console.info('mongo err', err);
148+
console.info('ERROR CONNECTING TO MONGO', err);
127149
ctx.bootErrors = ctx.bootErrors || [ ];
128150
ctx.bootErrors.push({'desc': 'Unable to connect to Mongo', err: err});
129151
next();
@@ -233,7 +255,7 @@ function boot (env, language) {
233255
});
234256

235257
ctx.bus.on('data-loaded', function updatePlugins ( ) {
236-
console.info('reloading sandbox data');
258+
// console.info('reloading sandbox data');
237259
var sbx = require('../sandbox')().serverInit(env, ctx);
238260
ctx.plugins.setProperties(sbx);
239261
ctx.notifications.initRequests();
@@ -285,6 +307,7 @@ function boot (env, language) {
285307
.acquire(checkNodeVersion)
286308
.acquire(checkEnv)
287309
.acquire(augmentSettings)
310+
.acquire(checkSettings)
288311
.acquire(setupStorage)
289312
.acquire(setupAuthorization)
290313
.acquire(setupInternals)

0 commit comments

Comments
 (0)