UNPKG

@axway/axway-central-cli

Version:

Manage APIs, services and publish to the Amplify Marketplace

146 lines (139 loc) 6.14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CacheController = void 0; var _dayjs = _interopRequireDefault(require("dayjs")); var _fsExtra = require("fs-extra"); var _isEmpty = _interopRequireDefault(require("lodash/isEmpty")); var _nodeCache = _interopRequireDefault(require("node-cache")); var _os = require("os"); var _path = _interopRequireDefault(require("path")); var _snooplogg = _interopRequireDefault(require("snooplogg")); var _types = require("./types"); var _utils = require("./utils"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } const { log } = (0, _snooplogg.default)('central: CacheController'); /** * Note: this file intentionally exporting only a single instance of CacheController, * since its possible to face a race condition when multiple instances will try to read/write file at the same time * Please do not use this class directly or rework the logic before. */ class CacheControllerClass { constructor() { _defineProperty(this, "cacheFilePath", _path.default.join((0, _os.homedir)(), '.axway', 'central', 'cache.json')); _defineProperty(this, "cache", new _nodeCache.default()); // note: init cache fire only once since using only a single instance of the class, remove if this will change this.initCacheFile(); this.readFromFile(); } /** * Inits and validate cache file, should run once before using this class in the code (initialized in cli.ts currently) * An empty JSON file will be created if it is not exists of the file size is more than some value. */ initCacheFile() { try { if ((0, _fsExtra.pathExistsSync)(this.cacheFilePath)) { log(`init, cache file found at ${this.cacheFilePath}`); const stats = (0, _fsExtra.lstatSync)(this.cacheFilePath); log(`init, cache file size: ${Math.round(stats.size / 1000)} kb`); if (stats.size >= _types.MAX_CACHE_FILE_SIZE) { // validating the size log(`init, cache size is exceeding the max allowed size of ${Math.round(_types.MAX_CACHE_FILE_SIZE / 1000)} kb, resetting the file`); (0, _fsExtra.outputJsonSync)(this.cacheFilePath, {}); } else if (!(0, _utils.isValidJson)((0, _fsExtra.readFileSync)(this.cacheFilePath, 'utf8'))) { // validating the content log('init, cache content is invalid, resetting the file '); (0, _fsExtra.outputJsonSync)(this.cacheFilePath, {}); } } else { log(`init, cache file not found, creating an empty one at ${this.cacheFilePath}`); (0, _fsExtra.outputJsonSync)(this.cacheFilePath, {}); } } catch (e) { log(`cannot initialize cache file`, e); } } /** * Set the key in memory cache. * @param key cache key to set * @param value value to set, note that setting "undefined" value will result in "null" value stored * @returns CacheController instance */ set(key, value) { this.cache.set(key, value); return this; } /** * Returns the key value from the memory cache. * @param key key to get * @returns key value */ get(key) { return this.cache.get(key); } /** * Load stored cache from the file into memory and checks its timestamp. * If the timestamp is more than X days old it will reset the file without any changes to cache. * Note: using this method before writeToFile() will override keys in memory cache with the same name. * @returns CacheController instance */ readFromFile() { try { log('reading cache from the file'); const jsonData = (0, _fsExtra.readFileSync)(this.cacheFilePath, 'utf8'); const storedCache = JSON.parse(jsonData); // validate values stored in the cache, reset the content of the file if its not empty already. if (storedCache.data && storedCache.metadata && storedCache.metadata.modifyTimestamp && (0, _dayjs.default)().diff(storedCache.metadata.modifyTimestamp, 'milliseconds') < _types.CACHE_FILE_TTL_MILLISECONDS) { for (const [key, val] of Object.entries(storedCache.data)) { if (storedCache.data.hasOwnProperty(key)) { this.cache.set(key, val); } } } else if (!(0, _isEmpty.default)(storedCache)) { log('timestamp or content is not valid and file is not empty, resetting the cache file'); (0, _fsExtra.outputJsonSync)(this.cacheFilePath, {}); } } catch (e) { log('cannot read cache from the file', e); } finally { return this; } } /** * Writes current set of keys to the json file with following structure: * { * metadata: { * modifyTimestamp: current timestamp, used on read for TTL validation * schemaVersion: indicates the version of cache file structure, can be used later on if changing it. * }, * data: {} key-value cache data * } * @returns CacheController instance */ writeToFile() { try { log('writing cache to the file'); const keys = this.cache.keys(); const cachedData = this.cache.mget(keys); const dataToStore = { metadata: { modifyTimestamp: Date.now(), schemaVersion: '1' }, data: cachedData }; (0, _utils.writeToFile)(this.cacheFilePath, JSON.stringify(dataToStore)); } catch (e) { log('cannot write cache to the file', e); } finally { return this; } } } const CacheController = exports.CacheController = new CacheControllerClass();