UNPKG

foobot-graphql

Version:

GraphQL server for Foobot device data.

172 lines (149 loc) 5.54 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _typeof2 = require('babel-runtime/helpers/typeof'); var _typeof3 = _interopRequireDefault(_typeof2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _averageBy = require('./average-by'); var _util = require('./util'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * A class for storing data returned by the Foobot API. Since the API is rate * limited, we want to avoid fetching data that we've already seen. Use this * class to store the highest resolution, un-averaged data returned by * the API. Consumers can then request the data from this cache instead, and * it'll do the necessary slicing and averaging using `period` and `averageBy`. */ var debug = require('debug')('foobot-graphql:data-cache'); var MAX_CONNECTED_DISTANCE = 6 * _util.ONE_MINUTE; var MAX_HISTORY_SIZE = 210384; // 2 years worth of five-minute intervals var DataCache = function () { function DataCache() { (0, _classCallCheck3.default)(this, DataCache); this.devices = {}; } (0, _createClass3.default)(DataCache, [{ key: 'updateData', value: function updateData(uuid, data) { var device = this.devices[uuid] = this.devices[uuid] || {}; device.uuid = uuid; device.sensors = data.sensors; device.units = data.units; device.datapoints = device.datapoints || []; var j = 0; var prepended = 0; var appended = 0; var inserted = 0; var skipped = 0; var pruned = 0; for (var i = 0; i < data.datapoints.length; i++) { var datapoint = data.datapoints[i]; var handled = false; while (!handled) { if (j >= device.datapoints.length) { handled = true; device.datapoints.push(datapoint); device.date = data.date; device.expires = data.expires; appended += 1; } else if (datapoint[0] < device.datapoints[j][0]) { handled = true; device.datapoints.splice(j, 0, datapoint); if (j) { inserted += 1; } else { prepended += 1; } j += 1; } else if (datapoint[0] === device.datapoints[j][0]) { handled = true; skipped += 1; j += 1; } else if (datapoint[0] > device.datapoints[j][0]) { j += 1; } } } if (device.datapoints.length > MAX_HISTORY_SIZE) { pruned = device.datapoints.length - MAX_HISTORY_SIZE; device.datapoints.splice(0, pruned); } debug('Added datapoints. ' + ('prepended=' + prepended + ' ') + ('inserted=' + inserted + ' ') + ('appended=' + appended + ' ') + ('skipped=' + skipped + ' ') + ('pruned=' + pruned)); } }, { key: 'add', value: function add(uuid, data) { this.updateData(uuid, data); } }, { key: 'hasCompleteData', value: function hasCompleteData(uuid, period) { var device = this.devices[uuid] || { datapoints: [] }; var datapoints = device.datapoints; if (datapoints.length) { var _ret = function () { var last = datapoints[datapoints.length - 1]; var cutoff = last[0] - period; var index = datapoints.findIndex(function (datapoint) { return datapoint[0] >= cutoff; }); if (index === -1) { return { v: false }; } return { v: datapoints.slice(index).every(function (datapoint, i, array) { var time = datapoint[0] * 1000; var prevTime = (i === 0 ? cutoff : array[i - 1][0]) * 1000; return time - prevTime <= MAX_CONNECTED_DISTANCE; }) }; }(); if ((typeof _ret === 'undefined' ? 'undefined' : (0, _typeof3.default)(_ret)) === "object") return _ret.v; } return false; } }, { key: 'get', value: function get(uuid, period) { var averageBy = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; var device = this.devices[uuid] || { uuid: uuid, start: null, end: null, sensors: ['time', 'pm', 'tmp', 'hum', 'co2', 'voc', 'allpollu'], units: ['s', 'ugm3', 'C', 'pc', 'ppm', 'ppb', '%'], datapoints: [] }; var _device = device, datapoints = _device.datapoints; if (datapoints.length) { (function () { var last = datapoints[datapoints.length - 1]; var cutoff = last[0] - period; var index = datapoints.findIndex(function (datapoint) { return datapoint[0] >= cutoff; }); device = (0, _extends3.default)({}, device, { start: datapoints[index][0], end: last[0], datapoints: datapoints.slice(index) }); if (averageBy >= 300) { device = (0, _averageBy.toAveragedData)(device, period, averageBy); } })(); } return device; } }]); return DataCache; }(); exports.default = DataCache;