import mkdirp from 'mkdirp'; import fs from 'fs'; import path from 'path'; class LocalStorage { constructor (basePath) { this._basePath = basePath; // Debounce writes on a per key basis this._timeouts = {}; this._buffer = {}; mkdirp.sync(basePath); console.log(`[localstorage] Initialized at ${basePath}`); } setItem (key, obj) { clearTimeout(this._timeouts[key]); this._buffer[key] = JSON.stringify(obj); this._timeouts[key] = setTimeout(this._flush.bind(this), 100); } getItem (key, defaultObj) { // Make sure things are flushed before we read this._flush(); let contents = JSON.stringify(defaultObj); const path = this._getKeyPath(key); try { contents = fs.readFileSync(path); } catch (e) { if (e.code === 'ENOENT') { this.setItem(key, defaultObj); } } try { return JSON.parse(contents) } catch (e) { console.error(`[localstorage] Failed to parse item from LocalStorage: ${e}`) return defaultObj; } } _flush () { const keys = Object.keys(this._buffer); if (!keys.length) { return; } for (const key of keys) { const contents = this._buffer[key]; const path = this._getKeyPath(key); delete this._buffer[key]; try { fs.writeFileSync(path, contents); } catch (e) { console.error(`[localstorage] Failed to save to LocalStorage: ${e}`) } } } _getKeyPath (key) { return path.join(this._basePath, key) } } export default LocalStorage;