diff --git a/lib/cluster/index.js b/lib/cluster/index.js index 959dc11c..76ce4d00 100644 --- a/lib/cluster/index.js +++ b/lib/cluster/index.js @@ -423,8 +423,8 @@ Cluster.prototype.sendCommand = function (command, stream, node) { if (_this.status === 'ready' || (command.name === 'cluster')) { if (node && node.redis) { redis = node.redis; - } else if (_.includes(Command.FLAGS.ENTER_SUBSCRIBER_MODE, command.name) || - _.includes(Command.FLAGS.EXIT_SUBSCRIBER_MODE, command.name)) { + } else if (Command.checkFlag('ENTER_SUBSCRIBER_MODE', command.name) || + Command.checkFlag('EXIT_SUBSCRIBER_MODE', command.name)) { redis = _this.subscriber; } else { if (!random) { diff --git a/lib/command.js b/lib/command.js index 8ef9d95a..89f10f6a 100644 --- a/lib/command.js +++ b/lib/command.js @@ -228,9 +228,6 @@ Command.prototype.transformReply = function (result) { }; Command.FLAGS = { - // Commands that can be processed when Redis is loading data from disk - VALID_WHEN_LOADING: ['info', 'auth', 'select', 'subscribe', 'unsubscribe', 'psubscribe', - 'pubsubscribe', 'publish', 'shutdown', 'replconf', 'role', 'pubsub', 'command', 'latency'], // Commands that can be processed when client is in the subscriber mode VALID_IN_SUBSCRIBER_MODE: ['subscribe', 'psubscribe', 'unsubscribe', 'punsubscribe', 'ping', 'quit'], // Commands that are valid in monitor mode @@ -243,6 +240,25 @@ Command.FLAGS = { WILL_DISCONNECT: ['quit'] }; +var flagMap = Object.keys(Command.FLAGS).reduce(function (map, flagName) { + map[flagName] = {}; + Command.FLAGS[flagName].forEach(function (commandName) { + map[flagName][commandName] = true; + }); + return map; +}, {}); + +/** + * Check whether the command has the flag + * + * @param {string} flagName + * @param {string} commandName + * @return {boolean} + */ +Command.checkFlag = function (flagName, commandName) { + return !!flagMap[flagName][commandName]; +}; + Command._transformer = { argument: {}, reply: {} diff --git a/lib/redis.js b/lib/redis.js index 01aeb616..000f0914 100644 --- a/lib/redis.js +++ b/lib/redis.js @@ -13,6 +13,7 @@ var debug = require('debug')('ioredis:redis'); var Connector = require('./connectors/connector'); var SentinelConnector = require('./connectors/sentinel_connector'); var ScanStream = require('./scan_stream'); +var commands = require('redis-commands'); /** * Creates a Redis instance @@ -530,13 +531,13 @@ Redis.prototype.sendCommand = function (command, stream) { command.reject(new Error('Connection is closed.')); return command.promise; } - if (this.condition.subscriber && !_.includes(Command.FLAGS.VALID_IN_SUBSCRIBER_MODE, command.name)) { + if (this.condition.subscriber && !Command.checkFlag('VALID_IN_SUBSCRIBER_MODE', command.name)) { command.reject(new Error('Connection in subscriber mode, only subscriber commands may be used')); return command.promise; } var writable = (this.status === 'ready') || - ((this.status === 'connect') && _.includes(Command.FLAGS.VALID_WHEN_LOADING, command.name)); + ((this.status === 'connect') && commands.hasFlag(command.name, 'loading')); if (!this.stream) { writable = false; } else if (!this.stream.writable) { @@ -561,7 +562,7 @@ Redis.prototype.sendCommand = function (command, stream) { select: this.condition.select }); - if (_.includes(Command.FLAGS.WILL_DISCONNECT, command.name)) { + if (Command.checkFlag('WILL_DISCONNECT', command.name)) { this.manuallyClosing = true; } } else if (this.options.enableOfflineQueue) { diff --git a/lib/redis/event_handler.js b/lib/redis/event_handler.js index c7407d6f..2031071b 100644 --- a/lib/redis/event_handler.js +++ b/lib/redis/event_handler.js @@ -2,7 +2,6 @@ var debug = require('debug')('ioredis:connection'); var Command = require('../command'); -var _ = require('lodash'); exports.connectHandler = function (self) { return function () { @@ -123,7 +122,7 @@ exports.readyHandler = function (self) { self.call('monitor'); var sendCommand = self.sendCommand; self.sendCommand = function (command) { - if (_.includes(Command.FLAGS.VALID_IN_MONITOR_MODE, command.name)) { + if (Command.checkFlag('VALID_IN_MONITOR_MODE', command.name)) { return sendCommand.call(self, command); } command.reject(new Error('Connection is in monitoring mode, can\'t process commands.')); diff --git a/lib/redis/parser.js b/lib/redis/parser.js index 15c4dd09..ce79bc6f 100644 --- a/lib/redis/parser.js +++ b/lib/redis/parser.js @@ -158,16 +158,17 @@ exports.returnReply = function (reply) { item = this.commandQueue.shift(); if (!item) { return this.emit('error', - new Error('Command queue state error. If you can reproduce this, please report it. Last reply: ' + reply.toString())); + new Error('Command queue state error. If you can reproduce this, please report it. Last reply: ' + + reply.toString())); } - if (_.includes(Command.FLAGS.ENTER_SUBSCRIBER_MODE, item.command.name)) { + if (Command.checkFlag('ENTER_SUBSCRIBER_MODE', item.command.name)) { this.condition.subscriber = new SubscriptionSet(); this.condition.subscriber.add(item.command.name, reply[1].toString()); if (!fillSubCommand(item.command, reply[2])) { this.commandQueue.unshift(item); } - } else if (_.includes(Command.FLAGS.EXIT_SUBSCRIBER_MODE, item.command.name)) { + } else if (Command.checkFlag('EXIT_SUBSCRIBER_MODE', item.command.name)) { if (!fillUnsubCommand(item.command, reply[2])) { this.commandQueue.unshift(item); } diff --git a/test/functional/send_command.js b/test/functional/send_command.js index 05d92168..aff6d9fa 100644 --- a/test/functional/send_command.js +++ b/test/functional/send_command.js @@ -187,4 +187,24 @@ describe('send command', function () { }); }); }); + + it('should allow sending the loading valid commands in connect event', function (done) { + var redis = new Redis({ enableOfflineQueue: false }); + redis.on('connect', function () { + redis.select(2, function (err, res) { + expect(res).to.eql('OK'); + done(); + }); + }); + }); + + it('should reject loading invalid commands in connect event', function (done) { + var redis = new Redis({ enableOfflineQueue: false }); + redis.on('connect', function () { + redis.get('foo', function (err) { + expect(err.message).to.eql('Stream isn\'t writeable and enableOfflineQueue options is false'); + done(); + }); + }); + }); }); diff --git a/test/unit/command.js b/test/unit/command.js index eda4379b..56c544dd 100644 --- a/test/unit/command.js +++ b/test/unit/command.js @@ -73,4 +73,12 @@ describe('Command', function () { } }); }); + + describe('.checkFlag()', function () { + it('should return correct result', function () { + expect(Command.checkFlag('VALID_IN_SUBSCRIBER_MODE', 'ping')).to.eql(true); + expect(Command.checkFlag('VALID_IN_SUBSCRIBER_MODE', 'get')).to.eql(false); + expect(Command.checkFlag('WILL_DISCONNECT', 'quit')).to.eql(true); + }); + }); });