UNPKG

@condor-labs/redis

Version:

This module provide and usefull helper to use the official Node_redis library.

126 lines (121 loc) 5.01 kB
const Joi = require('joi'); const fs = require('fs'); const os = require("os") const redis = require('redis'); const logger = require('@condor-labs/logger'); const { extractClientValue, removeIpPort } = require('../utils'); const self = { _settings: null, _client: undefined, _errorMsgInvalidSetting: 'INVALID_SETTINGS', _errorMsgUndefinedSetting: 'SETTINGS_NOT_DEFINED', _schema: Joi.object().keys({ socket: Joi.object().keys({ port: Joi.number().default(6379), host: Joi.string().default('127.0.0.1').required(), tls: Joi.boolean().default(false), key: Joi.string().when('tls', { is: true, then: Joi.string().required() }), ca: Joi.string().when('tls', { is: true, then: Joi.string().required() }), cert: Joi.string().when('tls', { is: true, then: Joi.string().required() }) }).unknown(true), clientName: Joi.string(), name: Joi.string(), password: Joi.string().default(null).allow(null).allow(''), prefix: Joi.string().default(null) }), _setSettings: settings => { //Validate the settings if (!self._validateSettings(settings)) { throw new Error(self._errorMsgInvalidSetting); } if (settings) { settings.clientName = settings.clientName || os.hostname() settings.clientName = settings.clientName.replace(new RegExp(`_pid${process.pid}|\\s`), '') settings.name = `${settings.clientName}_pid${process.pid}` } self._settings = settings; }, _validateSettings: settings => { if (!settings) { logger.error(self._errorMsgUndefinedSetting); return false; } const { error, value } = self._schema.validate(settings); if (error === void 0) { return true; } else { logger.error(`${error} - ${value}`); return false; } }, _clientList: async () => { const list = await self._client.sendCommand(['CLIENT', 'LIST']) return list.split(`\n`) }, _clientInfo: async () => { const info = await self._client.sendCommand(['CLIENT', 'INFO']) return info }, _filterclient: async (name, addr) => { const list = await self._clientList() let clients = list.filter((client) => (client.includes(`addr=${addr}`) && (client.includes(`name=${name}`) || client.includes(`name= `)))) return clients }, _verifyUniqueConnection: async (verifyUniqueConnection) => { if (verifyUniqueConnection) { const currenClient = await self._clientInfo() const actualID = extractClientValue('id', currenClient) const actualAddr = extractClientValue('addr', currenClient) const clients = await self._filterclient(self._settings.name, removeIpPort(actualAddr)) if (clients.length > 1) { for (const client of clients) { const clientId = extractClientValue('id', client) const ageConnection = extractClientValue('age', client) || 0 if (actualID !== clientId) { const clientName = extractClientValue('name', client) if (clientName === '' && Number(ageConnection) < 5) continue const del = await self._killClient(clientId) } } } } }, _killClient: async (id) => { if (id) { return await self._client.clientKill({ filter: 'ID', id }) } }, getClient: async (options = {}) => { const { forceReconnect = false, verifyUniqueConnection = true } = options if (forceReconnect || !self._client) { if (!self._validateSettings(self._settings)) { throw new Error(self._errorMsgInvalidSetting); } if (self._settings.socket.tls === true) { self._settings.socket.key = fs.readFileSync(self._settings.socket.key, { 'encoding': 'ascii' }) self._settings.socket.cert = fs.readFileSync(self._settings.socket.cert, { 'encoding': 'ascii' }) self._settings.socket.ca = [fs.readFileSync(self._settings.socket.ca, { 'encoding': 'ascii' })] }; self._client = await redis.createClient(self._settings); await self._client.connect() await self._verifyUniqueConnection(verifyUniqueConnection); self._client.on("connect", async () => { logger.info(`REDIS_CONNECTED`, self._settings.name); }); self._client.on("error", (err) => { logger.error('REDIS_ERROR_CONNECTION', err); }); } return self._client; } }; module.exports = self;