import { Inject, Injectable } from '@angular/core'; import { SESSION_STORAGE } from '@ng-web-apis/common'; import { AsyncFailable, Failable, HasFailed } from 'picsur-shared/dist/types'; interface dataWrapper { data: T; expires: number; } @Injectable({ providedIn: 'root', }) export class CacheService { private readonly cacheExpiresMS = 1000 * 60 * 60; private cacheVersion = '0.0.0'; constructor(@Inject(SESSION_STORAGE) private readonly storage: Storage) {} public setVersion(version: string): void { if (version !== this.cacheVersion) this.clear(); this.cacheVersion = version; } public clear(): void { this.storage.clear(); } public set(key: string, value: T): void { const safeKey = this.transformKey(key); const data: dataWrapper = { data: value, expires: Date.now() + this.cacheExpiresMS, }; this.storage.setItem(safeKey, JSON.stringify(data)); } public get(key: string): T | null { const safeKey = this.transformKey(key); try { const data: dataWrapper = JSON.parse( this.storage.getItem(safeKey) ?? '', ); if (data && data.data && data.expires > Date.now()) { return data.data; } return null; } catch (e) { return null; } } public async getFallback( key: string, finalFallback: T, ...fallbacks: Array<(key: string) => AsyncFailable | Failable> ): Promise { const cached = this.get(key); if (cached !== null) { return cached; } for (const fallback of fallbacks) { const result = await fallback(key); if (HasFailed(result)) { continue; } this.set(key, result); return result; } return finalFallback; } private transformKey(key: string): string { return `${this.cacheVersion}-${key}`; } }