130 lines
2.6 KiB
TypeScript
130 lines
2.6 KiB
TypeScript
|
type CacheOptions = {
|
||
|
/**
|
||
|
* The time the cached object will be valid for
|
||
|
*/
|
||
|
ttl?: number;
|
||
|
|
||
|
/**
|
||
|
* How often to check for expired objects
|
||
|
*/
|
||
|
checkInterval?: number;
|
||
|
|
||
|
/**
|
||
|
* Enable debug messages
|
||
|
*/
|
||
|
debug?: boolean;
|
||
|
};
|
||
|
|
||
|
type CachedObject = {
|
||
|
/**
|
||
|
* The cached object
|
||
|
*/
|
||
|
value: any;
|
||
|
|
||
|
/**
|
||
|
* The timestamp the object was cached
|
||
|
*/
|
||
|
timestamp: number;
|
||
|
};
|
||
|
|
||
|
export class SSRCache {
|
||
|
/**
|
||
|
* The time the cached object will be valid for
|
||
|
* @private
|
||
|
*/
|
||
|
private readonly ttl: number | undefined;
|
||
|
|
||
|
/**
|
||
|
* How often to check for expired objects
|
||
|
* @private
|
||
|
*/
|
||
|
private readonly checkInterval: number | undefined;
|
||
|
|
||
|
/**
|
||
|
* Enable debug messages
|
||
|
* @private
|
||
|
*/
|
||
|
private readonly debug: boolean;
|
||
|
|
||
|
/**
|
||
|
* The objects that have been cached
|
||
|
* @private
|
||
|
*/
|
||
|
private cache = new Map<string, CachedObject>();
|
||
|
|
||
|
constructor({ ttl, checkInterval, debug }: CacheOptions) {
|
||
|
this.ttl = ttl;
|
||
|
this.checkInterval = checkInterval || this.ttl ? 1000 * 60 : undefined; // 1 minute
|
||
|
this.debug = debug || false;
|
||
|
|
||
|
if (this.ttl !== undefined && this.checkInterval !== undefined) {
|
||
|
setInterval(() => {
|
||
|
for (const [key, value] of this.cache.entries()) {
|
||
|
if (value.timestamp + this.ttl! > Date.now()) {
|
||
|
continue;
|
||
|
}
|
||
|
this.remove(key);
|
||
|
}
|
||
|
}, this.checkInterval);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets an object from the cache
|
||
|
*
|
||
|
* @param key the cache key for the object
|
||
|
*/
|
||
|
public get<T>(key: string): T | undefined {
|
||
|
const cachedObject = this.cache.get(key);
|
||
|
if (cachedObject === undefined) {
|
||
|
if (this.debug) {
|
||
|
console.log(`Cache miss for key: ${key}`);
|
||
|
}
|
||
|
return undefined;
|
||
|
}
|
||
|
if (this.debug) {
|
||
|
console.log(`Retrieved ${key} from cache, value: ${JSON.stringify(cachedObject)}`);
|
||
|
}
|
||
|
return cachedObject.value as T;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets an object in the cache
|
||
|
*
|
||
|
* @param key the cache key
|
||
|
* @param value the object
|
||
|
*/
|
||
|
public set<T>(key: string, value: T): void {
|
||
|
this.cache.set(key, {
|
||
|
value,
|
||
|
timestamp: Date.now(),
|
||
|
});
|
||
|
|
||
|
if (this.debug) {
|
||
|
console.log(`Inserted ${key} into cache, value: ${JSON.stringify(value)}`);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if an object is in the cache
|
||
|
*
|
||
|
* @param key the cache key
|
||
|
*/
|
||
|
public has(key: string): boolean {
|
||
|
return this.cache.has(key);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Removes an object from the cache
|
||
|
*
|
||
|
* @param key the cache key
|
||
|
*/
|
||
|
public remove(key: string): void {
|
||
|
this.cache.delete(key);
|
||
|
|
||
|
if (this.debug) {
|
||
|
console.log(`Removed ${key} from cache`);
|
||
|
}
|
||
|
}
|
||
|
}
|