bibliogram/src/lib/cache.js

123 lines
2.2 KiB
JavaScript
Raw Normal View History

2020-01-18 15:38:14 +00:00
/**
* @template T
*/
class TtlCache {
2020-01-12 12:50:21 +00:00
/**
2020-01-18 15:38:14 +00:00
* @param {number} ttl time to keep each resource in milliseconds
2020-01-12 12:50:21 +00:00
*/
constructor(ttl) {
this.ttl = ttl
2020-01-18 15:38:14 +00:00
/** @type {Map<string, {data: T, time: number}>} */
2020-01-12 12:50:21 +00:00
this.cache = new Map()
}
clean() {
for (const key of this.cache.keys()) {
this.cleanKey(key)
2020-01-12 12:50:21 +00:00
}
}
cleanKey(key) {
const value = this.cache.get(key)
if (value && Date.now() > value.time + this.ttl) this.cache.delete(key)
}
2020-01-18 15:38:14 +00:00
/**
* @param {string} key
*/
has(key) {
this.cleanKey(key)
return this.hasWithoutClean(key)
}
hasWithoutClean(key) {
2020-01-18 15:38:14 +00:00
return this.cache.has(key)
}
2020-01-12 12:50:21 +00:00
/**
* @param {string} key
*/
get(key) {
this.cleanKey(key)
return this.getWithoutClean(key)
}
getWithoutClean(key) {
2020-01-18 15:38:14 +00:00
const value = this.cache.get(key)
if (value) return value.data
else return null
2020-01-12 12:50:21 +00:00
}
2020-01-18 15:38:14 +00:00
/**
* Returns null if doesn't exist
2020-01-18 15:38:14 +00:00
* @param {string} key
* @param {number} factor factor to divide the result by. use 60*1000 to get the ttl in minutes.
*/
2020-01-14 14:38:33 +00:00
getTtl(key, factor = 1) {
if (this.has(key)) {
return Math.max((Math.floor(Date.now() - this.cache.get(key).time) / factor), 0)
} else {
return null
}
2020-01-14 14:38:33 +00:00
}
2020-01-12 12:50:21 +00:00
/**
* @param {string} key
* @param {any} data
*/
set(key, data) {
this.cache.set(key, {data, time: Date.now()})
}
/**
* @param {string} key
*/
refresh(key) {
this.cache.get(key).time = Date.now()
}
2020-01-18 15:38:14 +00:00
}
class RequestCache extends TtlCache {
/**
* @param {number} ttl time to keep each resource in milliseconds
*/
constructor(ttl) {
super(ttl)
}
2020-01-12 12:50:21 +00:00
/**
* @param {string} key
* @param {() => Promise<T>} callback
* @returns {Promise<T>}
* @template T
*/
getOrFetch(key, callback) {
this.cleanKey(key)
2020-01-12 12:50:21 +00:00
if (this.cache.has(key)) return Promise.resolve(this.get(key))
else {
const pending = callback().then(result => {
this.set(key, result)
return result
})
this.set(key, pending)
return pending
}
}
/**
* @param {string} key
* @param {() => Promise<T>} callback
* @returns {Promise<T>}
* @template T
*/
getOrFetchPromise(key, callback) {
return this.getOrFetch(key, callback).then(result => {
this.cache.delete(key)
return result
})
}
}
2020-01-18 15:38:14 +00:00
module.exports.TtlCache = TtlCache
module.exports.RequestCache = RequestCache