@@ -26,19 +26,6 @@ if (typeof EventEmitter !== 'function') {
2626
2727function noop ( ) { }
2828
29- function handle_detect_buffers_reply ( reply , command , buffer_args ) {
30- if ( buffer_args === false || this . message_buffers ) {
31- // If detect_buffers option was specified, then the reply from the parser will be a buffer.
32- // If this command did not use Buffer arguments, then convert the reply to Strings here.
33- reply = utils . reply_to_strings ( reply ) ;
34- }
35-
36- if ( command === 'hgetall' ) {
37- reply = utils . reply_to_object ( reply ) ;
38- }
39- return reply ;
40- }
41-
4229exports . debug_mode = / \b r e d i s \b / i. test ( process . env . NODE_DEBUG ) ;
4330
4431// Attention: The second parameter might be removed at will and is not officially supported.
@@ -111,10 +98,6 @@ function RedisClient (options, stream) {
11198 self . warn ( 'WARNING: You activated return_buffers and detect_buffers at the same time. The return value is always going to be a buffer.' ) ;
11299 options . detect_buffers = false ;
113100 }
114- if ( options . detect_buffers ) {
115- // We only need to look at the arguments if we do not know what we have to return
116- this . handle_reply = handle_detect_buffers_reply ;
117- }
118101 this . should_buffer = false ;
119102 this . max_attempts = options . max_attempts | 0 ;
120103 if ( 'max_attempts' in options ) {
@@ -143,17 +126,18 @@ function RedisClient (options, stream) {
143126 this . pub_sub_mode = 0 ;
144127 this . subscription_set = { } ;
145128 this . monitoring = false ;
146- this . message_buffers = false ;
129+ this . message_buffers = false ; // Do we have subscribes on message_buffer event
147130 this . closing = false ;
148131 this . server_info = { } ;
149132 this . auth_pass = options . auth_pass || options . password ;
150133 this . selected_db = options . db ; // Save the selected db here, used when reconnecting
151134 this . old_state = null ;
152135 this . fire_strings = true ; // Determine if strings or buffers should be written to the stream
136+ this . cur_command_ret_buf = 0 ;
153137 this . pipeline = false ;
154138 this . sub_commands_left = 0 ;
155139 this . times_connected = 0 ;
156- this . buffers = options . return_buffers || options . detect_buffers ;
140+ this . using_buffer_parser = options . return_buffers || options . detect_buffers ;
157141 this . options = options ;
158142 this . reply = 'ON' ; // Returning replies is the default
159143 // Init parser
@@ -171,17 +155,23 @@ function RedisClient (options, stream) {
171155 'The drain event listener is deprecated and will be removed in v.3.0.0.\n' +
172156 'If you want to keep on listening to this event please listen to the stream drain event directly.'
173157 ) ;
174- } else if ( event === 'message_buffer' || event === 'pmessage_buffer' || event === 'messageBuffer' || event === 'pmessageBuffer' && ! this . buffers ) {
158+ } else if ( event === 'message_buffer' || event === 'pmessage_buffer' || event === 'messageBuffer' || event === 'pmessageBuffer' ) {
175159 this . message_buffers = true ;
176- this . handle_reply = handle_detect_buffers_reply ;
177- this . reply_parser = create_parser ( this ) ;
160+ if ( ! this . using_buffer_parser ) {
161+ this . switchToBufferParser ( ) ;
162+ }
178163 }
179164 } ) ;
180165}
181166util . inherits ( RedisClient , EventEmitter ) ;
182167
183168RedisClient . connection_id = 0 ;
184169
170+ RedisClient . prototype . switchToBufferParser = function ( ) {
171+ this . using_buffer_parser = true ;
172+ this . reply_parser = create_parser ( this ) ;
173+ }
174+
185175function create_parser ( self ) {
186176 return new Parser ( {
187177 returnReply : function ( data ) {
@@ -206,7 +196,7 @@ function create_parser (self) {
206196 self . emit ( 'error' , err ) ;
207197 self . create_stream ( ) ;
208198 } ,
209- returnBuffers : self . buffers || self . message_buffers ,
199+ returnBuffers : self . using_buffer_parser ,
210200 name : self . options . parser || 'javascript' ,
211201 stringNumbers : self . options . string_numbers || false
212202 } ) ;
@@ -302,7 +292,15 @@ RedisClient.prototype.create_stream = function () {
302292 }
303293} ;
304294
305- RedisClient . prototype . handle_reply = function ( reply , command ) {
295+ RedisClient . prototype . handle_reply = function ( reply , command , buffer_reply ) {
296+ if ( ! buffer_reply && this . using_buffer_parser ) {
297+ // Reply from parser will be Buffer if:
298+ // 1) return_buffers option set to true
299+ // 2) or detect_buffers option set to true and command used Buffer arguments
300+ // 3) or buffer_reply argument was set to true when calling internal_send_command
301+ reply = utils . reply_to_strings ( reply ) ;
302+ }
303+
306304 if ( command === 'hgetall' ) {
307305 reply = utils . reply_to_object ( reply ) ;
308306 }
@@ -709,7 +707,7 @@ function normal_reply (self, reply) {
709707 var command_obj = self . command_queue . shift ( ) ;
710708 if ( typeof command_obj . callback === 'function' ) {
711709 if ( command_obj . command !== 'exec' ) {
712- reply = self . handle_reply ( reply , command_obj . command , command_obj . buffer_args ) ;
710+ reply = self . handle_reply ( reply , command_obj . command , command_obj . buffer_reply ) ;
713711 }
714712 command_obj . callback ( null , reply ) ;
715713 } else {
@@ -721,8 +719,7 @@ function subscribe_unsubscribe (self, reply, type) {
721719 // Subscribe commands take an optional callback and also emit an event, but only the _last_ response is included in the callback
722720 // The pub sub commands return each argument in a separate return value and have to be handled that way
723721 var command_obj = self . command_queue . get ( 0 ) ;
724- var buffer = self . options . return_buffers || self . options . detect_buffers && command_obj . buffer_args ;
725- var channel = ( buffer || reply [ 1 ] === null ) ? reply [ 1 ] : reply [ 1 ] . toString ( ) ;
722+ var channel = command_obj . buffer_reply || reply [ 1 ] === null ? reply [ 1 ] : reply [ 1 ] . toString ( ) ;
726723 var count = + reply [ 2 ] ; // Return the channel counter as number no matter if `string_numbers` is activated or not
727724 debug ( type , channel ) ;
728725
@@ -796,7 +793,7 @@ RedisClient.prototype.return_reply = function (reply) {
796793 // the average performance of all other commands in case of no monitor mode
797794 if ( this . monitoring ) {
798795 var replyStr ;
799- if ( this . buffers && Buffer . isBuffer ( reply ) ) {
796+ if ( this . using_buffer_parser && Buffer . isBuffer ( reply ) ) {
800797 replyStr = reply . toString ( ) ;
801798 } else {
802799 replyStr = reply ;
@@ -856,6 +853,11 @@ function handle_offline_command (self, command_obj) {
856853 self . should_buffer = true ;
857854}
858855
856+ RedisClient . prototype . internal_send_command_buf = function ( command_obj ) {
857+ command_obj . buffer_reply = true ;
858+ return this . internal_send_command ( command_obj ) ;
859+ } ;
860+
859861// Do not call internal_send_command directly, if you are not absolutly certain it handles everything properly
860862// e.g. monitor / info does not work with internal_send_command only
861863RedisClient . prototype . internal_send_command = function ( command_obj ) {
@@ -868,6 +870,12 @@ RedisClient.prototype.internal_send_command = function (command_obj) {
868870 var big_data = false ;
869871 var args_copy = new Array ( len ) ;
870872
873+ if ( this . options . return_buffers || this . cur_command_ret_buf ) {
874+ // this.cur_command_ret_buf check is needed for send_command_buf and "b_" prefixed individual commands
875+ // (but not for standart "b_" prefixed command)
876+ command_obj . buffer_reply = true ;
877+ }
878+
871879 if ( this . ready === false || this . stream . writable === false ) {
872880 // Handle offline commands right away
873881 handle_offline_command ( this , command_obj ) ;
@@ -878,6 +886,10 @@ RedisClient.prototype.internal_send_command = function (command_obj) {
878886 command_obj . callback = process . domain . bind ( command_obj . callback ) ;
879887 }
880888
889+ if ( command_obj . buffer_reply && ! this . using_buffer_parser ) {
890+ this . switchToBufferParser ( ) ;
891+ }
892+
881893 for ( i = 0 ; i < len ; i += 1 ) {
882894 if ( typeof args [ i ] === 'string' ) {
883895 // 30000 seemed to be a good value to switch to buffers after testing and checking the pros and cons
@@ -899,7 +911,7 @@ RedisClient.prototype.internal_send_command = function (command_obj) {
899911 args_copy [ i ] = 'null' ; // Backwards compatible :/
900912 } else if ( Buffer . isBuffer ( args [ i ] ) ) {
901913 args_copy [ i ] = args [ i ] ;
902- command_obj . buffer_args = true ;
914+ if ( this . options . detect_buffers ) command_obj . buffer_reply = true ;
903915 big_data = true ;
904916 } else {
905917 this . warn (
0 commit comments