@@ -8,7 +8,7 @@ var utils = require('./lib/utils');
88var Queue = require ( 'double-ended-queue' ) ;
99var Command = require ( './lib/command' ) ;
1010var events = require ( 'events' ) ;
11- var parsers = [ ] ;
11+ var Parser = require ( 'redis-parser' ) ;
1212var commands = require ( 'redis-commands' ) ;
1313var connection_id = 0 ;
1414var default_port = 6379 ;
@@ -18,17 +18,20 @@ function noop () {}
1818function clone ( obj ) { return JSON . parse ( JSON . stringify ( obj || { } ) ) ; }
1919function debug ( msg ) { if ( exports . debug_mode ) { console . error ( msg ) ; } }
2020
21- exports . debug_mode = / \b r e d i s \b / i. test ( process . env . NODE_DEBUG ) ;
21+ function handle_detect_buffers_reply ( reply , command , buffer_args ) {
22+ if ( buffer_args === false ) {
23+ // If detect_buffers option was specified, then the reply from the parser will be a buffer.
24+ // If this command did not use Buffer arguments, then convert the reply to Strings here.
25+ reply = utils . reply_to_strings ( reply ) ;
26+ }
2227
23- // Hiredis might not be installed
24- try {
25- parsers . push ( require ( './lib/parsers/hiredis' ) ) ;
26- } catch ( err ) {
27- /* istanbul ignore next: won't be reached with tests */
28- debug ( 'Hiredis parser not installed.' ) ;
28+ if ( command === 'hgetall' ) {
29+ reply = utils . reply_to_object ( reply ) ;
30+ }
31+ return reply ;
2932}
3033
31- parsers . push ( require ( './lib/parsers/javascript' ) ) ;
34+ exports . debug_mode = / \b r e d i s \b / i . test ( process . env . NODE_DEBUG ) ;
3235
3336function RedisClient ( options ) {
3437 // Copy the options so they are not mutated
@@ -69,6 +72,10 @@ function RedisClient (options) {
6972 console . warn ( '>> WARNING: You activated return_buffers and detect_buffers at the same time. The return value is always going to be a buffer.' ) ;
7073 options . detect_buffers = false ;
7174 }
75+ if ( options . detect_buffers ) {
76+ // We only need to look at the arguments if we do not know what we have to return
77+ this . handle_reply = handle_detect_buffers_reply ;
78+ }
7279 this . should_buffer = false ;
7380 this . max_attempts = options . max_attempts | 0 ;
7481 this . command_queue = new Queue ( ) ; // Holds sent commands to de-pipeline them
@@ -83,13 +90,22 @@ function RedisClient (options) {
8390 this . closing = false ;
8491 this . server_info = { } ;
8592 this . auth_pass = options . auth_pass ;
86- this . parser_module = null ;
8793 this . selected_db = null ; // Save the selected db here, used when reconnecting
8894 this . old_state = null ;
8995 this . pipeline = 0 ;
9096 this . options = options ;
91- // Init parser once per instance
92- this . init_parser ( ) ;
97+ // Init parser
98+ var self = this ;
99+ this . reply_parser = new Parser ( {
100+ returnReply : function ( data ) {
101+ self . return_reply ( data ) ;
102+ } ,
103+ returnError : function ( data ) {
104+ self . return_error ( data ) ;
105+ } ,
106+ returnBuffers : options . return_buffers || options . detect_buffers ,
107+ name : options . parser
108+ } ) ;
93109 this . create_stream ( ) ;
94110}
95111util . inherits ( RedisClient , events . EventEmitter ) ;
@@ -153,6 +169,13 @@ RedisClient.prototype.create_stream = function () {
153169 } ) ;
154170} ;
155171
172+ RedisClient . prototype . handle_reply = function ( reply , command ) {
173+ if ( command === 'hgetall' ) {
174+ reply = utils . reply_to_object ( reply ) ;
175+ }
176+ return reply ;
177+ } ;
178+
156179RedisClient . prototype . cork = noop ;
157180RedisClient . prototype . uncork = noop ;
158181
@@ -300,39 +323,6 @@ RedisClient.prototype.on_connect = function () {
300323 }
301324} ;
302325
303- RedisClient . prototype . init_parser = function ( ) {
304- var self = this ;
305-
306- if ( this . options . parser ) {
307- if ( ! parsers . some ( function ( parser ) {
308- if ( parser . name === self . options . parser ) {
309- self . parser_module = parser ;
310- debug ( 'Using parser module: ' + self . parser_module . name ) ;
311- return true ;
312- }
313- } ) ) {
314- // Do not emit this error
315- // This should take down the app if anyone made such a huge mistake or should somehow be handled in user code
316- throw new Error ( "Couldn't find named parser " + self . options . parser + " on this system" ) ;
317- }
318- } else {
319- debug ( 'Using default parser module: ' + parsers [ 0 ] . name ) ;
320- this . parser_module = parsers [ 0 ] ;
321- }
322-
323- // return_buffers sends back Buffers from parser to callback. detect_buffers sends back Buffers from parser, but
324- // converts to Strings if the input arguments are not Buffers.
325- this . reply_parser = new this . parser_module . Parser ( self . options . return_buffers || self . options . detect_buffers ) ;
326- // Important: Only send results / errors async.
327- // That way the result / error won't stay in a try catch block and catch user things
328- this . reply_parser . send_error = function ( data ) {
329- self . return_error ( data ) ;
330- } ;
331- this . reply_parser . send_reply = function ( data ) {
332- self . return_reply ( data ) ;
333- } ;
334- } ;
335-
336326RedisClient . prototype . on_ready = function ( ) {
337327 var self = this ;
338328
@@ -599,7 +589,7 @@ RedisClient.prototype.return_error = function (err) {
599589 err . command = command_obj . command ;
600590 }
601591
602- var match = err . message . match ( utils . errCode ) ;
592+ var match = err . message . match ( utils . err_code ) ;
603593 // LUA script could return user errors that don't behave like all other errors!
604594 if ( match ) {
605595 err . code = match [ 1 ] ;
@@ -650,16 +640,7 @@ RedisClient.prototype.return_reply = function (reply) {
650640 if ( command_obj && ! command_obj . sub_command ) {
651641 if ( typeof command_obj . callback === 'function' ) {
652642 if ( 'exec' !== command_obj . command ) {
653- if ( command_obj . buffer_args === false ) {
654- // If detect_buffers option was specified, then the reply from the parser will be Buffers.
655- // If this command did not use Buffer arguments, then convert the reply to Strings here.
656- reply = utils . reply_to_strings ( reply ) ;
657- }
658-
659- // TODO - confusing and error-prone that hgetall is special cased in two places
660- if ( 'hgetall' === command_obj . command ) {
661- reply = utils . reply_to_object ( reply ) ;
662- }
643+ reply = this . handle_reply ( reply , command_obj . command , command_obj . buffer_args ) ;
663644 }
664645 command_obj . callback ( null , reply ) ;
665646 } else {
@@ -722,8 +703,7 @@ RedisClient.prototype.send_command = function (command, args, callback) {
722703 command_str = '' ,
723704 buffer_args = false ,
724705 big_data = false ,
725- prefix_keys ,
726- buffer = this . options . return_buffers ;
706+ prefix_keys ;
727707
728708 if ( args === undefined ) {
729709 args = [ ] ;
@@ -770,11 +750,8 @@ RedisClient.prototype.send_command = function (command, args, callback) {
770750 }
771751 }
772752 }
773- if ( this . options . detect_buffers ) {
774- buffer = buffer_args ;
775- }
776753
777- command_obj = new Command ( command , args , false , buffer , callback ) ;
754+ command_obj = new Command ( command , args , false , buffer_args , callback ) ;
778755
779756 if ( ! this . ready && ! this . send_anyway || ! stream . writable ) {
780757 if ( this . closing || ! this . enable_offline_queue ) {
@@ -1149,11 +1126,7 @@ Multi.prototype.exec_transaction = function (callback) {
11491126 cb = undefined ;
11501127 }
11511128 // Keep track of who wants buffer responses:
1152- if ( this . _client . options . return_buffers ) {
1153- this . wants_buffers [ index ] = true ;
1154- } else if ( ! this . _client . options . detect_buffers ) {
1155- this . wants_buffers [ index ] = false ;
1156- } else {
1129+ if ( this . _client . options . detect_buffers ) {
11571130 this . wants_buffers [ index ] = false ;
11581131 for ( var i = 0 ; i < args . length ; i += 1 ) {
11591132 if ( Buffer . isBuffer ( args [ i ] ) ) {
@@ -1193,20 +1166,14 @@ Multi.prototype.execute_callback = function (err, replies) {
11931166 while ( args = this . queue . shift ( ) ) {
11941167 // If we asked for strings, even in detect_buffers mode, then return strings:
11951168 if ( replies [ i ] instanceof Error ) {
1196- var match = replies [ i ] . message . match ( utils . errCode ) ;
1169+ var match = replies [ i ] . message . match ( utils . err_code ) ;
11971170 // LUA script could return user errors that don't behave like all other errors!
11981171 if ( match ) {
11991172 replies [ i ] . code = match [ 1 ] ;
12001173 }
12011174 replies [ i ] . command = args [ 0 ] . toUpperCase ( ) ;
12021175 } else if ( replies [ i ] ) {
1203- if ( this . wants_buffers [ i ] === false ) {
1204- replies [ i ] = utils . reply_to_strings ( replies [ i ] ) ;
1205- }
1206- if ( args [ 0 ] === 'hgetall' ) {
1207- // TODO - confusing and error-prone that hgetall is special cased in two places
1208- replies [ i ] = utils . reply_to_object ( replies [ i ] ) ;
1209- }
1176+ replies [ i ] = this . _client . handle_reply ( replies [ i ] , args [ 0 ] , this . wants_buffers [ i ] ) ;
12101177 }
12111178
12121179 if ( typeof args [ args . length - 1 ] === 'function' ) {
0 commit comments