scryfall-sdk
Version:
A Node.js SDK for https://scryfall.com/docs/api written in Typescript.
133 lines (132 loc) • 5.29 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
// 10 seconds minimum cache time (configuring it lower disables caching)
const MIN_CACHE_DURATION = 1000 * 10;
// 1 hour default cache time
const DEFAULT_CACHE_DURATION = 1000 * 60 * 60;
let configuredCacheDuration = DEFAULT_CACHE_DURATION;
const MIN_CACHE_LIMIT = 1;
const DEFAULT_CACHE_LIMIT = 500;
let configuredCacheLimit = DEFAULT_CACHE_LIMIT;
let caches = [];
function Cached(target, key, descriptor) {
let topCache = { map: new Map(), time: 0 };
return {
value(...args) {
let cache = topCache;
let shouldCache = false;
if (configuredCacheDuration >= MIN_CACHE_DURATION && configuredCacheLimit >= MIN_CACHE_LIMIT) {
// only put together caches when caches are enabled
let now = Date.now();
for (let i = 0; i < args.length; i++) {
const arg = args[i];
// caches are applied to methods that take misc args, so they don't get handy query strings to hash by
// as a result it's a pyramid of caches indexed by the arguments passed to the query methods
let nextCache = cache.map.get(arg);
if (!nextCache) {
nextCache = { key: arg, map: new Map(), time: 0 };
cache.map.set(arg, nextCache);
nextCache.parent = cache;
}
cache = nextCache;
}
if (now - cache.time < configuredCacheDuration)
return cache.value;
cache.time = now;
shouldCache = true;
}
const result = descriptor.value.apply(this, args);
if (shouldCache) {
cache.value = result;
caches.push(cache);
while (caches.length > configuredCacheLimit)
deleteCacheValue(caches.shift());
handleCacheGarbageCollection(false);
}
return result;
},
};
}
function deleteCacheValue(cache) {
var _a;
delete cache.value;
if (cache.map.size === 0)
(_a = cache.parent) === null || _a === void 0 ? void 0 : _a.map.delete(cache.key);
}
let garbageCollectionTimer;
function handleCacheGarbageCollection(reset) {
if (!reset && garbageCollectionTimer !== undefined)
// garbage collection already running, no need to start it up again
return;
if (garbageCollectionTimer !== undefined && reset)
clearInterval(garbageCollectionTimer);
if (configuredCacheDuration < MIN_CACHE_DURATION || configuredCacheLimit < MIN_CACHE_LIMIT) {
// caching is disabled
// if there's anything still cached, uncache it
caches.forEach(deleteCacheValue);
caches = [];
return;
}
garbageCollectionTimer = setInterval(() => {
const now = Date.now();
let newCaches = caches;
for (let i = 0; i < caches.length; i++) {
const cache = caches[i];
if (now - cache.time > configuredCacheDuration) {
deleteCacheValue(cache);
newCaches = [];
}
else {
// the cache array is ordered, so if we encounter a cache that shouldn't be deleted, it means the rest of them
// should be preserved, so a slice is enough
// we don't even need to bother slicing the cache array if this the very first cache
if (i)
newCaches = caches.slice(i);
break;
}
}
caches = newCaches;
if (caches.length === 0 && garbageCollectionTimer !== undefined) {
clearInterval(garbageCollectionTimer);
garbageCollectionTimer = undefined;
}
}, Math.sqrt(configuredCacheDuration / 1000) * 2000);
}
(function (Cached) {
function getObjectsCount() {
return caches.length;
}
Cached.getObjectsCount = getObjectsCount;
function isGarbageCollectorRunning() {
return garbageCollectionTimer !== undefined;
}
Cached.isGarbageCollectorRunning = isGarbageCollectorRunning;
function clear() {
caches.forEach(deleteCacheValue);
caches = [];
}
Cached.clear = clear;
function resetCacheDuration() {
setDuration(DEFAULT_CACHE_DURATION);
}
Cached.resetCacheDuration = resetCacheDuration;
function setDuration(ms) {
if (configuredCacheDuration !== ms) {
configuredCacheDuration = ms;
handleCacheGarbageCollection(true);
}
}
Cached.setDuration = setDuration;
function resetLimit() {
setLimit(DEFAULT_CACHE_LIMIT);
}
Cached.resetLimit = resetLimit;
function setLimit(count) {
configuredCacheLimit = count;
while (caches.length > configuredCacheLimit)
deleteCacheValue(caches.shift());
handleCacheGarbageCollection(true);
}
Cached.setLimit = setLimit;
})(Cached || (Cached = {}));
exports.default = Cached;