Skip to content

Instantly share code, notes, and snippets.

@7iomka
Created May 24, 2023 19:14
Show Gist options
  • Save 7iomka/8c3373578739dae72526b97c3a2a3928 to your computer and use it in GitHub Desktop.
Save 7iomka/8c3373578739dae72526b97c3a2a3928 to your computer and use it in GitHub Desktop.
http cache
export interface HttpCacheEntry {
data: any;
expires: number;
}
export interface SerializeCacheKeyPayload {
headers?: Record<string, string>;
method?: string;
url: string;
body?: Record<string, any>;
}
export abstract class HttpCache {
/**
* Получить данные из кеша
* @param key - Уникальный ключ кеша
* @example
* ```ts
* cache.get('key');
* ```
*/
public abstract get<T = any>(key: string): T | null;
/**
* Добавить данные в кеш
* @param key - Уникальный ключ кеша
* @param data - Данные для добавления
* @example
* ```ts
* cache.set('key', { ok: true });
* ```
*/
public abstract set(key: string, data: any, ...rest: any): any;
/**
* Удалить закешированные данные по ключу
* @param key - Уникальный ключ кеша
* @xample
* ```ts
* cache.delete('key');
* ```
*/
public abstract delete(key: string): any;
/**
* Полностью очистить кеш
*/
public abstract reset(): any;
/**
* Сгенерировать уникальный ключ кеша из параметров http-запроса
* @example
* ```ts
* cache.serializeCacheKey({
* url: 'https://example.com',
* body: { key: "value" },
* method: "POST"
* })
* ```
*/
// eslint-disable-next-line class-methods-use-this
public serializeCacheKey(payload: SerializeCacheKeyPayload): string {
try {
return JSON.stringify(payload);
} catch (_e) {
// на случай попытки сериализации объекта с циклическими зависимостями внутри
return payload.url + String(Math.random());
}
}
}
const minute = 60000;
export class DefaultHttpCache extends HttpCache {
private static sharedInstance: DefaultHttpCache;
private _map = new Map<string, HttpCacheEntry>();
private _ttl = 10 * minute;
/**
* Синглтон
* @example
* ```ts
* cache.shared.get('key');
* ```
*/
public static get shared(): DefaultHttpCache {
if (!DefaultHttpCache.sharedInstance) {
DefaultHttpCache.sharedInstance = new DefaultHttpCache();
}
return DefaultHttpCache.sharedInstance;
}
/**
* Время жизни кеша в миллисекундах
* @example
* ```ts
* cache.ttl = 60000;
* cache.ttl = Infinity;
* cache.tll = 0;
*
* // негативные значения игнорируются
* cache.ttl = -1;
* cache.ttl = Number.NEGATIVE_INFINITY;
* ```
*/
public get ttl(): number {
return this._ttl;
}
public set ttl(ttl: number) {
if (typeof ttl === 'number' && ttl >= 0) {
this._ttl = ttl;
}
}
/**
* Количество элементов в кеше
*/
public get size(): number {
return this._map.size;
}
public get<T = any>(key: string) {
const data = this._map.get(key);
if (!data) return null;
if (data.expires <= Date.now()) {
this.delete(key);
return null;
}
return data.data as T;
}
public set(key: string, data: any): this {
this._map.set(key, {
data,
expires: Date.now() + this.ttl,
});
return this;
}
public delete(key: string): this {
this._map.delete(key);
return this;
}
public reset(): this {
this._map.clear();
return this;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment