const Redis = require('ioredis'); const logger = require('../utils/logger'); class RedisClient { constructor() { this.client = null; this.subscriber = null; } async connect() { try { this.client = new Redis({ host: process.env.REDIS_HOST || 'localhost', port: process.env.REDIS_PORT || 6379, password: process.env.REDIS_PASSWORD || undefined, retryDelayOnFailover: 100, maxRetriesPerRequest: 3, lazyConnect: true, keepAlive: 30000, family: 4, db: 0 }); this.subscriber = new Redis({ host: process.env.REDIS_HOST || 'localhost', port: process.env.REDIS_PORT || 6379, password: process.env.REDIS_PASSWORD || undefined, retryDelayOnFailover: 100, maxRetriesPerRequest: 3, lazyConnect: true, keepAlive: 30000, family: 4, db: 0 }); // Test connection await this.client.ping(); await this.subscriber.ping(); logger.info('Redis connections established successfully'); } catch (error) { logger.error('Redis connection failed:', error); throw error; } } async disconnect() { if (this.client) { await this.client.quit(); logger.info('Redis client disconnected'); } if (this.subscriber) { await this.subscriber.quit(); logger.info('Redis subscriber disconnected'); } } async set(key, value, ttl = null) { try { if (ttl) { await this.client.setex(key, ttl, JSON.stringify(value)); } else { await this.client.set(key, JSON.stringify(value)); } } catch (error) { logger.error('Redis set error:', error); throw error; } } async get(key) { try { const value = await this.client.get(key); return value ? JSON.parse(value) : null; } catch (error) { logger.error('Redis get error:', error); throw error; } } async del(key) { try { await this.client.del(key); } catch (error) { logger.error('Redis del error:', error); throw error; } } async exists(key) { try { return await this.client.exists(key); } catch (error) { logger.error('Redis exists error:', error); throw error; } } async expire(key, seconds) { try { await this.client.expire(key, seconds); } catch (error) { logger.error('Redis expire error:', error); throw error; } } async publish(channel, message) { try { await this.client.publish(channel, JSON.stringify(message)); } catch (error) { logger.error('Redis publish error:', error); throw error; } } async subscribe(channel, callback) { try { await this.subscriber.subscribe(channel); this.subscriber.on('message', (chan, message) => { if (chan === channel) { callback(JSON.parse(message)); } }); } catch (error) { logger.error('Redis subscribe error:', error); throw error; } } async unsubscribe(channel) { try { await this.subscriber.unsubscribe(channel); } catch (error) { logger.error('Redis unsubscribe error:', error); throw error; } } async healthCheck() { try { await this.client.ping(); return true; } catch (error) { logger.error('Redis health check failed:', error); return false; } } // Device data caching methods async cacheDeviceData(deviceId, data, ttl = 300) { const key = `device:${deviceId}:data`; await this.set(key, data, ttl); } async getDeviceData(deviceId) { const key = `device:${deviceId}:data`; return await this.get(key); } // Alert caching methods async cacheAlert(alertId, alert, ttl = 3600) { const key = `alert:${alertId}`; await this.set(key, alert, ttl); } async getAlert(alertId) { const key = `alert:${alertId}`; return await this.get(key); } // User session caching async cacheUserSession(userId, sessionData, ttl = 86400) { const key = `session:${userId}`; await this.set(key, sessionData, ttl); } async getUserSession(userId) { const key = `session:${userId}`; return await this.get(key); } async invalidateUserSession(userId) { const key = `session:${userId}`; await this.del(key); } } module.exports = new RedisClient();