From 3658e0948443f8869fdc3cd8a5889002985b3a1d Mon Sep 17 00:00:00 2001 From: dev3Nigerian Date: Thu, 31 Jul 2025 20:06:29 +0100 Subject: [PATCH] Added Redis caching --- app/commons/cache.ts | 79 ++++++++++++++++++++++++++++++++++++++++++++ app/commons/utils.ts | 13 ++++++++ 2 files changed, 92 insertions(+) create mode 100644 app/commons/cache.ts diff --git a/app/commons/cache.ts b/app/commons/cache.ts new file mode 100644 index 0000000..67f2da4 --- /dev/null +++ b/app/commons/cache.ts @@ -0,0 +1,79 @@ +import Redis from 'redis' + +const redis = process.env.REDIS_URL ? Redis.createClient({ + url: process.env.REDIS_URL +}) : null + +export class CacheManager { + private static instance: CacheManager + private redis: Redis.RedisClientType | null = null + + private constructor() { + if (redis) { + this.redis = redis + this.redis.on('error', (err) => console.error('Redis error:', err)) + } + } + + static getInstance(): CacheManager { + if (!CacheManager.instance) { + CacheManager.instance = new CacheManager() + } + return CacheManager.instance + } + + async get(key: string): Promise { + if (!this.redis) return null + + try { + const value = await this.redis.get(key) + return value ? JSON.parse(value) : null + } catch (error) { + console.error('Cache get error:', error) + return null + } + } + + async set(key: string, value: any, ttlSeconds: number = 300): Promise { + if (!this.redis) return + + try { + await this.redis.setEx(key, ttlSeconds, JSON.stringify(value)) + } catch (error) { + console.error('Cache set error:', error) + } + } + + async del(key: string): Promise { + if (!this.redis) return + + try { + await this.redis.del(key) + } catch (error) { + console.error('Cache delete error:', error) + } + } +} + +export const withCache = ( + fn: (...args: T) => Promise, + keyGenerator: (...args: T) => string, + ttlSeconds: number = 300 +) => { + return async (...args: T): Promise => { + const cache = CacheManager.getInstance() + const cacheKey = keyGenerator(...args) + + // Try to get from cache first + const cached = await cache.get(cacheKey) + if (cached !== null) { + return cached + } + + // Execute function and cache result + const result = await fn(...args) + await cache.set(cacheKey, result, ttlSeconds) + + return result + } +} \ No newline at end of file diff --git a/app/commons/utils.ts b/app/commons/utils.ts index c0cf2e4..8d7d40a 100644 --- a/app/commons/utils.ts +++ b/app/commons/utils.ts @@ -23,6 +23,7 @@ import { type EVMParameter, } from '../types' import { formatEther, formatUnits } from 'viem' +import { withCache } from './cache' export const getPath = (subdomain: string) => { if (subdomain.length === 0) { @@ -650,3 +651,15 @@ export function serializeValue(value: any): any { // Handle other types (strings, numbers, booleans) return value } + +export const fetchContractAbiRawCached = withCache( + fetchContractAbiRaw, + ({ address, chainId }) => `contract_abi:${chainId}:${address}`, + 600 // 10 minutes +) + +export const getSourceCodeCached = withCache( + getSourceCode, + (chainId, address) => `source_code:${chainId}:${address}`, + 3600 // 1 hour +)