50 lines
1.5 KiB
TypeScript
50 lines
1.5 KiB
TypeScript
class CacheEntry<T> {
|
|
public value: T;
|
|
public expiration: Date;
|
|
|
|
constructor(value: T, expiration: Date) {
|
|
this.value = value;
|
|
this.expiration = expiration;
|
|
}
|
|
}
|
|
|
|
export type ExpirationSupplier<T> = (v: T) => Date;
|
|
|
|
export class RegionalMarketCache<T> {
|
|
private cache: Record<number, Record<number, CacheEntry<T>>>;
|
|
private expirationSupplier: (v: T) => Date;
|
|
|
|
constructor(expiration: ExpirationSupplier<T> | number) {
|
|
this.cache = {};
|
|
this.expirationSupplier = expiration instanceof Function ? expiration : () => new Date(Date.now() + expiration);
|
|
}
|
|
|
|
public get(regionId: number, typeId: number): T | undefined {
|
|
const entry = this.cache[regionId]?.[typeId];
|
|
|
|
if (entry && entry.expiration > new Date()) {
|
|
return entry.value;
|
|
}
|
|
this.remove(regionId, typeId);
|
|
return undefined;
|
|
}
|
|
|
|
public set(regionId: number, typeId: number, value: T): void {
|
|
this.cache[regionId] = this.cache[regionId] ?? {};
|
|
this.cache[regionId][typeId] = new CacheEntry(value, this.expirationSupplier(value));
|
|
}
|
|
|
|
public remove(regionId: number, typeId: number): void {
|
|
delete this.cache[regionId]?.[typeId];
|
|
}
|
|
|
|
public async computeIfAbsent(regionId: number, typeId: number, supplier: () => (Promise<T> | T)): Promise<T> {
|
|
let value = this.get(regionId, typeId);
|
|
|
|
if (!value) {
|
|
value = await supplier();
|
|
this.set(regionId, typeId, value);
|
|
}
|
|
return value;
|
|
}
|
|
}; |