You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-07 13:22:56 +03:00
chore - remove standard and use individual config
Standard is not as up to date and still uses a old eslint version. Instead, use the airbnb default with a couple of modifications. All required changes are included.
This commit is contained in:
34
lib/.eslintrc.json
Normal file
34
lib/.eslintrc.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"extends": "airbnb-base",
|
||||
// Override airbnb defaults
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "script"
|
||||
},
|
||||
"rules": {
|
||||
"semi": ["error", "never"],
|
||||
"strict": ["error", "global"],
|
||||
"comma-dangle": "off",
|
||||
"no-plusplus": "off",
|
||||
"func-names": "off",
|
||||
"arrow-body-style": "off",
|
||||
"no-underscore-dangle": "off",
|
||||
"consistent-return": "off",
|
||||
"no-unused-vars": ["error", { "vars": "all", "args": "none" }],
|
||||
"no-shadow": "off",
|
||||
"no-console": "off",
|
||||
"no-restricted-properties": "off",
|
||||
"no-param-reassign": "off",
|
||||
"no-var": "off",
|
||||
"vars-on-top": "off",
|
||||
"prefer-destructuring": "off",
|
||||
"no-mixed-operators": "off",
|
||||
"prefer-spread": "off",
|
||||
"no-use-before-define": "off",
|
||||
"global-require": "off",
|
||||
"no-nested-ternary": "off"
|
||||
},
|
||||
"env": {
|
||||
"mocha": 2
|
||||
}
|
||||
}
|
@@ -2,20 +2,15 @@
|
||||
|
||||
const Command = require('./command')
|
||||
|
||||
function addCommand (clientProto, multiProto, command) {
|
||||
function addCommand(clientProto, multiProto, command) {
|
||||
// Some rare Redis commands use special characters in their command name
|
||||
// Convert those to a underscore to prevent using invalid function names
|
||||
const commandName = command.replace(/(?:^([0-9])|[^a-zA-Z0-9_$])/g, '_$1')
|
||||
|
||||
// Do not override existing functions
|
||||
if (!clientProto[command]) {
|
||||
clientProto[commandName] = function () {
|
||||
const len = arguments.length
|
||||
const arr = new Array(len)
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
arr[i] = arguments[i]
|
||||
}
|
||||
return this.internalSendCommand(new Command(command, arr))
|
||||
clientProto[commandName] = function (...args) {
|
||||
return this.internalSendCommand(new Command(command, args))
|
||||
}
|
||||
if (!clientProto[commandName].name) {
|
||||
Object.defineProperty(clientProto[commandName], 'name', {
|
||||
@@ -32,13 +27,8 @@ function addCommand (clientProto, multiProto, command) {
|
||||
|
||||
// Do not override existing functions
|
||||
if (!multiProto[command] && command !== 'multi') {
|
||||
multiProto[commandName] = function () {
|
||||
const len = arguments.length
|
||||
const arr = new Array(len)
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
arr[i] = arguments[i]
|
||||
}
|
||||
this._queue.push(new Command(command, arr))
|
||||
multiProto[commandName] = function (...args) {
|
||||
this._queue.push(new Command(command, args))
|
||||
return this
|
||||
}
|
||||
if (!multiProto[commandName].name) {
|
||||
|
@@ -11,8 +11,9 @@ const Multi = require('./multi')
|
||||
const offlineCommand = require('./offlineCommand')
|
||||
const utils = require('./utils')
|
||||
const normalizeAndWriteCommand = require('./writeCommand')
|
||||
|
||||
const noop = function () {}
|
||||
var connectionId = 0
|
||||
let connectionId = 0
|
||||
|
||||
// Attention: The second parameter might be removed at will and is not officially supported.
|
||||
// Do not rely on this
|
||||
@@ -23,15 +24,17 @@ class RedisClient extends EventEmitter {
|
||||
*
|
||||
* @memberof RedisClient
|
||||
*/
|
||||
constructor (options) {
|
||||
constructor(options) {
|
||||
var i
|
||||
super()
|
||||
// Copy the options so they are not mutated
|
||||
options = utils.clone(options)
|
||||
// TODO: Add a more restrictive options validation
|
||||
const cnxOptions = {}
|
||||
for (const tlsOption in options.tls) {
|
||||
/* istanbul ignore else */
|
||||
if (options.tls.hasOwnProperty(tlsOption)) {
|
||||
if (options.tls) {
|
||||
const tlsKeys = Object.keys(options.tls)
|
||||
for (i = 0; i < tlsKeys.length; i++) {
|
||||
const tlsOption = tlsKeys[i]
|
||||
cnxOptions[tlsOption] = options.tls[tlsOption]
|
||||
// Copy the tls options into the general options to make sure the address is set right
|
||||
if (tlsOption === 'port' || tlsOption === 'host' || tlsOption === 'path' || tlsOption === 'family') {
|
||||
@@ -40,8 +43,10 @@ class RedisClient extends EventEmitter {
|
||||
}
|
||||
}
|
||||
if (options.stream) {
|
||||
// The stream from the outside is used so no connection from this side is triggered but from the server this client should talk to
|
||||
// Reconnect etc won't work with this. This requires monkey patching to work, so it is not officially supported
|
||||
// The stream from the outside is used so no connection from this side is
|
||||
// triggered but from the server this client should talk to Reconnect etc
|
||||
// won't work with this. This requires monkey patching to work, so it is
|
||||
// not officially supported
|
||||
this.address = '"Private stream"'
|
||||
} else if (options.path) {
|
||||
cnxOptions.path = options.path
|
||||
@@ -56,9 +61,10 @@ class RedisClient extends EventEmitter {
|
||||
if (options.socketKeepalive === undefined) {
|
||||
options.socketKeepalive = true
|
||||
}
|
||||
for (const command in options.renameCommands) {
|
||||
/* istanbul ignore else */
|
||||
if (options.renameCommands.hasOwnProperty(command)) {
|
||||
if (options.renameCommands) {
|
||||
const renameKeys = Object.keys(options.renameCommands)
|
||||
for (i = 0; i < renameKeys.length; i++) {
|
||||
const command = renameKeys[i]
|
||||
options.renameCommands[command.toLowerCase()] = options.renameCommands[command]
|
||||
}
|
||||
}
|
||||
@@ -116,7 +122,8 @@ class RedisClient extends EventEmitter {
|
||||
this._closing = false
|
||||
this._timesConnected = 0
|
||||
this._connectionOptions = cnxOptions
|
||||
// Only used as timeout until redis has to be connected to redis until throwing an connection error
|
||||
// Only used as timeout until redis has to be connected to redis until
|
||||
// throwing an connection error
|
||||
this._connectTimeout = +options.connectTimeout || 60 * 1000 // ms
|
||||
this._retryStrategy = options.retryStrategy || function (options) {
|
||||
// TODO: Find better defaults
|
||||
@@ -140,12 +147,15 @@ class RedisClient extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
// Do not call internalSendCommand directly, if you are not absolutely certain it handles everything properly
|
||||
// e.g. monitor / info does not work with internalSendCommand only
|
||||
// Do not call internalSendCommand directly, if you are not absolutely certain
|
||||
// it handles everything properly e.g. monitor / info does not work with
|
||||
// internalSendCommand only
|
||||
//
|
||||
// TODO: Move this function out of the client as a private function
|
||||
// TODO: Check how others can intercept (monkey patch) essential parts (e.g. opbeat)
|
||||
// after making this private.
|
||||
internalSendCommand (commandObj) {
|
||||
//
|
||||
// TODO: Check how others can intercept (monkey patch) essential parts (e.g.
|
||||
// opbeat) after making this private.
|
||||
internalSendCommand(commandObj) {
|
||||
if (this.ready === false || this._stream.writable === false) {
|
||||
// Handle offline commands right away
|
||||
offlineCommand(this, commandObj)
|
||||
@@ -175,7 +185,7 @@ class RedisClient extends EventEmitter {
|
||||
}
|
||||
|
||||
// Redirect calls to the appropriate function and use to send arbitrary / not supported commands
|
||||
sendCommand (command, args) {
|
||||
sendCommand(command, args) {
|
||||
// Throw to fail early instead of relying in order in this case
|
||||
if (typeof command !== 'string') {
|
||||
throw new TypeError(`Wrong input type "${command !== null && command !== undefined ? command.constructor.name : command}" for command name`)
|
||||
@@ -188,11 +198,12 @@ class RedisClient extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
// Using the raw multi command is only possible with this function
|
||||
// If the command is not yet added to the client, the internal function should be called right away
|
||||
// Otherwise we need to redirect the calls to make sure the internal functions don't get skipped
|
||||
// The internal functions could actually be used for any non hooked function
|
||||
// but this might change from time to time and at the moment there's no good way to distinguish them
|
||||
// Using the raw multi command is only possible with this function If the
|
||||
// command is not yet added to the client, the internal function should be
|
||||
// called right away Otherwise we need to redirect the calls to make sure
|
||||
// the internal functions don't get skipped The internal functions could
|
||||
// actually be used for any non hooked function but this might change from
|
||||
// time to time and at the moment there's no good way to distinguish them
|
||||
// from each other, so let's just do it do it this way for the time being
|
||||
if (command === 'multi' || typeof this[command] !== 'function') {
|
||||
return this.internalSendCommand(new Command(command, args))
|
||||
@@ -200,7 +211,7 @@ class RedisClient extends EventEmitter {
|
||||
return this[command].apply(this, args)
|
||||
}
|
||||
|
||||
end (flush) {
|
||||
end(flush) {
|
||||
if (typeof flush !== 'boolean') {
|
||||
throw new TypeError('You must call "end" with the flush argument.')
|
||||
}
|
||||
@@ -222,7 +233,7 @@ class RedisClient extends EventEmitter {
|
||||
return this._stream.destroySoon()
|
||||
}
|
||||
|
||||
unref () {
|
||||
unref() {
|
||||
if (this.connected) {
|
||||
debug('Unref\'ing the socket connection')
|
||||
this._stream.unref()
|
||||
@@ -237,18 +248,16 @@ class RedisClient extends EventEmitter {
|
||||
// This would be another BC and it should be fine to return the client sync.
|
||||
// Therefore a option could be to accept a resolved promise instead of a callback
|
||||
// to return a promise.
|
||||
duplicate (options, callback) {
|
||||
duplicate(options, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options
|
||||
options = null
|
||||
}
|
||||
const existingOptions = utils.clone(this._options)
|
||||
options = utils.clone(options)
|
||||
for (const elem in options) {
|
||||
/* istanbul ignore else */
|
||||
if (options.hasOwnProperty(elem)) {
|
||||
existingOptions[elem] = options[elem]
|
||||
}
|
||||
const keys = Object.keys(options)
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
existingOptions[keys[i]] = options[keys[i]]
|
||||
}
|
||||
const client = new RedisClient(existingOptions)
|
||||
// Return to the same state as the other client
|
||||
@@ -274,14 +283,13 @@ class RedisClient extends EventEmitter {
|
||||
}
|
||||
|
||||
// Note: this overrides a native function!
|
||||
multi (args) {
|
||||
multi(args) {
|
||||
return new Multi(this, 'multi', args)
|
||||
}
|
||||
|
||||
batch (args) {
|
||||
batch(args) {
|
||||
return new Multi(this, 'batch', args)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = RedisClient
|
||||
|
@@ -4,7 +4,7 @@ const betterStackTraces = /development/i.test(process.env.NODE_ENV) || /\bredis\
|
||||
|
||||
// TODO: Change the arguments to an object
|
||||
// callOnWrite could be two things now
|
||||
function Command (name, args, callOnWrite, transformer) {
|
||||
function Command(name, args, callOnWrite, transformer) {
|
||||
this.command = name
|
||||
this.args = args
|
||||
this.argsLength = 0
|
||||
|
@@ -7,15 +7,13 @@ const debug = require('./debug')
|
||||
const flushAndError = require('./flushAndError')
|
||||
const onConnect = require('./readyHandler')
|
||||
const replyHandler = require('./replyHandler')
|
||||
|
||||
var reconnect
|
||||
|
||||
const onResult = replyHandler.onResult
|
||||
const onError = replyHandler.onError
|
||||
|
||||
var lazyReconnect = function (client, why, err) {
|
||||
lazyReconnect = require('./reconnect')
|
||||
lazyReconnect(client, why, err)
|
||||
}
|
||||
|
||||
function onStreamError (client, err) {
|
||||
function onStreamError(client, err) {
|
||||
if (client._closing) {
|
||||
return
|
||||
}
|
||||
@@ -29,9 +27,10 @@ function onStreamError (client, err) {
|
||||
if (client._retryStrategyProvided === false) {
|
||||
client.emit('error', err)
|
||||
}
|
||||
// 'error' events get turned into exceptions if they aren't listened for. If the user handled this error
|
||||
// then we should try to reconnect.
|
||||
lazyReconnect(client, 'error', err)
|
||||
// 'error' events get turned into exceptions if they aren't listened for. If
|
||||
// the user handled this error then we should try to reconnect.
|
||||
if (reconnect === undefined) reconnect = require('./reconnect')
|
||||
reconnect(client, 'error', err)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,17 +39,19 @@ function onStreamError (client, err) {
|
||||
* @param {RedisClient} client
|
||||
* @returns JavascriptRedisParser
|
||||
*/
|
||||
function createParser (client) {
|
||||
function createParser(client) {
|
||||
return new Parser({
|
||||
returnReply (data) {
|
||||
returnReply(data) {
|
||||
onResult(client, data)
|
||||
},
|
||||
returnError (err) {
|
||||
returnError(err) {
|
||||
onError(client, err)
|
||||
},
|
||||
returnFatalError (err) {
|
||||
// Error out all fired commands. Otherwise they might rely on faulty data. We have to reconnect to get in a working state again
|
||||
// Note: the execution order is important. First flush and emit, then create the stream
|
||||
returnFatalError(err) {
|
||||
// Error out all fired commands. Otherwise they might rely on faulty data.
|
||||
// We have to reconnect to get in a working state again Note: the
|
||||
// execution order is important. First flush and emit, then create the
|
||||
// stream
|
||||
err.message += '. Please report this.'
|
||||
client.ready = false
|
||||
flushAndError(client, 'Fatal error encountered. Command aborted.', 'NR_FATAL', {
|
||||
@@ -73,7 +74,7 @@ function createParser (client) {
|
||||
*
|
||||
* @param {RedisClient} client
|
||||
*/
|
||||
function connect (client) {
|
||||
function connect(client) {
|
||||
// Init parser
|
||||
const parser = createParser(client)
|
||||
const options = client._options
|
||||
@@ -106,7 +107,8 @@ function connect (client) {
|
||||
// TODO: Check if this works with tls.
|
||||
stream.setTimeout(client._connectTimeout, () => {
|
||||
// Note: This is only tested if a internet connection is established
|
||||
lazyReconnect(client, 'timeout')
|
||||
if (reconnect === undefined) reconnect = require('./reconnect')
|
||||
reconnect(client, 'timeout')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -127,11 +129,13 @@ function connect (client) {
|
||||
})
|
||||
|
||||
stream.once('close', (hadError) => {
|
||||
lazyReconnect(client, 'close')
|
||||
if (reconnect === undefined) reconnect = require('./reconnect')
|
||||
reconnect(client, 'close')
|
||||
})
|
||||
|
||||
stream.once('end', () => {
|
||||
lazyReconnect(client, 'end')
|
||||
if (reconnect === undefined) reconnect = require('./reconnect')
|
||||
reconnect(client, 'end')
|
||||
})
|
||||
|
||||
if (options.tls) {
|
||||
|
@@ -1,16 +1,17 @@
|
||||
'use strict'
|
||||
|
||||
var index = {
|
||||
let index = {
|
||||
debugMode: /\bredis\b/i.test(process.env.NODE_DEBUG)
|
||||
}
|
||||
// Lazy load the main file
|
||||
process.nextTick(() => (index = require('../')))
|
||||
process.nextTick(() => { index = require('../') })
|
||||
|
||||
/**
|
||||
* @description Print a debug statement if in debug mode
|
||||
*/
|
||||
function debug () {
|
||||
function debug() {
|
||||
if (index.debugMode) {
|
||||
// eslint-disable-next-line
|
||||
console.error.apply(null, arguments)
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
const Errors = require('redis-errors')
|
||||
|
||||
// Flush provided queues, erroring out all items
|
||||
function flushAndError (client, message, code, options) {
|
||||
function flushAndError(client, message, code, options) {
|
||||
options = options || {}
|
||||
// Flush the commandQueue first to keep the order intact
|
||||
const queueNames = options.queues || ['commandQueue', 'offlineQueue']
|
||||
@@ -20,7 +20,7 @@ function flushAndError (client, message, code, options) {
|
||||
err.command = command.command.toUpperCase()
|
||||
err.args = command.args
|
||||
if (command.error) {
|
||||
err.stack = err.stack + command.error.stack.replace(/^Error.*?\n/, '\n')
|
||||
err.stack += command.error.stack.replace(/^Error.*?\n/, '\n')
|
||||
}
|
||||
if (options.error) {
|
||||
err.origin = options.error
|
||||
|
@@ -4,10 +4,11 @@ const Command = require('./command')
|
||||
const debug = require('./debug')
|
||||
const Multi = require('./multi')
|
||||
const utils = require('./utils')
|
||||
|
||||
const noPasswordIsSet = /no password is set/
|
||||
const RedisClient = require('./client')
|
||||
|
||||
/********************************************************************************************
|
||||
/** ******************************************************************************************
|
||||
Replace built-in redis functions
|
||||
|
||||
The callback may be hooked as needed. The same does not apply to the rest of the function.
|
||||
@@ -20,9 +21,9 @@ const RedisClient = require('./client')
|
||||
on single and multi calls!
|
||||
|
||||
TODO: Implement hooks to replace this. Most of these things are perfect for hooks
|
||||
********************************************************************************************/
|
||||
******************************************************************************************* */
|
||||
|
||||
function selectCallback (client, db) {
|
||||
function selectCallback(client, db) {
|
||||
return function (err, res) {
|
||||
if (err === null) {
|
||||
// Store db in this.selectDb to restore it on reconnect
|
||||
@@ -32,28 +33,31 @@ function selectCallback (client, db) {
|
||||
}
|
||||
}
|
||||
|
||||
RedisClient.prototype.select = function select (db) {
|
||||
RedisClient.prototype.select = function select(db) {
|
||||
return this.internalSendCommand(new Command('select', [db], null, selectCallback(this, db)))
|
||||
}
|
||||
|
||||
Multi.prototype.select = function select (db) {
|
||||
Multi.prototype.select = function select(db) {
|
||||
this._queue.push(new Command('select', [db], null, selectCallback(this._client, db)))
|
||||
return this
|
||||
}
|
||||
|
||||
RedisClient.prototype.monitor = function monitor () {
|
||||
// Use a individual command, as this is a special case that does not has to be checked for any other command
|
||||
RedisClient.prototype.monitor = function monitor() {
|
||||
// Use a individual command, as this is a special case that does not has to be
|
||||
// checked for any other command
|
||||
const callOnWrite = () => {
|
||||
// Activating monitor mode has to happen before Redis returned the callback. The monitor result is returned first.
|
||||
// Therefore we expect the command to be properly processed. If this is not the case, it's not an issue either.
|
||||
// Activating monitor mode has to happen before Redis returned the callback.
|
||||
// The monitor result is returned first. Therefore we expect the command to
|
||||
// be properly processed. If this is not the case, it's not an issue either.
|
||||
this._monitoring = true
|
||||
}
|
||||
return this.internalSendCommand(new Command('monitor', [], callOnWrite))
|
||||
}
|
||||
|
||||
// Only works with batch, not in a transaction
|
||||
Multi.prototype.monitor = function monitor () {
|
||||
// Use a individual command, as this is a special case that does not has to be checked for any other command
|
||||
Multi.prototype.monitor = function monitor() {
|
||||
// Use a individual command, as this is a special case that does not has to be
|
||||
// checked for any other command
|
||||
if (this._type !== 'multi') {
|
||||
const callOnWrite = () => {
|
||||
this._client._monitoring = true
|
||||
@@ -67,10 +71,11 @@ Multi.prototype.monitor = function monitor () {
|
||||
return this
|
||||
}
|
||||
|
||||
function quitCallback (client) {
|
||||
function quitCallback(client) {
|
||||
return function (err, res) {
|
||||
if (client._stream.writable) {
|
||||
// If the socket is still alive, destroy it. This could happen if quit got a NR_CLOSED error code
|
||||
// If the socket is still alive, destroy it. This could happen if quit got
|
||||
// a NR_CLOSED error code
|
||||
client._stream.destroy()
|
||||
}
|
||||
if (err && err.code === 'NR_CLOSED') {
|
||||
@@ -85,10 +90,11 @@ function quitCallback (client) {
|
||||
}
|
||||
}
|
||||
|
||||
RedisClient.prototype.quit = function quit () {
|
||||
RedisClient.prototype.quit = function quit() {
|
||||
// TODO: Consider this for v.3
|
||||
// Allow the quit command to be fired as soon as possible to prevent it landing in the offline queue.
|
||||
// this.ready = this.offlineQueue.length === 0;
|
||||
//
|
||||
// Allow the quit command to be fired as soon as possible to prevent it
|
||||
// landing in the offline queue. this.ready = this.offlineQueue.length === 0;
|
||||
const backpressureIndicator = this.internalSendCommand(new Command('quit', [], null, quitCallback(this)))
|
||||
// Calling quit should always end the connection, no matter if there's a connection or not
|
||||
this._closing = true
|
||||
@@ -97,7 +103,7 @@ RedisClient.prototype.quit = function quit () {
|
||||
}
|
||||
|
||||
// Only works with batch, not in a transaction
|
||||
Multi.prototype.quit = function quit () {
|
||||
Multi.prototype.quit = function quit() {
|
||||
const callOnWrite = () => {
|
||||
// If called in a multi context, we expect redis is available
|
||||
this._client._closing = true
|
||||
@@ -113,7 +119,7 @@ Multi.prototype.quit = function quit () {
|
||||
* @param {RedisClient} client
|
||||
* @returns {function}
|
||||
*/
|
||||
function infoCallback (client) {
|
||||
function infoCallback(client) {
|
||||
return function (err, res) {
|
||||
if (err) {
|
||||
return err
|
||||
@@ -125,7 +131,7 @@ function infoCallback (client) {
|
||||
|
||||
const obj = {}
|
||||
const lines = res.split('\r\n')
|
||||
var topic = ''
|
||||
let topic = ''
|
||||
|
||||
while (lines.length) {
|
||||
const parts = lines.shift().split(':')
|
||||
@@ -170,18 +176,18 @@ function infoCallback (client) {
|
||||
}
|
||||
|
||||
// Store info in this.serverInfo after each call
|
||||
RedisClient.prototype.info = function info (section) {
|
||||
RedisClient.prototype.info = function info(section) {
|
||||
const args = section ? [section] : []
|
||||
return this.internalSendCommand(new Command('info', args, null, infoCallback(this)))
|
||||
}
|
||||
|
||||
Multi.prototype.info = function info (section) {
|
||||
Multi.prototype.info = function info(section) {
|
||||
const args = section ? [section] : []
|
||||
this._queue.push(new Command('info', args, null, infoCallback(this._client)))
|
||||
return this
|
||||
}
|
||||
|
||||
function authCallback (client, pass) {
|
||||
function authCallback(client, pass) {
|
||||
return function (err, res) {
|
||||
if (err) {
|
||||
if (noPasswordIsSet.test(err.message)) {
|
||||
@@ -194,7 +200,7 @@ function authCallback (client, pass) {
|
||||
}
|
||||
}
|
||||
|
||||
RedisClient.prototype.auth = function auth (pass) {
|
||||
RedisClient.prototype.auth = function auth(pass) {
|
||||
debug('Sending auth to %s id %s', this.address, this.connectionId)
|
||||
|
||||
// Stash auth for connect and reconnect.
|
||||
@@ -207,7 +213,7 @@ RedisClient.prototype.auth = function auth (pass) {
|
||||
}
|
||||
|
||||
// Only works with batch, not in a transaction
|
||||
Multi.prototype.auth = function auth (pass) {
|
||||
Multi.prototype.auth = function auth(pass) {
|
||||
debug('Sending auth to %s id %s', this.address, this.connectionId)
|
||||
|
||||
// Stash auth for connect and reconnect.
|
||||
@@ -216,12 +222,7 @@ Multi.prototype.auth = function auth (pass) {
|
||||
return this
|
||||
}
|
||||
|
||||
RedisClient.prototype.client = function client () {
|
||||
const len = arguments.length
|
||||
const arr = new Array(len)
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
arr[i] = arguments[i]
|
||||
}
|
||||
RedisClient.prototype.client = function client(...arr) {
|
||||
var callOnWrite
|
||||
// CLIENT REPLY ON|OFF|SKIP
|
||||
if (arr.length === 2 && arr[0].toString().toUpperCase() === 'REPLY') {
|
||||
@@ -235,12 +236,7 @@ RedisClient.prototype.client = function client () {
|
||||
return this.internalSendCommand(new Command('client', arr, callOnWrite))
|
||||
}
|
||||
|
||||
Multi.prototype.client = function client () {
|
||||
const len = arguments.length
|
||||
const arr = new Array(len)
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
arr[i] = arguments[i]
|
||||
}
|
||||
Multi.prototype.client = function client(...arr) {
|
||||
var callOnWrite
|
||||
// CLIENT REPLY ON|OFF|SKIP
|
||||
if (arr.length === 2 && arr[0].toString().toUpperCase() === 'REPLY') {
|
||||
@@ -255,24 +251,14 @@ Multi.prototype.client = function client () {
|
||||
return this
|
||||
}
|
||||
|
||||
RedisClient.prototype.subscribe = function subscribe () {
|
||||
const len = arguments.length
|
||||
const arr = new Array(len)
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
arr[i] = arguments[i]
|
||||
}
|
||||
RedisClient.prototype.subscribe = function subscribe(...arr) {
|
||||
const callOnWrite = () => {
|
||||
this._pubSubMode = this._pubSubMode || this.commandQueue.length + 1
|
||||
}
|
||||
return this.internalSendCommand(new Command('subscribe', arr, callOnWrite))
|
||||
}
|
||||
|
||||
Multi.prototype.subscribe = function subscribe () {
|
||||
const len = arguments.length
|
||||
const arr = new Array(len)
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
arr[i] = arguments[i]
|
||||
}
|
||||
Multi.prototype.subscribe = function subscribe(...arr) {
|
||||
const callOnWrite = () => {
|
||||
this._client._pubSubMode = this._client._pubSubMode || this._client.commandQueue.length + 1
|
||||
}
|
||||
@@ -280,51 +266,33 @@ Multi.prototype.subscribe = function subscribe () {
|
||||
return this
|
||||
}
|
||||
|
||||
RedisClient.prototype.unsubscribe = function unsubscribe () {
|
||||
const len = arguments.length
|
||||
const arr = new Array(len)
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
arr[i] = arguments[i]
|
||||
}
|
||||
RedisClient.prototype.unsubscribe = function unsubscribe(...arr) {
|
||||
const callOnWrite = () => {
|
||||
// Pub sub has to be activated even if not in pub sub mode, as the return value is manipulated in the callback
|
||||
// Pub sub has to be activated even if not in pub sub mode, as the return
|
||||
// value is manipulated in the callback
|
||||
this._pubSubMode = this._pubSubMode || this.commandQueue.length + 1
|
||||
}
|
||||
return this.internalSendCommand(new Command('unsubscribe', arr, callOnWrite))
|
||||
}
|
||||
|
||||
Multi.prototype.unsubscribe = function unsubscribe () {
|
||||
const len = arguments.length
|
||||
const arr = new Array(len)
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
arr[i] = arguments[i]
|
||||
}
|
||||
Multi.prototype.unsubscribe = function unsubscribe(...arr) {
|
||||
const callOnWrite = () => {
|
||||
// Pub sub has to be activated even if not in pub sub mode, as the return value is manipulated in the callback
|
||||
// Pub sub has to be activated even if not in pub sub mode, as the return
|
||||
// value is manipulated in the callback
|
||||
this._client._pubSubMode = this._client._pubSubMode || this._client.commandQueue.length + 1
|
||||
}
|
||||
this._queue.push(new Command('unsubscribe', arr, callOnWrite))
|
||||
return this
|
||||
}
|
||||
|
||||
RedisClient.prototype.psubscribe = function psubscribe () {
|
||||
const len = arguments.length
|
||||
const arr = new Array(len)
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
arr[i] = arguments[i]
|
||||
}
|
||||
RedisClient.prototype.psubscribe = function psubscribe(...arr) {
|
||||
const callOnWrite = () => {
|
||||
this._pubSubMode = this._pubSubMode || this.commandQueue.length + 1
|
||||
}
|
||||
return this.internalSendCommand(new Command('psubscribe', arr, callOnWrite))
|
||||
}
|
||||
|
||||
Multi.prototype.psubscribe = function psubscribe () {
|
||||
const len = arguments.length
|
||||
const arr = new Array(len)
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
arr[i] = arguments[i]
|
||||
}
|
||||
Multi.prototype.psubscribe = function psubscribe(...arr) {
|
||||
const callOnWrite = () => {
|
||||
this._client._pubSubMode = this._client._pubSubMode || this._client.commandQueue.length + 1
|
||||
}
|
||||
@@ -332,27 +300,19 @@ Multi.prototype.psubscribe = function psubscribe () {
|
||||
return this
|
||||
}
|
||||
|
||||
RedisClient.prototype.punsubscribe = function punsubscribe () {
|
||||
const len = arguments.length
|
||||
const arr = new Array(len)
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
arr[i] = arguments[i]
|
||||
}
|
||||
RedisClient.prototype.punsubscribe = function punsubscribe(...arr) {
|
||||
const callOnWrite = () => {
|
||||
// Pub sub has to be activated even if not in pub sub mode, as the return value is manipulated in the callback
|
||||
// Pub sub has to be activated even if not in pub sub mode, as the return
|
||||
// value is manipulated in the callback
|
||||
this._pubSubMode = this._pubSubMode || this.commandQueue.length + 1
|
||||
}
|
||||
return this.internalSendCommand(new Command('punsubscribe', arr, callOnWrite))
|
||||
}
|
||||
|
||||
Multi.prototype.punsubscribe = function punsubscribe () {
|
||||
const len = arguments.length
|
||||
const arr = new Array(len)
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
arr[i] = arguments[i]
|
||||
}
|
||||
Multi.prototype.punsubscribe = function punsubscribe(...arr) {
|
||||
const callOnWrite = () => {
|
||||
// Pub sub has to be activated even if not in pub sub mode, as the return value is manipulated in the callback
|
||||
// Pub sub has to be activated even if not in pub sub mode, as the return
|
||||
// value is manipulated in the callback
|
||||
this._client._pubSubMode = this._client._pubSubMode || this._client.commandQueue.length + 1
|
||||
}
|
||||
this._queue.push(new Command('punsubscribe', arr, callOnWrite))
|
||||
|
45
lib/multi.js
45
lib/multi.js
@@ -4,6 +4,7 @@ const Queue = require('denque')
|
||||
const Errors = require('redis-errors')
|
||||
const Command = require('./command')
|
||||
const utils = require('./utils')
|
||||
|
||||
const handleReply = utils.handleReply
|
||||
|
||||
/**
|
||||
@@ -15,7 +16,7 @@ const handleReply = utils.handleReply
|
||||
* @param {number} index Command index in the Multi queue
|
||||
* @returns *
|
||||
*/
|
||||
function pipelineTransactionCommand (multi, command, index) {
|
||||
function pipelineTransactionCommand(multi, command, index) {
|
||||
// Queueing is done first, then the commands are executed
|
||||
const tmp = command.callback
|
||||
command.callback = function (err, reply) {
|
||||
@@ -37,7 +38,7 @@ function pipelineTransactionCommand (multi, command, index) {
|
||||
* @param {any[]} replies
|
||||
* @returns any[]
|
||||
*/
|
||||
function multiCallback (multi, replies) {
|
||||
function multiCallback(multi, replies) {
|
||||
if (replies) {
|
||||
var i = 0
|
||||
const queue = multi._queue
|
||||
@@ -70,13 +71,11 @@ function multiCallback (multi, replies) {
|
||||
* @param {Multi} multi
|
||||
* @returns Promise<any[]>
|
||||
*/
|
||||
function execTransaction (multi) {
|
||||
function execTransaction(multi) {
|
||||
const client = multi._client
|
||||
const queue = multi._queue
|
||||
if (multi._monitoring || client._monitoring) {
|
||||
const err = new RangeError(
|
||||
'Using transaction with a client that is in monitor mode does not work due to faulty return values of Redis.'
|
||||
)
|
||||
const err = new RangeError('Using transaction with a client that is in monitor mode does not work due to faulty return values of Redis.')
|
||||
err.command = 'EXEC'
|
||||
err.code = 'EXECABORT'
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -89,16 +88,19 @@ function execTransaction (multi) {
|
||||
// Silently ignore this error. We'll receive the error for the exec as well
|
||||
const promises = [client.internalSendCommand(new Command('multi', [])).catch(() => {})]
|
||||
// Drain queue, callback will catch 'QUEUED' or error
|
||||
for (var index = 0; index < len; index++) {
|
||||
for (let index = 0; index < len; index++) {
|
||||
// The commands may not be shifted off, since they are needed in the result handler
|
||||
promises.push(pipelineTransactionCommand(multi, queue.peekAt(index), index).catch((e) => e))
|
||||
promises.push(pipelineTransactionCommand(multi, queue.peekAt(index), index).catch(e => e))
|
||||
}
|
||||
|
||||
const main = client.internalSendCommand(new Command('exec', []))
|
||||
return Promise.all(promises).then(() => main.then((replies) => multiCallback(multi, replies)).catch((err) => {
|
||||
err.errors = multi._errors
|
||||
return Promise.reject(err)
|
||||
}))
|
||||
return Promise.all(promises)
|
||||
.then(() => main
|
||||
.then(replies => multiCallback(multi, replies))
|
||||
.catch((err) => {
|
||||
err.errors = multi._errors
|
||||
return Promise.reject(err)
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +109,7 @@ function execTransaction (multi) {
|
||||
* @param {Multi} multi
|
||||
* @returns Promise<any[]>
|
||||
*/
|
||||
function execBatch (multi) {
|
||||
function execBatch(multi) {
|
||||
const client = multi._client
|
||||
const queue = multi._queue
|
||||
if (queue.length === 0) {
|
||||
@@ -119,13 +121,14 @@ function execBatch (multi) {
|
||||
})
|
||||
}
|
||||
var error = false
|
||||
function setError(err) {
|
||||
error = true
|
||||
return err
|
||||
}
|
||||
const promises = []
|
||||
while (queue.length) {
|
||||
const command = queue.shift()
|
||||
promises.push(client.internalSendCommand(command).catch((e) => {
|
||||
error = true
|
||||
return e
|
||||
}))
|
||||
promises.push(client.internalSendCommand(command).catch(setError))
|
||||
}
|
||||
return Promise.all(promises).then((res) => {
|
||||
if (error) {
|
||||
@@ -147,14 +150,14 @@ class Multi {
|
||||
*
|
||||
* @memberof Multi
|
||||
*/
|
||||
constructor (client, type, args) {
|
||||
constructor(client, type, args) {
|
||||
this._client = client
|
||||
this._type = type
|
||||
this._queue = new Queue()
|
||||
// Either undefined or an array. Fail hard if it's not an array
|
||||
if (args) {
|
||||
// Legacy support for passing in an array of arguments
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
const command = args[i][0]
|
||||
const tmpArgs = args[i].slice(1)
|
||||
if (Array.isArray(command)) {
|
||||
@@ -173,7 +176,7 @@ class Multi {
|
||||
*
|
||||
* @memberof Multi
|
||||
*/
|
||||
execAtomic () {
|
||||
execAtomic() {
|
||||
if (this._queue.length < 2) {
|
||||
return this.execBatch()
|
||||
}
|
||||
@@ -187,7 +190,7 @@ class Multi {
|
||||
*
|
||||
* @memberof Multi
|
||||
*/
|
||||
exec () {
|
||||
exec() {
|
||||
if (this._type === 'batch') {
|
||||
return execBatch(this)
|
||||
}
|
||||
|
@@ -4,14 +4,14 @@ const Errors = require('redis-errors')
|
||||
const debug = require('./debug')
|
||||
const utils = require('./utils')
|
||||
|
||||
function offlineCommand (client, command) {
|
||||
function offlineCommand(client, command) {
|
||||
const commandName = command.command.toUpperCase()
|
||||
if (client._closing || client._options.enableOfflineQueue === false) {
|
||||
const msg = client._closing === true
|
||||
? 'The connection is already closed.'
|
||||
: client._stream.writable === true
|
||||
? 'The connection is not yet established and the offline queue is deactivated.'
|
||||
: 'Stream not writeable.'
|
||||
? 'The connection is not yet established and the offline queue is deactivated.'
|
||||
: 'Stream not writeable.'
|
||||
const err = new Errors.AbortError(`${commandName} can't be processed. ${msg}`)
|
||||
err.code = 'NR_CLOSED'
|
||||
err.command = commandName
|
||||
|
@@ -1,6 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const debug = require('./debug')
|
||||
|
||||
const SUBSCRIBE_COMMANDS = {
|
||||
subscribe: true,
|
||||
unsubscribe: true,
|
||||
@@ -8,17 +9,22 @@ const SUBSCRIBE_COMMANDS = {
|
||||
punsubscribe: true
|
||||
}
|
||||
|
||||
function subscribeUnsubscribe (client, reply, type) {
|
||||
// Subscribe commands take an optional callback and also emit an event, but only the Last_ response is included in the callback
|
||||
// The pub sub commands return each argument in a separate return value and have to be handled that way
|
||||
function subscribeUnsubscribe(client, reply, type) {
|
||||
// Subscribe commands take an optional callback and also emit an event, but
|
||||
// only the Last_ response is included in the callback The pub sub commands
|
||||
// return each argument in a separate return value and have to be handled that
|
||||
// way
|
||||
const commandObj = client.commandQueue.peekAt(0)
|
||||
const buffer = client._options.returnBuffers || client._options.detectBuffers && commandObj.bufferArgs
|
||||
const buffer = client._options.returnBuffers ||
|
||||
client._options.detectBuffers && commandObj.bufferArgs
|
||||
const channel = (buffer || reply[1] === null) ? reply[1] : reply[1].toString()
|
||||
const count = +reply[2] // Return the channel counter as number no matter if `stringNumbers` is activated or not
|
||||
// Return the channel counter as number no matter if `stringNumbers` is activated or not
|
||||
const count = +reply[2]
|
||||
debug(type, channel)
|
||||
|
||||
// Emit first, then return the callback
|
||||
if (channel !== null) { // Do not emit or "unsubscribe" something if there was no channel to unsubscribe from
|
||||
// Do not emit or "unsubscribe" something if there was no channel to unsubscribe from
|
||||
if (channel !== null) {
|
||||
if (type === 'subscribe' || type === 'psubscribe') {
|
||||
client._subscriptionSet[`${type}_${channel}`] = channel
|
||||
} else {
|
||||
@@ -29,10 +35,13 @@ function subscribeUnsubscribe (client, reply, type) {
|
||||
client._subscribeChannels.push(channel)
|
||||
}
|
||||
|
||||
if (commandObj.argsLength === 1 || client._subCommandsLeft === 1 || commandObj.argsLength === 0 && (count === 0 || channel === null)) {
|
||||
if (commandObj.argsLength === 1 ||
|
||||
client._subCommandsLeft === 1 ||
|
||||
commandObj.argsLength === 0 && (count === 0 || channel === null)) {
|
||||
if (count === 0) { // Unsubscribed from all channels
|
||||
client._pubSubMode = 0 // Deactivating pub sub mode
|
||||
// This should be a rare case and therefore handling it this way should be good performance wise for the general case
|
||||
// This should be a rare case and therefore handling it this way should be
|
||||
// good performance wise for the general case
|
||||
for (var i = 1; i < client.commandQueue.length; i++) {
|
||||
const runningCommand = client.commandQueue.peekAt(i)
|
||||
if (SUBSCRIBE_COMMANDS[runningCommand.command]) {
|
||||
@@ -45,16 +54,14 @@ function subscribeUnsubscribe (client, reply, type) {
|
||||
commandObj.callback(null, [count, client._subscribeChannels])
|
||||
client._subscribeChannels = []
|
||||
client._subCommandsLeft = 0
|
||||
} else if (client._subCommandsLeft !== 0) {
|
||||
client._subCommandsLeft--
|
||||
} else {
|
||||
if (client._subCommandsLeft !== 0) {
|
||||
client._subCommandsLeft--
|
||||
} else {
|
||||
client._subCommandsLeft = commandObj.argsLength ? commandObj.argsLength - 1 : count
|
||||
}
|
||||
client._subCommandsLeft = commandObj.argsLength ? commandObj.argsLength - 1 : count
|
||||
}
|
||||
}
|
||||
|
||||
function returnPubSub (client, reply) {
|
||||
function returnPubSub(client, reply) {
|
||||
const type = reply[0].toString()
|
||||
if (type === 'message') { // Channel, message
|
||||
if (typeof reply[1] !== 'string') {
|
||||
|
@@ -4,7 +4,7 @@ const Command = require('./command')
|
||||
const debug = require('./debug')
|
||||
const utils = require('./utils')
|
||||
|
||||
function onConnect (client) {
|
||||
function onConnect(client) {
|
||||
debug('Stream connected %s id %s', client.address, client.connectionId)
|
||||
|
||||
// TODO: Check if the clients prototype and the clients instance have
|
||||
@@ -30,7 +30,7 @@ function onConnect (client) {
|
||||
*
|
||||
* @param {RedisClient} client
|
||||
*/
|
||||
function sendOfflineQueue (client) {
|
||||
function sendOfflineQueue(client) {
|
||||
const queue = client.offlineQueue
|
||||
while (queue.length) {
|
||||
const command = queue.shift()
|
||||
@@ -47,7 +47,7 @@ function sendOfflineQueue (client) {
|
||||
*
|
||||
* @param {RedisClient} client
|
||||
*/
|
||||
function readyHandler (client) {
|
||||
function readyHandler(client) {
|
||||
debug('readyHandler called %s id %s', client.address, client.connectionId)
|
||||
client.ready = true
|
||||
|
||||
@@ -79,16 +79,16 @@ function readyHandler (client) {
|
||||
// }
|
||||
if (!client._options.disableResubscribing && callbackCount) {
|
||||
debug('Sending pub/sub commands')
|
||||
for (const key in client._subscriptionSet) {
|
||||
if (client._subscriptionSet.hasOwnProperty(key)) {
|
||||
const command = key.slice(0, key.indexOf('_'))
|
||||
const args = client._subscriptionSet[key]
|
||||
client[command]([args]).catch((err) => {
|
||||
if (!client._closing) {
|
||||
process.nextTick(client.emit, 'error', err)
|
||||
}
|
||||
})
|
||||
}
|
||||
const keys = Object.keys(client._subscriptionSet)
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
const key = keys[i]
|
||||
const command = key.slice(0, key.indexOf('_'))
|
||||
const args = client._subscriptionSet[key]
|
||||
client[command]([args]).catch((err) => {
|
||||
if (!client._closing) {
|
||||
process.nextTick(client.emit, 'error', err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
sendOfflineQueue(client)
|
||||
@@ -100,7 +100,7 @@ function readyHandler (client) {
|
||||
*
|
||||
* @param {RedisClient} client
|
||||
*/
|
||||
function readyCheck (client) {
|
||||
function readyCheck(client) {
|
||||
debug('Checking server ready state...')
|
||||
// Always fire client info command as first command even if other commands are already queued up
|
||||
client.ready = true
|
||||
@@ -112,7 +112,9 @@ function readyCheck (client) {
|
||||
}
|
||||
|
||||
const persistence = client.serverInfo.persistence
|
||||
if (persistence === undefined || persistence.loading === undefined || persistence.loading === 0) {
|
||||
if (persistence === undefined ||
|
||||
persistence.loading === undefined ||
|
||||
persistence.loading === 0) {
|
||||
// If the master_link_status exists but the link is not up, try again after 50 ms
|
||||
const replication = client.serverInfo.replication
|
||||
if (replication && typeof replication.master_link_status === 'string' && replication.master_link_status !== 'up') {
|
||||
@@ -125,12 +127,12 @@ function readyCheck (client) {
|
||||
}
|
||||
}
|
||||
|
||||
var retryTime = +persistence.loading_eta_seconds * 1000
|
||||
let retryTime = +persistence.loading_eta_seconds * 1000
|
||||
if (retryTime > 1000) {
|
||||
retryTime = 1000
|
||||
}
|
||||
debug('Redis server still loading, trying again in %s', retryTime)
|
||||
setTimeout((client) => readyCheck(client), retryTime, client)
|
||||
setTimeout(client => readyCheck(client), retryTime, client)
|
||||
}).catch((err) => {
|
||||
if (client._closing) {
|
||||
return
|
||||
@@ -142,7 +144,6 @@ function readyCheck (client) {
|
||||
}
|
||||
err.message = `Ready check failed: ${err.message}`
|
||||
client.emit('error', err)
|
||||
return
|
||||
})
|
||||
client.ready = false
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ const flushAndError = require('./flushAndError')
|
||||
* @param {RedisClient} client
|
||||
* @param {Error} [error]
|
||||
*/
|
||||
function retryConnection (client, error) {
|
||||
function retryConnection(client, error) {
|
||||
debug('Retrying connection...')
|
||||
|
||||
const reconnectParams = {
|
||||
@@ -36,7 +36,7 @@ function retryConnection (client, error) {
|
||||
* @param {string} why
|
||||
* @param {Error} [error]
|
||||
*/
|
||||
function reconnect (client, why, error) {
|
||||
function reconnect(client, why, error) {
|
||||
// If a retry is already in progress, just let that happen
|
||||
if (client.retryTimer) {
|
||||
return
|
||||
@@ -112,7 +112,12 @@ function reconnect (client, why, error) {
|
||||
|
||||
debug('Retry connection in %s ms', client.retryDelay)
|
||||
|
||||
client.retryTimer = setTimeout((client, error) => retryConnection(client, error), client.retryDelay, client, error)
|
||||
client.retryTimer = setTimeout(
|
||||
(client, error) => retryConnection(client, error),
|
||||
client.retryDelay,
|
||||
client,
|
||||
error
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = reconnect
|
||||
|
@@ -1,10 +1,10 @@
|
||||
'use strict'
|
||||
|
||||
const Buffer = require('buffer').Buffer
|
||||
const { Buffer } = require('buffer')
|
||||
const pubsub = require('./pubsub')
|
||||
const utils = require('./utils')
|
||||
|
||||
function onError (client, err) {
|
||||
function onError(client, err) {
|
||||
const commandObj = client.commandQueue.shift()
|
||||
if (commandObj.error) {
|
||||
err.stack = commandObj.error.stack.replace(/^Error.*?\n/, `ReplyError: ${err.message}\n`)
|
||||
@@ -28,7 +28,7 @@ function onError (client, err) {
|
||||
commandObj.callback(err)
|
||||
}
|
||||
|
||||
function normalReply (client, reply) {
|
||||
function normalReply(client, reply) {
|
||||
const command = client.commandQueue.shift()
|
||||
if (client._multi === false) {
|
||||
reply = utils.handleReply(client, reply, command)
|
||||
@@ -36,10 +36,11 @@ function normalReply (client, reply) {
|
||||
command.callback(null, reply)
|
||||
}
|
||||
|
||||
function onResult (client, reply) {
|
||||
// If in monitor mode, all normal commands are still working and we only want to emit the streamlined commands
|
||||
// As this is not the average use case and monitor is expensive anyway, let's change the code here, to improve
|
||||
// the average performance of all other commands in case of no monitor mode
|
||||
function onResult(client, reply) {
|
||||
// If in monitor mode, all normal commands are still working and we only want
|
||||
// to emit the streamlined commands As this is not the average use case and
|
||||
// monitor is expensive anyway, let's change the code here, to improve the
|
||||
// average performance of all other commands in case of no monitor mode
|
||||
if (client._monitoring === true) {
|
||||
var replyStr
|
||||
// TODO: This could be further improved performance wise
|
||||
|
@@ -5,9 +5,9 @@ const URL = require('url')
|
||||
|
||||
// TODO: Improve the unify performance by checking for the arguments length
|
||||
// before trying to access that argument.
|
||||
function unifyOptions (portArg, hostArg, options) {
|
||||
function unifyOptions(portArg, hostArg, options) {
|
||||
if (typeof portArg === 'number' || (typeof portArg === 'string' && /^\d+$/.test(portArg))) {
|
||||
var host
|
||||
let host
|
||||
if (typeof hostArg === 'string') {
|
||||
host = hostArg
|
||||
} else {
|
||||
@@ -24,6 +24,7 @@ function unifyOptions (portArg, hostArg, options) {
|
||||
|
||||
const parsed = URL.parse(portArg.url || portArg, true, true)
|
||||
|
||||
// eslint-disable-next-line
|
||||
// [redis:]//[[user][:password]@][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]]
|
||||
if (parsed.slashes) { // We require slashes
|
||||
if (parsed.auth) {
|
||||
@@ -42,11 +43,9 @@ function unifyOptions (portArg, hostArg, options) {
|
||||
options.port = parsed.port
|
||||
}
|
||||
if (parsed.search !== '') {
|
||||
for (var elem in parsed.query) {
|
||||
/* istanbul ignore if */
|
||||
if (!Object.prototype.hasOwnProperty.call(parsed.query, elem)) {
|
||||
continue
|
||||
}
|
||||
const keys = Object.keys(parsed.query)
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
const elem = keys[i]
|
||||
// If options are passed twice, only the parsed options will be used
|
||||
if (elem in options) {
|
||||
if (options[elem] === parsed.query[elem]) {
|
||||
|
27
lib/utils.js
27
lib/utils.js
@@ -6,12 +6,12 @@
|
||||
* @param {any[]} reply
|
||||
* @returns object
|
||||
*/
|
||||
function replyToObject (reply) {
|
||||
function replyToObject(reply) {
|
||||
if (reply.length === 0) {
|
||||
return null
|
||||
}
|
||||
const obj = {}
|
||||
for (let i = 0; i < reply.length; i += 2) {
|
||||
for (var i = 0; i < reply.length; i += 2) {
|
||||
obj[reply[i].toString('binary')] = reply[i + 1]
|
||||
}
|
||||
return obj
|
||||
@@ -23,7 +23,7 @@ function replyToObject (reply) {
|
||||
* @param {any[]} reply
|
||||
* @returns any[]|string
|
||||
*/
|
||||
function replyToStrings (reply) {
|
||||
function replyToStrings(reply) {
|
||||
if (reply === null) {
|
||||
return null
|
||||
}
|
||||
@@ -32,7 +32,7 @@ function replyToStrings (reply) {
|
||||
}
|
||||
if (typeof reply.map === 'function') { // instanceof Array
|
||||
const res = new Array(reply.length)
|
||||
for (let i = 0; i < reply.length; i++) {
|
||||
for (var i = 0; i < reply.length; i++) {
|
||||
// Recursively call the function as slowlog returns deep nested replies
|
||||
res[i] = replyToStrings(reply[i])
|
||||
}
|
||||
@@ -51,7 +51,7 @@ function replyToStrings (reply) {
|
||||
* @param {any} obj
|
||||
* @returns any
|
||||
*/
|
||||
function clone (obj) {
|
||||
function clone(obj) {
|
||||
if (Array.isArray(obj)) {
|
||||
const copy = new Array(obj.length)
|
||||
for (var i = 0; i < obj.length; i++) {
|
||||
@@ -81,7 +81,7 @@ function clone (obj) {
|
||||
* @param {undefined|object} obj
|
||||
* @returns object
|
||||
*/
|
||||
function convenienceClone (obj) {
|
||||
function convenienceClone(obj) {
|
||||
return clone(obj) || {}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ function convenienceClone (obj) {
|
||||
* @param {any} res
|
||||
* @param {Denque} queue
|
||||
*/
|
||||
function replyInOrder (client, callback, err, res, queue) {
|
||||
function replyInOrder(client, callback, err, res, queue) {
|
||||
const commandObj = queue
|
||||
? queue.peekBack()
|
||||
: (client.offlineQueue.peekBack() || client.commandQueue.peekBack())
|
||||
@@ -121,7 +121,7 @@ function replyInOrder (client, callback, err, res, queue) {
|
||||
* @param {RedisClient} client
|
||||
* @param {string} msg
|
||||
*/
|
||||
function warn (client, msg) {
|
||||
function warn(client, msg) {
|
||||
if (client.listeners('warning').length !== 0) {
|
||||
client.emit('warning', msg)
|
||||
} else {
|
||||
@@ -140,8 +140,9 @@ function warn (client, msg) {
|
||||
* @param {Command} command
|
||||
* @returns {string|number|null|Buffer|any[]|object}
|
||||
*/
|
||||
function handleReply (client, reply, command) {
|
||||
if (client._options.detectBuffers === true && command.bufferArgs === false || client._messageBuffers === true) {
|
||||
function handleReply(client, reply, command) {
|
||||
if (client._options.detectBuffers === true && command.bufferArgs === false ||
|
||||
client._messageBuffers === true) {
|
||||
reply = replyToStrings(reply)
|
||||
}
|
||||
|
||||
@@ -157,12 +158,12 @@ function handleReply (client, reply, command) {
|
||||
* @param {Error|null} err
|
||||
* @param {any} reply
|
||||
*/
|
||||
function print (err, reply) {
|
||||
function print(err, reply) {
|
||||
if (err) {
|
||||
// A error always begins with Error:
|
||||
console.error(err.toString())
|
||||
} else {
|
||||
console.log('Reply: ' + reply)
|
||||
console.log(`Reply: ${reply}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +172,7 @@ function print (err, reply) {
|
||||
*
|
||||
* @param {RedisClient} client
|
||||
*/
|
||||
function setReconnectDefaults (client) {
|
||||
function setReconnectDefaults(client) {
|
||||
client.retryTimer = null
|
||||
client.retryTotaltime = 0
|
||||
client.retryDelay = 100
|
||||
|
@@ -21,10 +21,11 @@ var errors = null
|
||||
/**
|
||||
* @description Pipeline and write all commands to the stream
|
||||
*
|
||||
* If the pipelined string exceeds X mb, write it directly to the stream and pipeline the rest again.
|
||||
* If the pipelined string exceeds X mb, write it directly to the stream and
|
||||
* pipeline the rest again.
|
||||
* @param {RedisClient} client
|
||||
*/
|
||||
function writeToStream (client) {
|
||||
function writeToStream(client) {
|
||||
const stream = client._stream
|
||||
const queue = client._pipelineQueue
|
||||
const cache = client._strCache
|
||||
@@ -41,7 +42,7 @@ function writeToStream (client) {
|
||||
client._pipeline = false
|
||||
}
|
||||
|
||||
function write (client) {
|
||||
function write(client) {
|
||||
if (client._pipeline === false) {
|
||||
client._stream.cork()
|
||||
client._pipeline = true
|
||||
@@ -49,11 +50,11 @@ function write (client) {
|
||||
}
|
||||
}
|
||||
|
||||
function pipelineBuffers (client, commandStr) {
|
||||
function pipelineBuffers(client, commandStr) {
|
||||
const queue = client._pipelineQueue
|
||||
client._strCache += commandStr
|
||||
while (copy.length) {
|
||||
var arg = copy.shift()
|
||||
const arg = copy.shift()
|
||||
if (typeof arg === 'string') {
|
||||
client._strCache += `$${Buffer.byteLength(arg)}\r\n${arg}\r\n`
|
||||
} else {
|
||||
@@ -69,20 +70,20 @@ function pipelineBuffers (client, commandStr) {
|
||||
client._strCache = ''
|
||||
}
|
||||
|
||||
function toString (arg) {
|
||||
function toString(arg) {
|
||||
if (typeof arg === 'string') {
|
||||
copy.push(arg)
|
||||
} else if (typeof arg === 'number') {
|
||||
copy.push('' + arg)
|
||||
copy.push(`${arg}`)
|
||||
} else if (arg instanceof Array) {
|
||||
for (var i = 0; i < arg.length; i += 1) {
|
||||
for (let i = 0; i < arg.length; i += 1) {
|
||||
toString(arg[i])
|
||||
}
|
||||
} else if (arg && arg.constructor.name === 'Buffer') { // TODO: check performance
|
||||
copy.push(arg)
|
||||
bufferCount++
|
||||
} else if (typeof arg === 'boolean') { // TODO: Remove this support and use hooks instead
|
||||
copy.push('' + arg)
|
||||
copy.push(`${arg}`)
|
||||
} else if (arg && arg.constructor.name === 'Object') { // Check if this is actually a good check or not
|
||||
// TODO: As soon as we add support for JSON
|
||||
// We could simple stringify this right here.
|
||||
@@ -99,7 +100,7 @@ function toString (arg) {
|
||||
toString(val)
|
||||
})
|
||||
} else if (arg instanceof Set) {
|
||||
arg.forEach((val) => toString(val))
|
||||
arg.forEach(val => toString(val))
|
||||
} else if (arg && arg.constructor.name === 'Date') { // Check if this is actually a good check or not
|
||||
copy.push(arg.toString())
|
||||
} else {
|
||||
@@ -110,7 +111,7 @@ function toString (arg) {
|
||||
}
|
||||
}
|
||||
|
||||
function returnErr (client, command) {
|
||||
function returnErr(client, command) {
|
||||
const err = new TypeError('NodeRedis can not handle the provided arguments (see "error.issues" property).\n\nFurther information https://github.com/asd')
|
||||
err.command = command.command.toUpperCase()
|
||||
err.args = command.args
|
||||
@@ -119,13 +120,14 @@ function returnErr (client, command) {
|
||||
utils.replyInOrder(client, command.callback, err, undefined, client.commandQueue)
|
||||
}
|
||||
|
||||
// Always use 'Multi bulk commands', but if passed any Buffer args, then do multiple writes, one for each arg.
|
||||
// This means that using Buffers in commands is going to be slower, so use Strings if you don't already have a Buffer.
|
||||
// Always use 'Multi bulk commands', but if passed any Buffer args, then do
|
||||
// multiple writes, one for each arg. This means that using Buffers in commands
|
||||
// is going to be slower, so use Strings if you don't already have a Buffer.
|
||||
|
||||
// TODO: It is faster to move this part somewhere else
|
||||
// We could move this to the function creation as well
|
||||
// if we use hooks for our individual commands!
|
||||
function normalizeAndWrite (client, command) {
|
||||
function normalizeAndWrite(client, command) {
|
||||
const args = command.args
|
||||
const origName = command.command
|
||||
const renameCommands = client._options.renameCommands
|
||||
@@ -134,7 +136,7 @@ function normalizeAndWrite (client, command) {
|
||||
: origName
|
||||
|
||||
bufferCount = 0
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
toString(args[i])
|
||||
}
|
||||
|
||||
@@ -153,7 +155,7 @@ function normalizeAndWrite (client, command) {
|
||||
|
||||
const bufferArgs = bufferCount !== 0
|
||||
const len = copy.length
|
||||
var commandStr = `*${len + 1}\r\n$${name.length}\r\n${name}\r\n`
|
||||
let commandStr = `*${len + 1}\r\n$${name.length}\r\n${name}\r\n`
|
||||
|
||||
command.bufferArgs = bufferArgs
|
||||
command.argsLength = len
|
||||
|
Reference in New Issue
Block a user