const TTL_MS = 15 * 60 * 1000; export class ApplianceValues implements Map { private _data: Map = new Map(); private _lastUpdateByResource: Map = new Map(); private _resourceByKey: Map = new Map(); get [Symbol.toStringTag](): string { return 'ApplianceValues'; } get size(): number { return this._data.size; } clear(): void { this._data.clear(); this._lastUpdateByResource.clear(); this._resourceByKey.clear(); } delete(key: string): boolean { const result = this._data.delete(key); this._resourceByKey.delete(key); return result; } forEach( callbackfn: (value: string, key: string, map: Map) => void, ): void { this._data.forEach(callbackfn); } get(key: string): string | undefined { const resource = this._resourceByKey.get(key); if (resource !== undefined) { this._lastUpdateByResource.delete(resource); } return this._data.get(key); } has(key: string): boolean { return this._data.has(key); } set(key: string, value: string): this { this._data.set(key, value); return this; } keys(): IterableIterator { return this._data.keys(); } values(): IterableIterator { return this._data.values(); } entries(): IterableIterator<[string, string]> { return this._data.entries(); } [Symbol.iterator](): IterableIterator<[string, string]> { return this._data[Symbol.iterator](); } getWithInvalidate(key: string, invalidate = true): string | undefined { if (!this._data.has(key)) { return undefined; } if (invalidate && this._resourceByKey.has(key)) { this._lastUpdateByResource.delete(this._resourceByKey.get(key)!); } return this._data.get(key); } shouldResourceBeUpdated(resource: string): boolean { const now = new Date(); const toDelete: string[] = []; for (const [res, lastUpdate] of this._lastUpdateByResource.entries()) { if (now.getTime() - lastUpdate.getTime() >= TTL_MS) { toDelete.push(res); } } for (const res of toDelete) { this._lastUpdateByResource.delete(res); } return !this._lastUpdateByResource.has(resource); } invalidateResource(resource: string): void { this._lastUpdateByResource.delete(resource); } updateByResource(resource: string, data: Record): void { for (const [key, value] of Object.entries(data)) { this._data.set(key, value); } this._lastUpdateByResource.set(resource, new Date()); for (const key of Object.keys(data)) { this._resourceByKey.set(key, resource); } } toJSON(): Record { const obj: Record = {}; for (const [key, value] of this._data) { obj[key] = value; } return obj; } getWithDefault(key: string, defaultValue: string): string { const val = this.get(key); return val !== undefined ? val : defaultValue; } }