Picsur/frontend/src/app/services/storage/cache.service.ts

83 lines
1.8 KiB
TypeScript

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<T> {
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<T>(key: string, value: T): void {
const safeKey = this.transformKey(key);
const data: dataWrapper<T> = {
data: value,
expires: Date.now() + this.cacheExpiresMS,
};
this.storage.setItem(safeKey, JSON.stringify(data));
}
public get<T>(key: string): T | null {
const safeKey = this.transformKey(key);
try {
const data: dataWrapper<T> = 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<T>(
key: string,
finalFallback: T,
...fallbacks: Array<(key: string) => AsyncFailable<T> | Failable<T>>
): Promise<T> {
const cached = this.get<T>(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}`;
}
}