diff --git a/src/redis/session/SessionManager.ts b/src/redis/session/SessionManager.ts new file mode 100644 index 0000000..81d1653 --- /dev/null +++ b/src/redis/session/SessionManager.ts @@ -0,0 +1,87 @@ +import Redis, { RedisOptions } from 'ioredis'; +import dotenv from 'dotenv'; + +dotenv.config(); + +interface RedisConfig extends RedisOptions { + host: string; + port: number; + password?: string; +} + +class RedisSessionManager { + private static instance: RedisSessionManager; + public readonly client: Redis; + private subscriber: Redis | null = null; + + private constructor() { + const redisConfig: RedisConfig = { + host: process.env.REDIS_HOST!, + port: Number(process.env.REDIS_PORT), + password: process.env.REDIS_PASSWORD || undefined, + showFriendlyErrorStack: true, + }; + this.client = new Redis(redisConfig); + } + + public static getInstance(): RedisSessionManager { + if (!RedisSessionManager.instance) { + RedisSessionManager.instance = new RedisSessionManager(); + } + return RedisSessionManager.instance; + } + + async subscribe(channel: string, messageHandler: (channel: string, message: string) => void): Promise { + if (!this.subscriber) { + this.subscriber = new Redis({ + host: process.env.REDIS_HOST!, + port: Number(process.env.REDIS_PORT), + password: process.env.REDIS_PASSWORD || undefined, + showFriendlyErrorStack: true, + }); + } + + await this.subscriber.subscribe(channel, (err, count) => { + if (err) { + console.error(`Failed to subscribe: ${err.message}`); + return; + } + console.log(`Subscribed to ${count} channel(s). Currently subscribed to ${channel}`); + }); + + this.subscriber.on('message', messageHandler); + } + + async unsubscribe(channel: string): Promise { + if (this.subscriber) { + await this.subscriber.unsubscribe(channel); + console.log(`Unsubscribed from ${channel}`); + } + } + + async storeObject(keyPrefix: string, objectId: string, data: Record, expirationSec: number = 3600): Promise { + const key = `${keyPrefix}:${objectId}`; + const dataToStore = JSON.stringify(data); + await this.client.set(key, dataToStore, 'EX', expirationSec); + } + + async retrieveObject(keyPrefix: string, objectId: string): Promise | null> { + const key = `${keyPrefix}:${objectId}`; + const data = await this.client.get(key); + return data ? JSON.parse(data) : null; + } + + async publishObject(channel: string, data: Record): Promise { + const dataToPublish = JSON.stringify(data); + return this.client.publish(channel, dataToPublish); + } + + async shutdown(): Promise { + if (this.subscriber) { + await this.subscriber.quit(); + } + await this.client.quit(); + } +} + +export default RedisSessionManager;