export interface CacheStorage { get(key: string): Promise; set(key: string, value: any): Promise; has(key: string): Promise; del(key: string): Promise; list(): Promise; } export class ExtCache implements CacheStorage { get(key: string): Promise { return new Promise((resolve) => { chrome.storage.session.get(key, (value) => { resolve(value[key]); }); }); } set(key: string, value: any): Promise { return new Promise((resolve) => { chrome.storage.session.set( { [key]: value, }, () => { resolve(); } ); }); } has(key: string): Promise { return new Promise((resolve) => { chrome.storage.session.get(key, (value) => { resolve(value[key] !== undefined); }); }); } del(key: string): Promise { return new Promise((resolve) => { chrome.storage.session.remove(key, () => { resolve(); }); }); } list(): Promise { return new Promise((resolve) => { chrome.storage.session.get(null, (value) => { resolve(Object.keys(value)); }); }); } } export class MapCache { private map: Map = new Map(); get(key: string): Promise { return new Promise((resolve) => { resolve(this.map.get(key)); }); } set(key: string, value: any): Promise { return new Promise((resolve) => { this.map.set(key, value); resolve(); }); } has(key: string): Promise { return new Promise((resolve) => { resolve(this.map.has(key)); }); } del(key: string): Promise { return new Promise((resolve) => { this.map.delete(key); resolve(); }); } list(): Promise { return new Promise((resolve) => { resolve(Array.from(this.map.keys())); }); } } export async function incr(cache: Cache, key: string, increase: number): Promise { const value = await cache.get(key); let num = value || 0; num += increase; await cache.set(key, num); return num; } export default class Cache { static instance: Cache = new Cache(new ExtCache()); static getInstance(): Cache { return Cache.instance; } private constructor(private storage: CacheStorage) {} public get(key: string): Promise { return this.storage.get(key); } public async getOrSet(key: string, set: () => Promise): Promise { let ret = await this.get(key); if (!ret) { ret = await set(); this.set(key, ret); } return Promise.resolve(ret); } public set(key: string, value: any): Promise { return this.storage.set(key, value); } public has(key: string): Promise { return this.storage.has(key); } public del(key: string): Promise { return this.storage.del(key); } public list(): Promise { return this.storage.list(); } }