UNPKG

@ngx-cache/fs-storage

Version:
213 lines (206 loc) 7.08 kB
import { ɵɵinject, ɵɵdefineInjectable, ɵsetClassMetadata, Injectable } from '@angular/core'; import { Storage } from '@ngx-cache/core'; import { EventEmitter } from 'events'; import { statSync, readdirSync, mkdirSync, writeFileSync, readFileSync, rmdirSync, unlinkSync } from 'fs'; import { resolve, join } from 'path'; class FsStorageLoader { } class FsStorageStaticLoader { constructor(providedSettings = { path: './.cache', quota: 5 * 1024 * 1024 }) { this.providedSettings = providedSettings; } get path() { return this.providedSettings.path; } get quota() { return this.providedSettings.quota; } } class FsEvent { constructor(key, oldValue, newValue, pid, area = 'fs-storage') { this.key = key; this.oldValue = oldValue; this.newValue = newValue; this.pid = pid; this.area = area; } } class FsItemMetadata { constructor(key, index) { this.key = key; this.index = index; } } class FsStorageService extends Storage { constructor(loader) { super(); this.loader = loader; this.instances = {}; this.path = resolve(this.loader.path); this.quota = this.loader.quota; if (this.instances[this.path]) { return this.instances[this.path]; } this.length = 0; this.keys = []; this.pid = `pid:${process.pid}`; this.metadata = new Map(); this.bytesUsed = 0; try { let stat = statSync(this.path); if (!stat.hasOwnProperty('isDirectory')) { throw new Error(`A file exists at the location ${this.path} when trying to create/open localStorage`); } this.length = 0; this.keys = readdirSync(this.path); this.bytesUsed = 0; const decodedKeys = []; this.keys.forEach((key, index) => { const decodedKey = decodeURIComponent(key); decodedKeys.push(decodedKey); const item = new FsItemMetadata(key, index); this.metadata[decodedKey] = item; stat = this.getStats(key); if (!stat.hasOwnProperty('size')) { item.size = stat.size; this.metadata[decodedKey] = item; this.bytesUsed += stat.size; } }); this.keys = decodedKeys; this.length = this.keys.length; } catch (error) { mkdirSync(this.path); } this.instances[this.path] = this; } setItem(key, value) { const hasListeners = EventEmitter.listenerCount(this, 'fs-storage'); const oldValue = hasListeners ? this.getItem(key) : undefined; let item = this.metadata[key]; const oldLength = item ? item.size : 0; if (this.bytesUsed - oldLength + Number(value.toString().length) > this.quota) { throw new Error(`Disk quota (${this.quota / 1024}KB) has been reached!`); } const encodedKey = encodeURIComponent(key); const filename = join(this.path, encodedKey); writeFileSync(filename, value.toString(), 'utf8'); if (!item) { item = new FsItemMetadata(encodedKey, this.keys.push(key) - 1); item.size = value.toString().length; this.length += 1; this.metadata[key] = item; this.bytesUsed += value.toString().length; } if (!hasListeners) { return false; } const e = new FsEvent(key, oldValue, value, this.pid); return this.emit('fs-storage', e); } getItem(key) { const item = this.metadata[key]; if (item) { const filename = join(this.path, item.key); try { return readFileSync(filename, 'utf8'); } catch (error) { this.removeItem(key); } } return undefined; } removeItem(key) { const hasListeners = EventEmitter.listenerCount(this, 'fs-storage'); const oldValue = hasListeners ? this.getItem(key) : undefined; const item = this.metadata[key]; if (item) { delete this.metadata[key]; this.length -= 1; this.bytesUsed -= item.size; this.keys.splice(item.index, 1); const metadataRef = this.metadata; metadataRef.forEach((k) => { const i = this.metadata[k]; if (i.index > item.index) { i.index -= 1; } }); const itemPath = join(this.path, item.key); try { this.deletePath(itemPath); } catch (error) { } if (!hasListeners) { return false; } const e = new FsEvent(key, oldValue, undefined, this.pid); return this.emit('fs-storage', e); } return false; } key(index) { return this.keys[index]; } clear() { this.deleteDirectory(this.path); this.length = 0; this.keys = []; this.metadata = new Map(); this.bytesUsed = 0; const hasListeners = EventEmitter.listenerCount(this, 'fs-storage'); if (!hasListeners) { return false; } const e = new FsEvent(undefined, undefined, undefined, this.pid); return this.emit('fs-storage', e); } getStats(key) { const filename = join(this.path, encodeURIComponent(key)); try { return statSync(filename); } catch (error) { return undefined; } } deleteDirectory(dirPath) { const contents = readdirSync(dirPath); contents.forEach((path) => { const joined = join(dirPath, path); this.deletePath(joined); }); } deletePath(path) { const isDirectory = statSync(path).isDirectory(); if (isDirectory) { this.deleteDirectory(path); rmdirSync(path); } else { unlinkSync(path); } } deleteInstance() { delete this.instances[this.path]; this.deletePath(this.path); this.length = 0; this.keys = []; this.metadata = new Map(); this.bytesUsed = 0; } } FsStorageService.ɵfac = function FsStorageService_Factory(t) { return new (t || FsStorageService)(ɵɵinject(FsStorageLoader)); }; FsStorageService.ɵprov = ɵɵdefineInjectable({ token: FsStorageService, factory: FsStorageService.ɵfac }); (function () { ɵsetClassMetadata(FsStorageService, [{ type: Injectable }], function () { return [{ type: FsStorageLoader }]; }, null); })(); const fsStorageFactory = () => new FsStorageStaticLoader(); export { FsStorageLoader, FsStorageService, FsStorageStaticLoader, fsStorageFactory }; //# sourceMappingURL=ngx-cache-fs-storage.js.map