UNPKG

domotz-remote-pawn

Version:

Domotz Agent

162 lines (144 loc) 5.65 kB
/** This file is part of Domotz Agent. * Copyright (C) 2016 Domotz Ltd * * Domotz Agent is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Domotz Agent is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Domotz Agent. If not, see <http://www.gnu.org/licenses/>. * * Created by Andrea Azzarà <a.azzara@domotz.com> on 04/07/18. */ function httpOutCache(resourceLocator) { var defaultExpiration = resourceLocator.settingsManager ? resourceLocator.settingsManager.getSetting('configuration.settings.http_out_cache_default_expiration', 168) : 168; //7 days var maxCacheEntries = resourceLocator.settingsManager ? resourceLocator.settingsManager.getSetting('configuration.settings.http_out_cache_max_entries', 30000) : 30000; var stringify = resourceLocator.stringify; var crypto = resourceLocator.crypto; var _ = resourceLocator.lodash; var os = resourceLocator.os; var outboundCache = {}; var fileUtils = resourceLocator.utils.file; var path = resourceLocator.path; var fsCachePath = path.join(os.tmpdir(), 'domotz_http_cache.json'); var changed = false; var myConsole = resourceLocator.log.decorateLogs(); var lazyLoaded = false; function _getKey(method, resource) { return method + '+' + resource; } function _createHash(body) { // JSON normalization so that it is deterministic in sending to engine and the md5 has reason to exists var normalisedStrPayload = stringify(body); return crypto.createHash('md5').update(normalisedStrPayload).digest('hex'); } /** * @param resource (http resource) * @param method (http method) * @param body * @param expiration (unix timestamp with ms resolution e.g., new Date().getTime()). * '0' or 'null' mean no expiration. */ function storeCallHash(resource, method, body, expiration) { if (Object.keys(outboundCache).length > maxCacheEntries) { myConsole.warn('Cache is full'); return; } if (expiration === null || expiration === 0) { expiration = null; } else if (typeof expiration === 'undefined') { expiration = expirationInNHours(defaultExpiration); } var key = _getKey(method, resource); myConsole.debug( 'Storing entry for %s with expiration %s hours', key, expiration ? Math.round((expiration - new Date().getTime()) / (1000 * 3600)) : '-' ); outboundCache[key] = { hash: _createHash(body), expiration: expiration, }; changed = true; } function checkCallHash(resource, method, body) { if (!lazyLoaded) { loadCache(); } var hash = _createHash(body); var key = _getKey(method, resource); if (key in outboundCache && hash === outboundCache[key].hash) { if (outboundCache[key].expiration) { var now = new Date().getTime(); if (outboundCache[key].expiration < now) { myConsole.debug('Deleting expired entry for %s with expiration %s', key); delete outboundCache[key]; return false; } } myConsole.debug('Cache hit for %s', key); return true; } myConsole.debug('Cache miss for %s', key); return false; } function getTable() { myConsole.verbose('Cache content %s', JSON.stringify(outboundCache)); return outboundCache; } function resetCache() { outboundCache = {}; fileUtils.deleteFile(fsCachePath); } function cleanup() { var now = new Date().getTime(); _.forOwn(outboundCache, function (value, key) { if (value.expiration && value.expiration < now) { myConsole.debug('Removing expired key from cache %s', key); delete outboundCache[key]; } }); } function expirationInNHours(n) { return new Date().getTime() + n * 3600 * 1000; } function loadCache() { myConsole.info('reading table from fs'); var content = fileUtils.readFile(fsCachePath, JSON.parse); lazyLoaded = true; if (!content) { return; } outboundCache = content; cleanup(); myConsole.info('Loaded %s entries from cache ', Object.keys(outboundCache).length); myConsole.verbose('Cache content: %s', JSON.stringify(outboundCache)); } function storeCache() { if (Object.keys(outboundCache).length > 0 && changed) { myConsole.info('Storing cache to fs'); fileUtils.writeFileSafe(fsCachePath, JSON.stringify(outboundCache)); } } return { checkCallHash: checkCallHash, storeCallHash: storeCallHash, getTable: getTable, resetCache: resetCache, cleanup: cleanup, expirationInNHours: expirationInNHours, loadCache: loadCache, storeCache: storeCache, }; } module.exports.httpOutCache = httpOutCache;