Untitled

mail@pastecode.io avatar
unknown
plain_text
2 months ago
5.0 kB
3
Indexable
Never
const { createClient } = require("redis");
const hash = require("object-hash");
const zlib = require("zlib");

let redisClient = undefined;

async function initializeRedisClient() {
    try {
        let redisURL = process.env.REDIS_URI;
        if (!redisURL) {
            throw new Error("REDIS_URI environment variable not found.");
        }
        
        redisClient = createClient({ url: redisURL });
        
        redisClient.on("error", (error) => {
            console.error("Redis client error:", error);
        });
        
        await redisClient.connect();
        console.log("Connected to Redis successfully!");
    } catch (error) {
        console.error("Error connecting to Redis:", error);
        throw error;
    }
}

async function writeData(key, data, options, compression = true) {
    if (!isRedisConnected()) {
        console.error("Redis client is not connected.");
        return;
    }

    try {
        let dataToCache = data;
        if (compression) {
            dataToCache = zlib.deflateSync(data);
        }
        
        await redisClient.set(key, dataToCache, options);
        console.log("Data cached successfully for key:", key);
    } catch (error) {
        console.error(`Failed to cache data for key=${key}:`, error);
    }
}

async function allRedisKeys(req, res, next) {
    try {
        if (!isRedisConnected()) {
            return res.status(500).json({ message: "Unable to retrieve keys. Redis connection not available." });
        }
        
        redisClient.keys("*", (err, keys) => {
            if (err) {
                console.error("Error retrieving keys from Redis:", err);
                return res.status(500).json({ message: "Internal server error." });
            }
            return res.status(200).json({ keys });
        });
    } catch (error) {
        console.error("Error retrieving keys from Redis:", error);
        next(error);
    }
}

async function flushAllData(req, res, next) {
    try {
        if (!isRedisConnected()) {
            return res.status(500).json({ message: "Unable to flush keys. Redis connection not available." });
        }

        redisClient.flushall((err, result) => {
            if (err) {
                console.error("Error flushing keys from Redis:", err);
                return res.status(500).json({ message: "Internal server error." });
            }
            return res.status(200).json({ message: "All keys flushed successfully." });
        });
    } catch (error) {
        console.error("Error flushing keys from Redis:", error);
        next(error);
    }
}

async function readData(key, compression = true) {
    if (!isRedisConnected()) {
        console.error("Redis client is not connected.");
        return;
    }

    try {
        const cachedValue = await redisClient.get(key);
        if (cachedValue) {
            if (compression) {
                return zlib.inflateSync(cachedValue).toString();
            }
            return cachedValue;
        }
        return cachedValue;
    } catch (error) {
        console.error(`Error reading data for key=${key}:`, error);
        return;
    }
}

function isRedisConnected() {
    return redisClient && redisClient.status === "ready";
}

function requestToKey(req) {
    const reqDataToHash = {
        method: req.method,
        path: req.path,
        query: req.query,
        body: req.body
    };

    return `${req.method}:${req.path}@${hash.sha1(reqDataToHash)}`;
}

function redisCachingMiddleware(compression = true) {
    return async (req, res, next) => {
        if (isRedisConnected()) {
            const key = requestToKey(req);
            const expirationTime = req.query.expiration || 300; // Default expiration: 5 minutes (300 seconds)

            const cachedValue = await readData(key, compression);

            if (cachedValue) {
                try {
                    console.log("Cache Hit");
                    return res.json(JSON.parse(cachedValue));
                } catch {
                    console.log("Cache Hit");
                    return res.send(cachedValue);
                }
            } else {
                console.log("Cache Miss");
                const oldSend = res.send;

                res.send = function (data) {
                    res.send = oldSend;

                    if (res.statusCode.toString().startsWith("2")) {
                        const options = { EX: expirationTime };
                        writeData(key, data, options, compression).then();
                    }

                    return res.send(data);
                };

                next();
            }
        } else {
            next();
        }
    };
}

module.exports = { initializeRedisClient, allRedisKeys, flushAllData, readData, requestToKey, redisCachingMiddleware };
Leave a Comment