Skip to content

Commit 58ddd51

Browse files
author
Ruben Bridgewater
committed
Always refresh the server_info after running info; Remove proper auth support for redis < 2.6.11
1 parent 52f9873 commit 58ddd51

File tree

1 file changed

+91
-115
lines changed

1 file changed

+91
-115
lines changed

index.js

Lines changed: 91 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -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

177187
RedisClient.prototype.handle_reply = function (reply, command) {
@@ -248,89 +258,51 @@ RedisClient.prototype.on_error = function (err) {
248258
};
249259

250260
var noPasswordIsSet = /no password is set/;
251-
var loading = /LOADING/;
252261

253262
RedisClient.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

304283
RedisClient.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

331302
RedisClient.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 () {
401373
RedisClient.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

472407
RedisClient.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

484415
RedisClient.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+
1013991
RedisClient.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

10411017
RedisClient.prototype.hmset = RedisClient.prototype.HMSET = function (key, args, callback) {

0 commit comments

Comments
 (0)