@@ -8,7 +8,7 @@ var utils = require('./lib/utils');
8
8
var Queue = require ( 'double-ended-queue' ) ;
9
9
var Command = require ( './lib/command' ) ;
10
10
var events = require ( 'events' ) ;
11
- var parsers = [ ] ;
11
+ var Parser = require ( 'redis-parser' ) ;
12
12
var commands = require ( 'redis-commands' ) ;
13
13
var connection_id = 0 ;
14
14
var default_port = 6379 ;
@@ -18,17 +18,20 @@ function noop () {}
18
18
function clone ( obj ) { return JSON . parse ( JSON . stringify ( obj || { } ) ) ; }
19
19
function debug ( msg ) { if ( exports . debug_mode ) { console . error ( msg ) ; } }
20
20
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
+ }
22
27
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 ;
29
32
}
30
33
31
- parsers . push ( require ( './lib/parsers/javascript' ) ) ;
34
+ exports . debug_mode = / \b r e d i s \b / i . test ( process . env . NODE_DEBUG ) ;
32
35
33
36
function RedisClient ( options ) {
34
37
// Copy the options so they are not mutated
@@ -69,6 +72,10 @@ function RedisClient (options) {
69
72
console . warn ( '>> WARNING: You activated return_buffers and detect_buffers at the same time. The return value is always going to be a buffer.' ) ;
70
73
options . detect_buffers = false ;
71
74
}
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
+ }
72
79
this . should_buffer = false ;
73
80
this . max_attempts = options . max_attempts | 0 ;
74
81
this . command_queue = new Queue ( ) ; // Holds sent commands to de-pipeline them
@@ -83,13 +90,22 @@ function RedisClient (options) {
83
90
this . closing = false ;
84
91
this . server_info = { } ;
85
92
this . auth_pass = options . auth_pass ;
86
- this . parser_module = null ;
87
93
this . selected_db = null ; // Save the selected db here, used when reconnecting
88
94
this . old_state = null ;
89
95
this . pipeline = 0 ;
90
96
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
+ } ) ;
93
109
this . create_stream ( ) ;
94
110
}
95
111
util . inherits ( RedisClient , events . EventEmitter ) ;
@@ -153,6 +169,13 @@ RedisClient.prototype.create_stream = function () {
153
169
} ) ;
154
170
} ;
155
171
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
+
156
179
RedisClient . prototype . cork = noop ;
157
180
RedisClient . prototype . uncork = noop ;
158
181
@@ -300,39 +323,6 @@ RedisClient.prototype.on_connect = function () {
300
323
}
301
324
} ;
302
325
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
-
336
326
RedisClient . prototype . on_ready = function ( ) {
337
327
var self = this ;
338
328
@@ -599,7 +589,7 @@ RedisClient.prototype.return_error = function (err) {
599
589
err . command = command_obj . command ;
600
590
}
601
591
602
- var match = err . message . match ( utils . errCode ) ;
592
+ var match = err . message . match ( utils . err_code ) ;
603
593
// LUA script could return user errors that don't behave like all other errors!
604
594
if ( match ) {
605
595
err . code = match [ 1 ] ;
@@ -650,16 +640,7 @@ RedisClient.prototype.return_reply = function (reply) {
650
640
if ( command_obj && ! command_obj . sub_command ) {
651
641
if ( typeof command_obj . callback === 'function' ) {
652
642
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 ) ;
663
644
}
664
645
command_obj . callback ( null , reply ) ;
665
646
} else {
@@ -722,8 +703,7 @@ RedisClient.prototype.send_command = function (command, args, callback) {
722
703
command_str = '' ,
723
704
buffer_args = false ,
724
705
big_data = false ,
725
- prefix_keys ,
726
- buffer = this . options . return_buffers ;
706
+ prefix_keys ;
727
707
728
708
if ( args === undefined ) {
729
709
args = [ ] ;
@@ -770,11 +750,8 @@ RedisClient.prototype.send_command = function (command, args, callback) {
770
750
}
771
751
}
772
752
}
773
- if ( this . options . detect_buffers ) {
774
- buffer = buffer_args ;
775
- }
776
753
777
- command_obj = new Command ( command , args , false , buffer , callback ) ;
754
+ command_obj = new Command ( command , args , false , buffer_args , callback ) ;
778
755
779
756
if ( ! this . ready && ! this . send_anyway || ! stream . writable ) {
780
757
if ( this . closing || ! this . enable_offline_queue ) {
@@ -1149,11 +1126,7 @@ Multi.prototype.exec_transaction = function (callback) {
1149
1126
cb = undefined ;
1150
1127
}
1151
1128
// 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 ) {
1157
1130
this . wants_buffers [ index ] = false ;
1158
1131
for ( var i = 0 ; i < args . length ; i += 1 ) {
1159
1132
if ( Buffer . isBuffer ( args [ i ] ) ) {
@@ -1193,20 +1166,14 @@ Multi.prototype.execute_callback = function (err, replies) {
1193
1166
while ( args = this . queue . shift ( ) ) {
1194
1167
// If we asked for strings, even in detect_buffers mode, then return strings:
1195
1168
if ( replies [ i ] instanceof Error ) {
1196
- var match = replies [ i ] . message . match ( utils . errCode ) ;
1169
+ var match = replies [ i ] . message . match ( utils . err_code ) ;
1197
1170
// LUA script could return user errors that don't behave like all other errors!
1198
1171
if ( match ) {
1199
1172
replies [ i ] . code = match [ 1 ] ;
1200
1173
}
1201
1174
replies [ i ] . command = args [ 0 ] . toUpperCase ( ) ;
1202
1175
} 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 ] ) ;
1210
1177
}
1211
1178
1212
1179
if ( typeof args [ args . length - 1 ] === 'function' ) {
0 commit comments