@baguskto/saham
Version:
MCP Server untuk data saham Indonesia (IDX) - Implementasi Node.js/TypeScript
161 lines • 4.73 kB
JavaScript
;
/**
* Caching layer for IDX MCP Server
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.cacheManager = exports.CacheKeyBuilder = void 0;
const node_cache_1 = __importDefault(require("node-cache"));
const config_1 = require("../config");
const logger_1 = require("../utils/logger");
class MemoryCache {
cache;
hits = 0;
misses = 0;
constructor() {
this.cache = new node_cache_1.default({
stdTTL: 300, // 5 minutes default
checkperiod: 120, // Check for expired keys every 2 minutes
useClones: true,
deleteOnExpire: true
});
this.cache.on('set', (key) => {
logger_1.logger.debug(`Cache SET: ${key}`);
});
this.cache.on('del', (key) => {
logger_1.logger.debug(`Cache DEL: ${key}`);
});
this.cache.on('expired', (key) => {
logger_1.logger.debug(`Cache EXPIRED: ${key}`);
});
}
async get(key) {
const value = this.cache.get(key);
if (value !== undefined) {
this.hits++;
logger_1.logger.debug(`Cache HIT: ${key}`);
return value;
}
else {
this.misses++;
logger_1.logger.debug(`Cache MISS: ${key}`);
return undefined;
}
}
async set(key, value, ttl) {
const success = this.cache.set(key, value, ttl || 300);
if (!success) {
throw new Error(`Failed to set cache key: ${key}`);
}
}
async del(key) {
this.cache.del(key);
}
async clear() {
this.cache.flushAll();
}
async stats() {
const keys = this.cache.keys().length;
const total = this.hits + this.misses;
const hitRate = total > 0 ? (this.hits / total) * 100 : 0;
return {
hits: this.hits,
misses: this.misses,
keys,
hitRate: Math.round(hitRate * 100) / 100
};
}
}
class CacheKeyBuilder {
static marketOverview() {
return 'market:overview';
}
static stockInfo(ticker) {
return `stock:info:${ticker.toUpperCase()}`;
}
static historicalData(ticker, period) {
return `stock:historical:${ticker.toUpperCase()}:${period}`;
}
static sectorPerformance() {
return 'sector:performance';
}
static stockSearch(query) {
return `search:${query.toLowerCase().replace(/\s+/g, '_')}`;
}
static static(key) {
return `static:${key}`;
}
}
exports.CacheKeyBuilder = CacheKeyBuilder;
class CacheManager {
static instance;
cache;
constructor() {
this.cache = this.createCache();
}
static getInstance() {
if (!CacheManager.instance) {
CacheManager.instance = new CacheManager();
}
return CacheManager.instance;
}
createCache() {
const cacheConfig = config_1.config.getCache();
// For now, only support memory cache
// Redis support can be added later if needed
if (cacheConfig.type === 'redis') {
logger_1.logger.warn('Redis cache not implemented yet, falling back to memory cache');
}
return new MemoryCache();
}
async get(key) {
try {
return await this.cache.get(key);
}
catch (error) {
logger_1.logger.error(`Cache get error for key ${key}:`, error);
return undefined;
}
}
async set(key, value, ttl) {
try {
await this.cache.set(key, value, ttl);
}
catch (error) {
logger_1.logger.error(`Cache set error for key ${key}:`, error);
}
}
async del(key) {
try {
await this.cache.del(key);
}
catch (error) {
logger_1.logger.error(`Cache delete error for key ${key}:`, error);
}
}
async clear() {
try {
await this.cache.clear();
logger_1.logger.info('Cache cleared');
}
catch (error) {
logger_1.logger.error('Cache clear error:', error);
}
}
async stats() {
try {
return await this.cache.stats();
}
catch (error) {
logger_1.logger.error('Cache stats error:', error);
return { hits: 0, misses: 0, keys: 0, hitRate: 0 };
}
}
getTtl(type) {
return config_1.config.getCache().ttl[type];
}
}
exports.cacheManager = CacheManager.getInstance();
//# sourceMappingURL=index.js.map