CoolFace
Apppublic

sanket3280/code-execution

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
cache.js280 linesDownload Raw Back to utils
1/**2 * Caching Utilities3 * Provides caching helpers for Redis and in-memory caching4 */5 6const logger = require('./logger');7 8/**9 * In-memory cache implementation10 * Used as fallback when Redis is not available11 */12class MemoryCache {13  constructor() {14    this.cache = new Map();15    this.timers = new Map();16  }17 18  /**19   * Set a value in cache with optional TTL20   */21  async set(key, value, ttl = null) {22    try {23      this.cache.set(key, value);24 25      // Clear existing timer if any26      if (this.timers.has(key)) {27        clearTimeout(this.timers.get(key));28      }29 30      // Set expiration timer if TTL provided31      if (ttl) {32        const timer = setTimeout(() => {33          this.cache.delete(key);34          this.timers.delete(key);35        }, ttl * 1000);36        this.timers.set(key, timer);37      }38 39      return true;40    } catch (error) {41      logger.error('Memory cache set error', error);42      return false;43    }44  }45 46  /**47   * Get a value from cache48   */49  async get(key) {50    try {51      return this.cache.get(key) || null;52    } catch (error) {53      logger.error('Memory cache get error', error);54      return null;55    }56  }57 58  /**59   * Delete a value from cache60   */61  async del(key) {62    try {63      if (this.timers.has(key)) {64        clearTimeout(this.timers.get(key));65        this.timers.delete(key);66      }67      return this.cache.delete(key);68    } catch (error) {69      logger.error('Memory cache delete error', error);70      return false;71    }72  }73 74  /**75   * Check if key exists76   */77  async exists(key) {78    return this.cache.has(key);79  }80 81  /**82   * Clear all cache83   */84  async clear() {85    try {86      // Clear all timers87      for (const timer of this.timers.values()) {88        clearTimeout(timer);89      }90      this.timers.clear();91      this.cache.clear();92      return true;93    } catch (error) {94      logger.error('Memory cache clear error', error);95      return false;96    }97  }98 99  /**100   * Get cache size101   */102  size() {103    return this.cache.size;104  }105}106 107/**108 * Cache wrapper that uses Redis if available, falls back to memory cache109 */110class CacheManager {111  constructor(redisClient = null) {112    this.redis = redisClient;113    this.memoryCache = new MemoryCache();114    this.useRedis = !!redisClient;115  }116 117  /**118   * Set a value in cache119   */120  async set(key, value, ttl = 300) {121    try {122      const stringValue = typeof value === 'string' ? value : JSON.stringify(value);123 124      if (this.useRedis && this.redis) {125        if (ttl) {126          await this.redis.setex(key, ttl, stringValue);127        } else {128          await this.redis.set(key, stringValue);129        }130        logger.debug(`Cache set (Redis): ${key}`);131      } else {132        await this.memoryCache.set(key, stringValue, ttl);133        logger.debug(`Cache set (Memory): ${key}`);134      }135      return true;136    } catch (error) {137      logger.error(`Cache set error for key: ${key}`, error);138      return false;139    }140  }141 142  /**143   * Get a value from cache144   */145  async get(key) {146    try {147      let value;148 149      if (this.useRedis && this.redis) {150        value = await this.redis.get(key);151        logger.debug(`Cache get (Redis): ${key} - ${value ? 'HIT' : 'MISS'}`);152      } else {153        value = await this.memoryCache.get(key);154        logger.debug(`Cache get (Memory): ${key} - ${value ? 'HIT' : 'MISS'}`);155      }156 157      if (!value) return null;158 159      // Try to parse JSON, return as-is if not JSON160      try {161        return JSON.parse(value);162      } catch {163        return value;164      }165    } catch (error) {166      logger.error(`Cache get error for key: ${key}`, error);167      return null;168    }169  }170 171  /**172   * Delete a value from cache173   */174  async del(key) {175    try {176      if (this.useRedis && this.redis) {177        await this.redis.del(key);178        logger.debug(`Cache delete (Redis): ${key}`);179      } else {180        await this.memoryCache.del(key);181        logger.debug(`Cache delete (Memory): ${key}`);182      }183      return true;184    } catch (error) {185      logger.error(`Cache delete error for key: ${key}`, error);186      return false;187    }188  }189 190  /**191   * Check if key exists192   */193  async exists(key) {194    try {195      if (this.useRedis && this.redis) {196        return await this.redis.exists(key) === 1;197      } else {198        return await this.memoryCache.exists(key);199      }200    } catch (error) {201      logger.error(`Cache exists error for key: ${key}`, error);202      return false;203    }204  }205 206  /**207   * Clear cache by pattern208   */209  async clearPattern(pattern) {210    try {211      if (this.useRedis && this.redis) {212        const keys = await this.redis.keys(pattern);213        if (keys.length > 0) {214          await this.redis.del(...keys);215          logger.debug(`Cache cleared (Redis): ${keys.length} keys matching ${pattern}`);216        }217      } else {218        // Memory cache doesn't support patterns, clear all219        await this.memoryCache.clear();220        logger.debug('Cache cleared (Memory): all keys');221      }222      return true;223    } catch (error) {224      logger.error(`Cache clear pattern error: ${pattern}`, error);225      return false;226    }227  }228 229  /**230   * Get or set pattern - fetch from cache or execute function and cache result231   */232  async getOrSet(key, fetchFn, ttl = 300) {233    try {234      // Try to get from cache235      const cached = await this.get(key);236      if (cached !== null) {237        return cached;238      }239 240      // Not in cache, fetch data241      const data = await fetchFn();242      243      // Cache the result244      await this.set(key, data, ttl);245      246      return data;247    } catch (error) {248      logger.error(`Cache getOrSet error for key: ${key}`, error);249      // If caching fails, still return the fetched data250      return await fetchFn();251    }252  }253}254 255// Export singleton instance256let cacheInstance = null;257 258const initializeCache = (redisClient) => {259  cacheInstance = new CacheManager(redisClient);260  logger.info('Cache manager initialized', {261    type: redisClient ? 'Redis' : 'Memory',262  });263  return cacheInstance;264};265 266const getCache = () => {267  if (!cacheInstance) {268    cacheInstance = new CacheManager();269    logger.warn('Cache manager not initialized, using memory cache');270  }271  return cacheInstance;272};273 274module.exports = {275  MemoryCache,276  CacheManager,277  initializeCache,278  getCache,279};280