UNPKG

@baguskto/saham

Version:

MCP Server untuk data saham Indonesia (IDX) - Implementasi Node.js/TypeScript

161 lines 4.73 kB
"use strict"; /** * 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