PeerCortex/server/caches/response-caches.js
Rene Fichtmueller e5c1c2a6ae refactor: extract cache modules from server.js (roaStore, pdbSourceCache, response caches)
Also drops confirmed-dead code found during extraction: unused TIER1_ASNS
require (its only consumer, computeRouteLeakDetection, already moved to
server/route-leak.js with its own require) and bgproutesVpCache/
bgproutesVpCacheTs/BGPROUTES_VP_TTL (declared, never read anywhere).

Verified via smoke-test harness (28/28 match). server.js: 6302 -> 5907 lines.
2026-07-16 23:28:00 +02:00

113 lines
3.9 KiB
JavaScript

// Task 6: In-memory cache with TTL + Rate Limiting
const responseCache = new Map();
function cacheGet(key) {
const entry = responseCache.get(key);
if (!entry) return null;
if (Date.now() > entry.expires) {
responseCache.delete(key);
return null;
}
return entry.data;
}
function cacheSet(key, data, ttlMs) {
responseCache.set(key, { data, expires: Date.now() + ttlMs });
// Evict old entries periodically (keep cache under 500 entries)
if (responseCache.size > 500) {
const now = Date.now();
for (const [k, v] of responseCache) {
if (now > v.expires) responseCache.delete(k);
}
}
}
const CACHE_TTL_LOOKUP = 5 * 60 * 1000; // 5 minutes
const CACHE_TTL_LOOKUP_DEGRADED = 90 * 1000; // matches the existing 90s guard for suspicious /api/validate zero-counts
const CACHE_TTL_DEFAULT = 5 * 60 * 1000; // 5 minutes
// RDAP Cache — prevents 429 flooding on LACNIC/AFRINIC/APNIC/ARIN
const rdapCache = new Map(); // key: asn string, value: { data, ts }
const RDAP_CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours
function rdapCacheGet(asn) {
const e = rdapCache.get(String(asn));
if (e && (Date.now() - e.ts) < RDAP_CACHE_TTL) return e.data;
return undefined; // undefined = not cached, null = cached miss
}
function rdapCacheSet(asn, data) {
if (rdapCache.size > 5000) {
rdapCache.delete(rdapCache.keys().next().value);
}
rdapCache.set(String(asn), { data, ts: Date.now() });
}
// WHOIS Cache — 24h TTL, prevents repeated RDAP hammering
const whoisCache = new Map(); // key: asn string, value: { data, ts, ttl }
const WHOIS_CACHE_TTL = 24 * 60 * 60 * 1000;
// A "not found" result after all 5 RIR sources failed is far more often a shared
// network blip (DNS, outbound connectivity, simultaneous rate-limit) than a real
// ASN existing nowhere across RIPE+APNIC+ARIN+LACNIC+AFRINIC -- fetchJSON can't
// tell timeout/network-error apart from a genuine 404, so cache that specific
// conclusion much more briefly than a confirmed, parsed WHOIS record.
const WHOIS_NOT_FOUND_CACHE_TTL = 10 * 60 * 1000;
function whoisCacheGet(asn) {
const e = whoisCache.get(String(asn));
if (e && (Date.now() - e.ts) < (e.ttl || WHOIS_CACHE_TTL)) return e.data;
return undefined;
}
function whoisCacheSet(asn, data, ttl) {
if (whoisCache.size > 5000) whoisCache.delete(whoisCache.keys().next().value);
whoisCache.set(String(asn), { data, ts: Date.now(), ttl: ttl || WHOIS_CACHE_TTL });
}
// Quick-IX Cache — 1h TTL, for Peering Recommendations
const quickIxCache = new Map(); // key: asn string, value: { data, ts }
const QUICK_IX_CACHE_TTL = 60 * 60 * 1000;
function quickIxCacheGet(asn) {
const e = quickIxCache.get(String(asn));
if (e && (Date.now() - e.ts) < QUICK_IX_CACHE_TTL) return e.data;
return undefined;
}
function quickIxCacheSet(asn, data) {
if (quickIxCache.size > 2000) quickIxCache.delete(quickIxCache.keys().next().value);
quickIxCache.set(String(asn), { data, ts: Date.now() });
}
// bgproutes + ASPA result caches — 15min TTL, prevent re-hitting slow APIs
const bgproutesResultCache = new Map();
const aspaResultCache = new Map();
const validateResultCache = new Map();
const RESULT_CACHE_TTL = 15 * 60 * 1000; // 15 minutes
function resultCacheGet(map, key) {
const e = map.get(String(key));
const ttl = e && e.ttl ? e.ttl : RESULT_CACHE_TTL;
if (e && (Date.now() - e.ts) < ttl) return e.data;
return undefined;
}
function resultCacheSet(map, key, data, ttlMs) {
if (map.size > 2000) map.delete(map.keys().next().value);
map.set(String(key), { data, ts: Date.now(), ttl: ttlMs || RESULT_CACHE_TTL });
}
module.exports = {
responseCache,
cacheGet,
cacheSet,
CACHE_TTL_LOOKUP,
CACHE_TTL_LOOKUP_DEGRADED,
CACHE_TTL_DEFAULT,
rdapCacheGet,
rdapCacheSet,
whoisCacheGet,
whoisCacheSet,
WHOIS_NOT_FOUND_CACHE_TTL,
quickIxCacheGet,
quickIxCacheSet,
bgproutesResultCache,
aspaResultCache,
validateResultCache,
resultCacheGet,
resultCacheSet,
};