const logger = require("./logger"); /** * Apply Redis helper functions * @param pubClient * @param app */ const applyRedisHelpers = (pubClient, app, logger) => { // Store session data in Redis const setSessionData = async (socketId, key, value) => { try { await pubClient.hset(`socket:${socketId}`, key, JSON.stringify(value)); // Use Redis pubClient } catch (error) { logger.log(`Error Setting Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); } }; // Retrieve session data from Redis const getSessionData = async (socketId, key) => { try { const data = await pubClient.hget(`socket:${socketId}`, key); return data ? JSON.parse(data) : null; } catch (error) { logger.log(`Error Getting Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); } }; // Clear session data from Redis const clearSessionData = async (socketId) => { try { await pubClient.del(`socket:${socketId}`); } catch (error) { logger.log(`Error Clearing Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); } }; // Store multiple session data in Redis const setMultipleSessionData = async (socketId, keyValues) => { try { // keyValues is expected to be an object { key1: value1, key2: value2, ... } const entries = Object.entries(keyValues).map(([key, value]) => [key, JSON.stringify(value)]); await pubClient.hset(`socket:${socketId}`, ...entries.flat()); } catch (error) { logger.log(`Error Setting Multiple Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); } }; // Retrieve multiple session data from Redis const getMultipleSessionData = async (socketId, keys) => { try { const data = await pubClient.hmget(`socket:${socketId}`, keys); // Redis returns an object with null values for missing keys, so we parse the non-null ones return Object.fromEntries(keys.map((key, index) => [key, data[index] ? JSON.parse(data[index]) : null])); } catch (error) { logger.log(`Error Getting Multiple Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); } }; const setMultipleFromArraySessionData = async (socketId, keyValueArray) => { try { // Use Redis multi/pipeline to batch the commands const multi = pubClient.multi(); keyValueArray.forEach(([key, value]) => { multi.hSet(`socket:${socketId}`, key, JSON.stringify(value)); }); await multi.exec(); // Execute all queued commands } catch (error) { logger.log(`Error Setting Multiple Session Data for socket ${socketId}: ${error}`, "ERROR", "redis"); } }; // Helper function to add an item to the end of the Redis list const addItemToEndOfList = async (socketId, key, newItem) => { try { await pubClient.rpush(`socket:${socketId}:${key}`, JSON.stringify(newItem)); } catch (error) { logger.log(`Error adding item to the end of the list for socket ${socketId}: ${error}`, "ERROR", "redis"); } }; // Helper function to add an item to the beginning of the Redis list const addItemToBeginningOfList = async (socketId, key, newItem) => { try { await pubClient.lpush(`socket:${socketId}:${key}`, JSON.stringify(newItem)); } catch (error) { logger.log(`Error adding item to the beginning of the list for socket ${socketId}: ${error}`, "ERROR", "redis"); } }; // Helper function to clear a list in Redis const clearList = async (socketId, key) => { try { await pubClient.del(`socket:${socketId}:${key}`); } catch (error) { logger.log(`Error clearing list for socket ${socketId}: ${error}`, "ERROR", "redis"); } }; // Add methods to manage room users const addUserToRoom = async (room, user) => { try { await pubClient.sadd(room, JSON.stringify(user)); } catch (error) { logger.log(`Error adding user to room ${room}: ${error}`, "ERROR", "redis"); } }; const removeUserFromRoom = async (room, user) => { try { await pubClient.srem(room, JSON.stringify(user)); } catch (error) { logger.log(`Error removing user to room ${room}: ${error}`, "ERROR", "redis"); } }; const getUsersInRoom = async (room) => { try { const users = await pubClient.smembers(room); return users.map((user) => JSON.parse(user)); } catch (error) { logger.log(`Error getting users in room ${room}: ${error}`, "ERROR", "redis"); } }; const api = { setSessionData, getSessionData, clearSessionData, setMultipleSessionData, getMultipleSessionData, setMultipleFromArraySessionData, addItemToEndOfList, addItemToBeginningOfList, clearList, addUserToRoom, removeUserFromRoom, getUsersInRoom }; Object.assign(module.exports, api); app.use((req, res, next) => { req.sessionUtils = api; next(); }); // // Demo to show how all the helper functions work // const demoSessionData = async () => { // const socketId = "testSocketId"; // // // Store session data using setSessionData // await exports.setSessionData(socketId, "field1", "Hello, Redis!"); // // // Retrieve session data using getSessionData // const field1Value = await exports.getSessionData(socketId, "field1"); // console.log("Retrieved single field value:", field1Value); // // // Store multiple session data using setMultipleSessionData // await exports.setMultipleSessionData(socketId, { field2: "Second Value", field3: "Third Value" }); // // // Retrieve multiple session data using getMultipleSessionData // const multipleFields = await exports.getMultipleSessionData(socketId, ["field2", "field3"]); // console.log("Retrieved multiple field values:", multipleFields); // // // Store multiple session data using setMultipleFromArraySessionData // await exports.setMultipleFromArraySessionData(socketId, [ // ["field4", "Fourth Value"], // ["field5", "Fifth Value"] // ]); // // // Retrieve and log all fields // const allFields = await exports.getMultipleSessionData(socketId, [ // "field1", // "field2", // "field3", // "field4", // "field5" // ]); // console.log("Retrieved all field values:", allFields); // // // Add item to the end of a Redis list // await exports.addItemToEndOfList(socketId, "logEvents", { event: "Log Event 1", timestamp: new Date() }); // await exports.addItemToEndOfList(socketId, "logEvents", { event: "Log Event 2", timestamp: new Date() }); // // // Add item to the beginning of a Redis list // await exports.addItemToBeginningOfList(socketId, "logEvents", { event: "First Log Event", timestamp: new Date() }); // // // Retrieve the entire list (using lRange) // const logEvents = await pubClient.lRange(`socket:${socketId}:logEvents`, 0, -1); // console.log("Log Events List:", logEvents.map(JSON.parse)); // // // **Add the new code below to test clearList** // // // Clear the list using clearList // await exports.clearList(socketId, "logEvents"); // console.log("Log Events List cleared."); // // // Retrieve the list after clearing to confirm it's empty // const logEventsAfterClear = await pubClient.lRange(`socket:${socketId}:logEvents`, 0, -1); // console.log("Log Events List after clearing:", logEventsAfterClear); // Should be an empty array // // // Clear session data // await exports.clearSessionData(socketId); // console.log("Session data cleared."); // }; // // if (process.env.NODE_ENV === "development") { // demoSessionData(); // } // "th1s1sr3d1s" (BCrypt) return api; }; module.exports = applyRedisHelpers;