@@ -97,6 +97,7 @@ function RedisClient (options) {
9797 this . auth_pass = options . auth_pass ;
9898 this . selected_db = null ; // Save the selected db here, used when reconnecting
9999 this . old_state = null ;
100+ this . send_anyway = false ;
100101 this . pipeline = 0 ;
101102 this . options = options ;
102103 // Init parser
@@ -172,6 +173,15 @@ RedisClient.prototype.create_stream = function () {
172173 this . stream . on ( 'drain' , function ( ) {
173174 self . drain ( ) ;
174175 } ) ;
176+
177+ if ( this . options . socket_nodelay ) {
178+ this . stream . setNoDelay ( ) ;
179+ }
180+
181+ // Fire the command before redis is connected to be sure it's the first fired command
182+ if ( typeof this . auth_pass === 'string' ) {
183+ this . do_auth ( ) ;
184+ }
175185} ;
176186
177187RedisClient . prototype . handle_reply = function ( reply , command ) {
@@ -248,89 +258,51 @@ RedisClient.prototype.on_error = function (err) {
248258} ;
249259
250260var noPasswordIsSet = / n o p a s s w o r d i s s e t / ;
251- var loading = / L O A D I N G / ;
252261
253262RedisClient . prototype . do_auth = function ( ) {
254263 var self = this ;
255-
256264 debug ( 'Sending auth to ' + self . address + ' id ' + self . connection_id ) ;
257265
258- self . send_anyway = true ;
259- self . send_command ( 'auth' , [ this . auth_pass ] , function ( err , res ) {
266+ this . send_anyway = true ;
267+ this . send_command ( 'auth' , [ this . auth_pass ] , function ( err , res ) {
260268 if ( err ) {
261- /* istanbul ignore if: this is almost impossible to test */
262- if ( loading . test ( err . message ) ) {
263- // If redis is still loading the db, it will not authenticate and everything else will fail
264- debug ( 'Redis still loading, trying to authenticate later' ) ;
265- setTimeout ( function ( ) {
266- self . do_auth ( ) ;
267- } , 333 ) ;
268- return ;
269- } else if ( noPasswordIsSet . test ( err . message ) ) {
269+ if ( noPasswordIsSet . test ( err . message ) ) {
270270 debug ( 'Warning: Redis server does not require a password, but a password was supplied.' ) ;
271271 err = null ;
272272 res = 'OK' ;
273- } else if ( self . auth_callback ) {
274- self . auth_callback ( err ) ;
275- self . auth_callback = null ;
276- return ;
277273 } else {
278274 self . emit ( 'error' , err ) ;
279- return ;
280275 }
281- }
282-
283- res = res . toString ( ) ;
284- debug ( 'Auth succeeded ' + self . address + ' id ' + self . connection_id ) ;
285-
286- if ( self . auth_callback ) {
287- self . auth_callback ( null , res ) ;
288- self . auth_callback = null ;
289- }
290-
291- // Now we are really connected
292- self . emit ( 'connect' ) ;
293- self . initialize_retry_vars ( ) ;
294-
295- if ( self . options . no_ready_check ) {
296- self . on_ready ( ) ;
297276 } else {
298- self . ready_check ( ) ;
277+ debug ( 'Auth succeeded ' + self . address + ' id ' + self . connection_id ) ;
299278 }
300279 } ) ;
301- self . send_anyway = false ;
280+ this . send_anyway = false ;
302281} ;
303282
304283RedisClient . prototype . on_connect = function ( ) {
305284 debug ( 'Stream connected ' + this . address + ' id ' + this . connection_id ) ;
306285
307286 this . connected = true ;
308287 this . ready = false ;
309- this . connections += 1 ;
310288 this . emitted_end = false ;
311- if ( this . options . socket_nodelay ) {
312- this . stream . setNoDelay ( ) ;
313- }
314289 this . stream . setKeepAlive ( this . options . socket_keepalive ) ;
315290 this . stream . setTimeout ( 0 ) ;
316291
317- if ( typeof this . auth_pass === 'string' ) {
318- this . do_auth ( ) ;
319- } else {
320- this . emit ( 'connect' ) ;
321- this . initialize_retry_vars ( ) ;
292+ this . emit ( 'connect' ) ;
293+ this . initialize_retry_vars ( ) ;
322294
323- if ( this . options . no_ready_check ) {
324- this . on_ready ( ) ;
325- } else {
326- this . ready_check ( ) ;
327- }
295+ if ( this . options . no_ready_check ) {
296+ this . on_ready ( ) ;
297+ } else {
298+ this . ready_check ( ) ;
328299 }
329300} ;
330301
331302RedisClient . prototype . on_ready = function ( ) {
332303 var self = this ;
333304
305+ debug ( 'on_ready called ' + this . address + ' id ' + this . connection_id ) ;
334306 this . ready = true ;
335307
336308 if ( this . old_state !== null ) {
@@ -358,8 +330,8 @@ RedisClient.prototype.on_ready = function () {
358330 }
359331 this . cork = cork ;
360332
361- // magically restore any modal commands from a previous connection
362- if ( this . selected_db !== null ) {
333+ // restore modal commands from previous connection
334+ if ( this . selected_db !== undefined ) {
363335 // this trick works if and only if the following send_command
364336 // never goes into the offline queue
365337 var pub_sub_mode = this . pub_sub_mode ;
@@ -401,84 +373,43 @@ RedisClient.prototype.on_ready = function () {
401373RedisClient . prototype . on_info_cmd = function ( err , res ) {
402374 if ( err ) {
403375 if ( err . message === "ERR unknown command 'info'" ) {
404- this . server_info = { } ;
405376 this . on_ready ( ) ;
406377 return ;
407- } else {
408- err . message = 'Ready check failed: ' + err . message ;
409- this . emit ( 'error' , err ) ;
410- return ;
411- }
378+ }
379+ err . message = 'Ready check failed: ' + err . message ;
380+ this . emit ( 'error' , err ) ;
381+ return ;
412382 }
413383
414384 /* istanbul ignore if: some servers might not respond with any info data. This is just a safety check that is difficult to test */
415385 if ( ! res ) {
416386 debug ( 'The info command returned without any data.' ) ;
417- this . server_info = { } ;
418387 this . on_ready ( ) ;
419388 return ;
420389 }
421390
422- var obj = { } ;
423- var lines = res . toString ( ) . split ( '\r\n' ) ;
424- var i = 0 ;
425- var key = 'db' + i ;
426- var line , retry_time , parts , sub_parts ;
427-
428- for ( i = 0 ; i < lines . length ; i ++ ) {
429- parts = lines [ i ] . split ( ':' ) ;
430- if ( parts [ 1 ] ) {
431- obj [ parts [ 0 ] ] = parts [ 1 ] ;
432- }
433- }
434-
435- obj . versions = [ ] ;
436- /* istanbul ignore else: some redis servers do not send the version */
437- if ( obj . redis_version ) {
438- obj . redis_version . split ( '.' ) . forEach ( function ( num ) {
439- obj . versions . push ( + num ) ;
440- } ) ;
441- }
442-
443- while ( obj [ key ] ) {
444- parts = obj [ key ] . split ( ',' ) ;
445- obj [ key ] = { } ;
446- while ( line = parts . pop ( ) ) {
447- sub_parts = line . split ( '=' ) ;
448- obj [ key ] [ sub_parts [ 0 ] ] = + sub_parts [ 1 ] ;
449- }
450- i ++ ;
451- key = 'db' + i ;
452- }
453-
454- // Expose info key/vals to users
455- this . server_info = obj ;
456-
457- if ( ! obj . loading || obj . loading === '0' ) {
391+ if ( ! this . server_info . loading || this . server_info . loading === '0' ) {
458392 debug ( 'Redis server ready.' ) ;
459393 this . on_ready ( ) ;
460- } else {
461- retry_time = obj . loading_eta_seconds * 1000 ;
462- if ( retry_time > 1000 ) {
463- retry_time = 1000 ;
464- }
465- debug ( 'Redis server still loading, trying again in ' + retry_time ) ;
466- setTimeout ( function ( self ) {
467- self . ready_check ( ) ;
468- } , retry_time , this ) ;
394+ return ;
395+ }
396+
397+ var retry_time = + this . server_info . loading_eta_seconds * 1000 ;
398+ if ( retry_time > 1000 ) {
399+ retry_time = 1000 ;
469400 }
401+ debug ( 'Redis server still loading, trying again in ' + retry_time ) ;
402+ setTimeout ( function ( self ) {
403+ self . ready_check ( ) ;
404+ } , retry_time , this ) ;
470405} ;
471406
472407RedisClient . prototype . ready_check = function ( ) {
473408 var self = this ;
474-
475409 debug ( 'Checking server ready state...' ) ;
476-
477- this . send_anyway = true ; // secret flag to send_command to send something even if not 'ready'
478410 this . info ( function ( err , res ) {
479411 self . on_info_cmd ( err , res ) ;
480412 } ) ;
481- this . send_anyway = false ;
482413} ;
483414
484415RedisClient . prototype . send_offline_queue = function ( ) {
@@ -531,7 +462,7 @@ RedisClient.prototype.connection_gone = function (why) {
531462 this . old_state = state ;
532463 this . monitoring = false ;
533464 this . pub_sub_mode = false ;
534- this . selected_db = null ;
465+ this . selected_db = undefined ;
535466 }
536467
537468 // since we are collapsing end and close, users don't expect to be called twice
@@ -1010,6 +941,53 @@ RedisClient.prototype.select = RedisClient.prototype.SELECT = function (db, call
1010941 } ) ;
1011942} ;
1012943
944+ // Store db in this.select_db to restore it on reconnect
945+ RedisClient . prototype . info = RedisClient . prototype . INFO = function ( callback ) {
946+ var self = this ;
947+ this . send_anyway = true ;
948+ var tmp = this . send_command ( 'info' , [ ] , function ( err , res ) {
949+ if ( res ) {
950+ var obj = { } ;
951+ var lines = res . toString ( ) . split ( '\r\n' ) ;
952+ var line , parts , sub_parts ;
953+
954+ for ( var i = 0 ; i < lines . length ; i ++ ) {
955+ parts = lines [ i ] . split ( ':' ) ;
956+ if ( parts [ 1 ] ) {
957+ if ( parts [ 0 ] . indexOf ( 'db' ) === 0 ) {
958+ sub_parts = parts [ 1 ] . split ( ',' ) ;
959+ obj [ parts [ 0 ] ] = { } ;
960+ while ( line = sub_parts . pop ( ) ) {
961+ line = line . split ( '=' ) ;
962+ obj [ parts [ 0 ] ] [ line [ 0 ] ] = + line [ 1 ] ;
963+ }
964+ } else {
965+ obj [ parts [ 0 ] ] = parts [ 1 ] ;
966+ }
967+ }
968+ }
969+ obj . versions = [ ] ;
970+ /* istanbul ignore else: some redis servers do not send the version */
971+ if ( obj . redis_version ) {
972+ obj . redis_version . split ( '.' ) . forEach ( function ( num ) {
973+ obj . versions . push ( + num ) ;
974+ } ) ;
975+ }
976+ // Expose info key/vals to users
977+ self . server_info = obj ;
978+ } else {
979+ self . server_info = { } ;
980+ }
981+ if ( typeof callback === 'function' ) {
982+ callback ( err , res ) ;
983+ } else if ( err ) {
984+ self . emit ( 'error' , err ) ;
985+ }
986+ } ) ;
987+ this . send_anyway = false ;
988+ return tmp ;
989+ } ;
990+
1013991RedisClient . prototype . callback_emit_error = function ( callback , err ) {
1014992 if ( callback ) {
1015993 setImmediate ( function ( ) {
@@ -1030,12 +1008,10 @@ RedisClient.prototype.auth = RedisClient.prototype.AUTH = function (pass, callba
10301008 }
10311009 this . auth_pass = pass ;
10321010 debug ( 'Saving auth as ' + this . auth_pass ) ;
1033- // Only run the callback once. So do not safe it if already connected
1034- if ( this . connected ) {
1035- return this . send_command ( 'auth' , [ this . auth_pass ] , callback ) ;
1036- }
1037- this . auth_callback = callback ;
1038- return true ;
1011+ this . send_anyway = true ;
1012+ var tmp = this . send_command ( 'auth' , [ pass ] , callback ) ;
1013+ this . send_anyway = false ;
1014+ return tmp ;
10391015} ;
10401016
10411017RedisClient . prototype . hmset = RedisClient . prototype . HMSET = function ( key , args , callback ) {
0 commit comments