Skip to content

Commit 60f8ee4

Browse files
committed
ribeesu
1 parent ed57f44 commit 60f8ee4

File tree

8 files changed

+841
-117
lines changed

8 files changed

+841
-117
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ client.get("missingkey", function(err, reply) {
109109
});
110110
```
111111

112+
If you want receive reply as Buffers instead of Strings just add "b_" prefix before command name:
113+
114+
```js
115+
client.b_get("some key", function(err, buf) {});
116+
```
117+
112118
For a list of Redis commands, see [Redis Command Reference](http://redis.io/commands)
113119

114120
Minimal parsing is done on the replies. Commands that return a integer return JavaScript Numbers, arrays return JavaScript Array. `HGETALL` returns an Object keyed by the hash keys. All strings will either be returned as string or as buffer depending on your setting.
@@ -666,6 +672,10 @@ The command_name has to be lower case.
666672

667673
All commands are sent as multi-bulk commands. `args` can either be an Array of arguments, or omitted / set to undefined.
668674

675+
## client.send_command_buf(command_name[, [args][, callback]])
676+
677+
The same as client.send_command but is sending reply as Buffers instead of Strings.
678+
669679
## client.connected
670680

671681
Boolean tracking the state of the connection to the Redis server.

index.js

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,6 @@ if (typeof EventEmitter !== 'function') {
2626

2727
function 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-
4229
exports.debug_mode = /\bredis\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
}
181166
util.inherits(RedisClient, EventEmitter);
182167

183168
RedisClient.connection_id = 0;
184169

170+
RedisClient.prototype.switchToBufferParser = function() {
171+
this.using_buffer_parser = true;
172+
this.reply_parser = create_parser(this);
173+
}
174+
185175
function 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
861863
RedisClient.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(

lib/command.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
var betterStackTraces = /development/i.test(process.env.NODE_ENV) || /\bredis\b/i.test(process.env.NODE_DEBUG);
44

5-
function Command (command, args, callback, call_on_write) {
5+
function Command (command, args, callback, call_on_write, buffer_reply) {
66
this.command = command;
77
this.args = args;
8-
this.buffer_args = false;
98
this.callback = callback;
109
this.call_on_write = call_on_write;
10+
this.buffer_reply = buffer_reply;
1111
if (betterStackTraces) {
1212
this.error = new Error();
1313
}

0 commit comments

Comments
 (0)