@siva-sub/mcp-public-transport
Version:
A Model Context Protocol server for Singapore transport data with real-time information and routing
71 lines (70 loc) • 1.99 kB
JavaScript
import NodeCache from 'node-cache';
import { logger } from '../utils/logger.js';
export class CacheService {
cache;
hitCount = 0;
missCount = 0;
constructor(defaultTtl = 300) {
this.cache = new NodeCache({
stdTTL: defaultTtl,
checkperiod: 60,
useClones: false,
deleteOnExpire: true,
});
this.cache.on('expired', (key) => {
logger.debug(`Cache key expired: ${key}`);
});
this.cache.on('del', (key) => {
logger.debug(`Cache key deleted: ${key}`);
});
}
async getOrSet(key, fetchFn, ttl) {
const cached = this.cache.get(key);
if (cached !== undefined) {
this.hitCount++;
logger.debug(`Cache hit: ${key}`);
return cached;
}
this.missCount++;
logger.debug(`Cache miss: ${key}`);
try {
const data = await fetchFn();
this.cache.set(key, data, ttl || 300);
logger.debug(`Cache set: ${key} (TTL: ${ttl || 'default'})`);
return data;
}
catch (error) {
logger.error(`Failed to fetch data for cache key: ${key}`, error);
throw error;
}
}
get(key) {
const value = this.cache.get(key);
if (value !== undefined) {
this.hitCount++;
}
else {
this.missCount++;
}
return value;
}
set(key, value, ttl) {
return this.cache.set(key, value, ttl || 300);
}
del(key) {
return this.cache.del(key);
}
flush() {
this.cache.flushAll();
logger.info('Cache flushed');
}
getStats() {
const cacheStats = this.cache.getStats();
return {
...cacheStats,
hitRate: this.hitCount / (this.hitCount + this.missCount) || 0,
hitCount: this.hitCount,
missCount: this.missCount,
};
}
}