Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/ISSUE_TEMPLATE/--bug-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ label: bug

---

**If you need support for Nightscout, PLEASE DO NOT FILE A TICKET HERE**
For support, please post a question to the "CGM in The Cloud" group in Facebook
(https://www.facebook.com/groups/cgminthecloud) or visit the WeAreNotWaiting Discord at https://discord.gg/zg7CvCQ

**Describe the bug**
A clear and concise description of what the bug is.

Expand Down
4 changes: 4 additions & 0 deletions .github/ISSUE_TEMPLATE/--feature-request--.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ about: Suggest an idea for this project

---

**If you need support for Nightscout, PLEASE DO NOT FILE A TICKET HERE**
For support, please post a question to the "CGM in The Cloud" group in Facebook
(https://www.facebook.com/groups/cgminthecloud) or visit the WeAreNotWaiting Discord at https://discord.gg/zg7CvCQ

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Expand Down
4 changes: 3 additions & 1 deletion .github/ISSUE_TEMPLATE/--individual-troubleshooting-help.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ about: Getting help with your own individual setup of Nightscout

Having issues getting Nightscout up and running? Instead of creating an issue here, please use one of the existing support channels for Nightscout.

The documentation for Nightscout lives at (https://nightscout.github.io)

The main support channel is on Facebook: please join the CGM In The Cloud Facebook group (https://www.facebook.com/groups/cgminthecloud) and start a post there.

**Suggestions to include in your post when you are asking for help:**
1. Include what you are trying to do: ("*I am trying to set up Nightscout for the first time.*")
2. Include which step you are on and what the problem is: ("*I deployed on Heroku, but I'm not seeing any BG data.*")
3. If possible, include a link to the version of documentation you are following ("*I'm following the OpenAPS Nightscout setup docs (https://openaps.readthedocs.io/en/latest/docs/While%20You%20Wait%20For%20Gear/nightscout-setup.html#nightscout-setup-with-heroku)*")

Other places you can find support and assistance for Nightscout include Gitter's [nightscout/public](https://gitter.im/nightscout/public) channel.
Other places you can find support and assistance for Nightscout include our Discord channel at (https://discord.gg/zg7CvCQ)
49 changes: 18 additions & 31 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,25 @@ function create (env, ctx) {
));
});

// Allow static resources to be cached for week
var maxAge = 7 * 24 * 60 * 60 * 1000;

if (process.env.NODE_ENV === 'development') {
maxAge = 1;
console.log('Development environment detected, setting static file cache age to 1 second');
}

var staticFiles = express.static(env.static_files, {
maxAge
});

// serve the static content
app.use(staticFiles);

if (ctx.bootErrors && ctx.bootErrors.length > 0) {
app.get('*', require('./lib/server/booterror')(ctx));
const bootErrorView = require('./lib/server/booterror')(env, ctx);
bootErrorView.setLocals(app.locals);
app.get('*', bootErrorView);
return app;
}

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

/* // FOR DEBUGGING MEMORY LEEAKS
if (env.settings.isEnabled('dumps')) {
var heapdump = require('heapdump');
app.get('/api/v2/dumps/start', function(req, res) {
var path = new Date().toISOString() + '.heapsnapshot';
path = path.replace(/:/g, '-');
console.info('writing dump to', path);
heapdump.writeSnapshot(path);
res.send('wrote dump to ' + path);
});
}
*/

// app.get('/package.json', software);

// Allow static resources to be cached for week
var maxAge = 7 * 24 * 60 * 60 * 1000;

if (process.env.NODE_ENV === 'development') {
maxAge = 1;
console.log('Development environment detected, setting static file cache age to 1 second');
}

var staticFiles = express.static(env.static_files, {
maxAge
});

// serve the static content
app.use(staticFiles);

// API docs

const swaggerUi = require('swagger-ui-express');
Expand Down
23 changes: 17 additions & 6 deletions env.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,20 @@ var env = {
settings: require('./lib/settings')()
};

var shadowEnv;

// Module to constrain all config and environment parsing to one spot.
// See README.md for info about all the supported ENV VARs
function config ( ) {

// Assume users will typo whitespaces into keys and values

shadowEnv = {};

Object.keys(process.env).forEach((key, index) => {
shadowEnv[_trim(key)] = _trim(process.env[key]);
});

env.PORT = readENV('PORT', 1337);
env.HOSTNAME = readENV('HOSTNAME', null);
env.IMPORT_CONFIG = readENV('IMPORT_CONFIG', null);
Expand Down Expand Up @@ -122,7 +133,7 @@ function updateSettings() {
});

//should always find extended settings last
env.extendedSettings = findExtendedSettings(process.env);
env.extendedSettings = findExtendedSettings(shadowEnv);

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

function readENV(varName, defaultValue) {
//for some reason Azure uses this prefix, maybe there is a good reason
var value = process.env['CUSTOMCONNSTR_' + varName]
|| process.env['CUSTOMCONNSTR_' + varName.toLowerCase()]
|| process.env[varName]
|| process.env[varName.toLowerCase()];
var value = shadowEnv['CUSTOMCONNSTR_' + varName]
|| shadowEnv['CUSTOMCONNSTR_' + varName.toLowerCase()]
|| shadowEnv[varName]
|| shadowEnv[varName.toLowerCase()];

if (varName == 'DISPLAY_UNITS') {
if (value && value.toLowerCase().includes('mmol')) {
Expand All @@ -162,7 +173,7 @@ function findExtendedSettings (envs) {
extended.devicestatus = {};
extended.devicestatus.advanced = true;
extended.devicestatus.days = 1;
if(process.env['DEVICESTATUS_DAYS'] && process.env['DEVICESTATUS_DAYS'] == '2') extended.devicestatus.days = 1;
if(shadowEnv['DEVICESTATUS_DAYS'] && shadowEnv['DEVICESTATUS_DAYS'] == '2') extended.devicestatus.days = 1;

function normalizeEnv (key) {
return key.toUpperCase().replace('CUSTOMCONNSTR_', '');
Expand Down
36 changes: 14 additions & 22 deletions lib/data/dataloader.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

const _ = require('lodash');
const async = require('async');
const times = require('../times');
const fitTreatmentsToBGCurve = require('./treatmenttocurve');
const constants = require('../constants');

Expand Down Expand Up @@ -144,8 +143,11 @@ function init(env, ctx) {
done(err, result);
}

// clear treatments to the base set, we're going to merge from multiple queries
ddata.treatments = []; // ctx.cache.treatments ? _.cloneDeep(ctx.cache.treatments) : [];
// clear data we'll get from the cache

ddata.treatments = [];
ddata.devicestatus = [];
ddata.entries = [];

ddata.dbstats = {};

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

if (!err && results) {

const ageFilter = ddata.lastUpdated - constants.TWO_DAYS;
const r = ctx.ddata.processRawDataForRuntime(results);
ctx.cache.insertData('entries', r, ageFilter);

const currentData = ctx.cache.getData('entries').reverse();
const currentData = ctx.cache.insertData('entries', r).reverse();

const mbgs = [];
const sgvs = [];
Expand Down Expand Up @@ -324,12 +323,11 @@ function loadTreatments(ddata, ctx, callback) {

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

// update cache
ctx.cache.insertData('treatments', r, ageFilter);
ddata.treatments = ctx.ddata.idMergePreferNew(ddata.treatments, ctx.cache.getData('treatments'));
// update cache and apply to runtime data
const r = ctx.ddata.processRawDataForRuntime(results);
const currentData = ctx.cache.insertData('treatments', r);
ddata.treatments = ctx.ddata.idMergePreferNew(ddata.treatments, currentData);
}

callback();
Expand Down Expand Up @@ -361,7 +359,6 @@ function loadProfileSwitchTreatments(ddata, ctx, callback) {
ctx.treatments.list(tq, function(err, results) {
if (!err && results) {
ddata.treatments = mergeProcessSort(ddata.treatments, results);
//mergeToTreatments(ddata, results);
}

// Store last profile switch
Expand Down Expand Up @@ -418,7 +415,6 @@ function loadLatestSingle(ddata, ctx, dataType, callback) {
ctx.treatments.list(tq, function(err, results) {
if (!err && results) {
ddata.treatments = mergeProcessSort(ddata.treatments, results);
//mergeToTreatments(ddata, results);
}
callback();
});
Expand Down Expand Up @@ -473,16 +469,12 @@ function loadDeviceStatus(ddata, env, ctx, callback) {

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

const ageFilter = ddata.lastUpdated - longLoad;
// update cache and apply to runtime data
const r = ctx.ddata.processRawDataForRuntime(results);
ctx.cache.insertData('devicestatus', r, ageFilter);

const res = ctx.cache.getData('devicestatus');
const currentData = ctx.cache.insertData('devicestatus', r);

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

ddata.devicestatus = mergeProcessSort(ddata.devicestatus, res2, ageFilter);
ddata.devicestatus = mergeProcessSort(ddata.devicestatus, res2);
} else {
ddata.devicestatus = [];
}
Expand Down
8 changes: 5 additions & 3 deletions lib/data/ddata.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ function init () {

Object.keys(obj).forEach(key => {
if (typeof obj[key] === 'object' && obj[key]) {
if (obj[key].hasOwnProperty('_id')) {
if (Object.prototype.hasOwnProperty.call(obj[key], '_id')) {
obj[key]._id = obj[key]._id.toString();
}
if (obj[key].hasOwnProperty('created_at') && !obj[key].hasOwnProperty('mills')) {
if (Object.prototype.hasOwnProperty.call(obj[key], 'created_at')
&& !Object.prototype.hasOwnProperty.call(obj[key], 'mills')) {
obj[key].mills = new Date(obj[key].created_at).getTime();
}
if (obj[key].hasOwnProperty('sysTime') && !obj[key].hasOwnProperty('mills')) {
if (Object.prototype.hasOwnProperty.call(obj[key], 'sysTime')
&& !Object.prototype.hasOwnProperty.call(obj[key], 'mills')) {
obj[key].mills = new Date(obj[key].sysTime).getTime();
}
}
Expand Down
3 changes: 3 additions & 0 deletions lib/profilefunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ function init (profileData) {
// preprocess the timestamps to seconds for a couple orders of magnitude faster operation
profile.preprocessProfileOnLoad = function preprocessProfileOnLoad (container) {
_.each(container, function eachValue (value) {

if (value === null) return;

if (Object.prototype.toString.call(value) === '[object Array]') {
profile.preprocessProfileOnLoad(value);
}
Expand Down
40 changes: 32 additions & 8 deletions lib/server/booterror.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,46 @@
'use strict';

const express = require('express');
const path = require('path');
var _ = require('lodash');

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

function bootError(ctx) {
const app = new express();
let locals = {};

app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);
app.set("views", path.join(__dirname, "../../views/"));

app.get('*', (req, res, next) => {

if (req.url.includes('images')) return next();

return function pageHandler (req, res) {
var errors = _.map(ctx.bootErrors, function (obj) {
obj.err = _.pick(obj.err, Object.getOwnPropertyNames(obj.err));
return '<dt>' + obj.desc + '</dt><dd>' + JSON.stringify(obj.err).replace(/\\n/g, '<br/>') + '</dd>';

let message;

if (typeof obj.err === 'string' || obj.err instanceof String) {
message = obj.err;
} else {
message = JSON.stringify(_.pick(obj.err, Object.getOwnPropertyNames(obj.err)));
}
return '<dt>' + obj.desc + '</dt><dd>' + message.replace(/\\n/g, '<br/>') + '</dd>';
}).join(' ');

res.set('Content-Type', 'text/html');
res.send(head + errors + tail);
res.render('error.html', {
errors,
locals
});

});

app.setLocals = function (_locals) {
locals = _locals;
}

return app;
}

module.exports = bootError;
Loading