RSS Git Download  Clone
Raw Blame History 7kB 184 lines
const Redis = require('../../../lib/ioredis-cluster')

module.exports = async (options) => {
    const { socket } = options;

    try {
        let redisConfig = options.payload.model;
        const actualConnection = p3xrs.connections.list.find(con => redisConfig.id === con.id)
        if (actualConnection !== undefined) {
            if (redisConfig.password === actualConnection.id) {
                redisConfig.password = actualConnection.password;
            }
            if (redisConfig.tlsCrt === actualConnection.id) {
                redisConfig.tlsCrt = actualConnection.tlsCrt;
            }
            if (redisConfig.tlsKey === actualConnection.id) {
                redisConfig.tlsKey = actualConnection.tlsKey;
            }
            if (redisConfig.tlsCa === actualConnection.id) {
                redisConfig.tlsCa = actualConnection.tlsCa;
            }
            if (redisConfig.sshPassword === actualConnection.id) {
                redisConfig.sshPassword = actualConnection.sshPassword;
            }
            if (redisConfig.sshPrivateKey === actualConnection.id) {
                redisConfig.sshPrivateKey = actualConnection.sshPrivateKey;
            }
        }

        const sentinelName = redisConfig.sentinelName
        //TODO fix secured nodes password
        delete redisConfig.name
        delete redisConfig.id


        if (redisConfig.tlsWithoutCert) {
            redisConfig.tls = {
            }
        } else if (typeof redisConfig.tlsCa === 'string' && redisConfig.tlsCa.trim() !== '') {
            redisConfig.tls = {
                //rejectUnauthorized: false,
                cert: redisConfig.tlsCrt,
                key: redisConfig.tlsKey,
                ca: redisConfig.tlsCa,
            }
        }
        if (redisConfig.hasOwnProperty('tls')) {
            redisConfig.tls.rejectUnauthorized = redisConfig.tlsRejectUnauthorized === undefined ? false : redisConfig.tlsRejectUnauthorized
        }


        if (redisConfig.hasOwnProperty('sentinel') && redisConfig.sentinel === true) {
            redisConfig.nodes = redisConfig.nodes.map((node) => {
                if (node.password === node.id) {
                    const foundNode = actualConnection.nodes.find((findNode) => findNode.id === node.password)
                    node.password = foundNode.password
                }
                return node
            })
            redisConfig = [redisConfig].concat(redisConfig.nodes)
        } else if (redisConfig.cluster === true) {
            redisConfig.nodes = redisConfig.nodes.map((node) => {
                if (node.password === node.id) {
                    const foundNode = actualConnection.nodes.find((findNode) => findNode.id === node.password)
                    node.password = foundNode.password
                }
                return node
            })
            redisConfig = [redisConfig].concat(redisConfig.nodes)
        }


        if (Array.isArray(redisConfig) && redisConfig[0].hasOwnProperty('sentinel') && redisConfig[0].sentinel === true) {
            redisConfig = {
                sentinels: redisConfig,
                name: sentinelName,
                sentinelPassword: redisConfig[0].password,
                sentinelRetryStrategy: () => {
                    return false
                }
            }
        }

        let ssh = undefined
        if (!Array.isArray(redisConfig)) {

            if (redisConfig.ssh === true) {
                const { NodeSSH } = require('node-ssh-no-cpu-features');
                const getPort = require('get-port');

                ssh = new NodeSSH();

                const sshOptions = {
                    host: redisConfig.sshHost,
                    port: parseInt(redisConfig.sshPort, 10),
                    username: redisConfig.sshUsername,
                    ...(redisConfig.sshPrivateKey
                        ? { privateKey: redisConfig.sshPrivateKey }
                        : { password: redisConfig.sshPassword }),
                };

                try {
                    console.log('Connecting to SSH server...');
                    await ssh.connect(sshOptions);
                    console.log('SSH connection established.');

                    // Dynamically get an available local port
                    const localPort = await getPort.default();
                    console.log(`Dynamic local port allocated: ${localPort}`);

                    // Manually set up port forwarding
                    const forwardCommand = `ssh -L 127.0.0.1:${localPort}:${redisConfig.host}:${redisConfig.port} -N`;
                    const result = await ssh.execCommand(forwardCommand, { execOptions: { pty: true } });

                    if (result.stderr) {
                        throw new Error(`Failed to forward port: ${result.stderr}`);
                    }

                    console.log('Port forwarding set up successfully.');

                    // Update redisConfig with the dynamically assigned port
                    //redisConfig.port = localPort;

                    // Assign the SSH connection as tunnel and client

                    console.log(`Tunnel created on local port: ${localPort}`);
                } catch (error) {
                    console.error('Failed to set up SSH tunnel:', error);
                    socket.emit(options.responseEvent, {
                        status: 'error',
                        error: error.message,
                    });
                }
            }

        }

        let redis = new Redis(redisConfig)
        //console.info('redis-test-connection', redisConfig)
        redis.on('error', function (error) {
            console.error(error)
            socket.emit(options.responseEvent, {
                status: 'error',
                error: error.message
            })
            redis.disconnect()
            if (ssh && ssh.connection) {
                ssh.connection.end()
            }
        })
        redis.on('connect', async function () {
            try {
                //await redis.call('client', 'list')

                setTimeout(() => {
                    socket.emit(options.responseEvent, {
                        status: 'ok',
                    })
                }, 1000)

            } catch (error) {
                console.error(error)
                socket.emit(options.responseEvent, {
                    status: 'error',
                    error: error.message
                })
            } finally {
                redis.disconnect()
                if (ssh && ssh.connection) {
                    ssh.connection.end()
                }
            }
        })

    } catch (e) {
        console.error(e)
        socket.emit(options.responseEvent, {
            status: 'error',
            error: e.message
        })
    }

}