const { R } = require("redbean-node"); const { log } = require("../src/util"); class Settings { /** * Example: * { * key1: { * value: "value2", * timestamp: 12345678 * }, * key2: { * value: 2, * timestamp: 12345678 * }, * } * @type {{}} */ static cacheList = { }; static cacheCleaner = null; /** * Retrieve value of setting based on key * @param {string} key Key of setting to retrieve * @returns {Promise} Value */ static async get(key) { // Start cache clear if not started yet if (!Settings.cacheCleaner) { Settings.cacheCleaner = setInterval(() => { log.debug("settings", "Cache Cleaner is just started."); for (key in Settings.cacheList) { if (Date.now() - Settings.cacheList[key].timestamp > 60 * 1000) { log.debug("settings", "Cache Cleaner deleted: " + key); delete Settings.cacheList[key]; } } }, 60 * 1000); } // Query from cache if (key in Settings.cacheList) { const v = Settings.cacheList[key].value; log.debug("settings", `Get Setting (cache): ${key}: ${v}`); return v; } let value = await R.getCell("SELECT `value` FROM setting WHERE `key` = ? ", [ key, ]); try { const v = JSON.parse(value); log.debug("settings", `Get Setting: ${key}: ${v}`); Settings.cacheList[key] = { value: v, timestamp: Date.now() }; return v; } catch (e) { return value; } } /** * Sets the specified setting to specified value * @param {string} key Key of setting to set * @param {any} value Value to set to * @param {?string} type Type of setting * @returns {Promise} */ static async set(key, value, type = null) { let bean = await R.findOne("setting", " `key` = ? ", [ key, ]); if (!bean) { bean = R.dispense("setting"); bean.key = key; } bean.type = type; bean.value = JSON.stringify(value); await R.store(bean); Settings.deleteCache([ key ]); } /** * Get settings based on type * @param {string} type The type of setting * @returns {Promise} Settings */ static async getSettings(type) { let list = await R.getAll("SELECT `key`, `value` FROM setting WHERE `type` = ? ", [ type, ]); let result = {}; for (let row of list) { try { result[row.key] = JSON.parse(row.value); } catch (e) { result[row.key] = row.value; } } return result; } /** * Set settings based on type * @param {string} type Type of settings to set * @param {object} data Values of settings * @returns {Promise} */ static async setSettings(type, data) { let keyList = Object.keys(data); let promiseList = []; for (let key of keyList) { let bean = await R.findOne("setting", " `key` = ? ", [ key ]); if (bean == null) { bean = R.dispense("setting"); bean.type = type; bean.key = key; } if (bean.type === type) { bean.value = JSON.stringify(data[key]); promiseList.push(R.store(bean)); } } await Promise.all(promiseList); Settings.deleteCache(keyList); } /** * Delete selected keys from settings cache * @param {string[]} keyList Keys to remove * @returns {void} */ static deleteCache(keyList) { for (let key of keyList) { delete Settings.cacheList[key]; } } /** * Stop the cache cleaner if running * @returns {void} */ static stopCacheCleaner() { if (Settings.cacheCleaner) { clearInterval(Settings.cacheCleaner); Settings.cacheCleaner = null; } } } module.exports = { Settings, };