From a6670edb9aaf0f12b4d969eae21a67b3fc06b7a0 Mon Sep 17 00:00:00 2001 From: Dayananda Nanjundappa Date: Thu, 3 Nov 2011 16:32:47 +0530 Subject: [PATCH] Support for retrieving data as Buffer on a per command basis This is achieved by introducing a new option to the createClient method called bufferedInput. If bufferedInput is set to true, then the returned data will be a Buffer if the command argument passed is a buffer E.g. var redis = require("redis"), client = redis.createClient(, , {buffered_input: true}); client.set("foo_rand000000000000", "OK"); // The below get request will return a utf8 string client.get("foo_rand000000000000", function (err, reply) { console.log(reply.toString()); // Will print `OK` }); // The below get request will return a Buffer as the key is specified as a Buffer client.get(new Buffer("foo_rand000000000000"), function (err, reply) { console.log(reply.toString()); // Will print `` }); client.end(); --- README.md | 19 +++++++++++++++++++ index.js | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 02a873b191..520c28543d 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,25 @@ port and host are probably fine. `options` in an object with the following poss This may also be set to `javascript`. * `return_buffers`: defaults to false. If set to `true`, then bulk data replies will be returned as node Buffer objects instead of JavaScript Strings. +* `buffered_input`: default to false. If set to `true`, then data replies will be replied as node Buffer objects +if the input arguments are passed as a Buffer object. This option will let you retrieve data as a node Buffer object +or as string on a per command basis, unlike the returnBuffers, which applies to all the commands +E.g. + var redis = require("redis"), + client = redis.createClient(, , {buffered_input: true}); + + client.set("foo_rand000000000000", "OK"); + + // The below get request will return a utf8 string + client.get("foo_rand000000000000", function (err, reply) { + console.log(reply.toString()); // Will print `OK` + }); + + // The below get request will return a Buffer as the key is specified as a Buffer + client.get(new Buffer("foo_rand000000000000"), function (err, reply) { + console.log(reply.toString()); // Will print `` + }); + client.end(); `createClient()` returns a `RedisClient` object that is named `client` in all of the examples here. diff --git a/index.js b/index.js index a1dd40fe97..4befd494e5 100644 --- a/index.js +++ b/index.js @@ -210,8 +210,13 @@ RedisClient.prototype.init_parser = function () { this.parser_module.debug_mode = exports.debug_mode; this.reply_parser = new this.parser_module.Parser({ - return_buffers: self.options.return_buffers || false + // Always pass return_buffers or buffered_input is passed as an argument, + // then set the parser to return the data as Buffers + // For buffered_input, encoding to utf8 string will be done in return_reply method + // if the command argument is not a buffer + return_buffers: self.options.return_buffers || self.options.buffered_input || false }); + // "reply error" is an error sent back by Redis this.reply_parser.on("reply error", function (reply) { self.return_error(new Error(reply)); @@ -402,10 +407,57 @@ RedisClient.prototype.return_error = function (err) { } }; +RedisClient.prototype.encode_data = function (data) { + if(Buffer.isBuffer(data) ) { + // If the reply is a buffer, then encode to utf8 + return data.toString("utf8"); + } + + if(typeof data == "object") { + // Encode all the buffers in the object if in buffer format + return this.encode_object(data); + } + + return data; +}; + +RedisClient.prototype.encode_object = function (reply) { + for(var i in reply) { + reply[i] = this.encode_data(reply[i]); + } + + return reply; +}; + +RedisClient.prototype.encode_reply = function (command_obj, reply) { + // Return if the response is not because of a client command reauest + if(!command_obj) { + return reply; + } + + // If any of the arguments to the command are passed as Buffer, then + // return the reply as is (since it is already in Buffer format) + var command_args = command_obj.args; + for (var i = 0, len = command_args.length; i < len; i++) { + if (Buffer.isBuffer(command_args[i])) { + return reply; + } + } + + return this.encode_data(reply); +}; + RedisClient.prototype.return_reply = function (reply) { var command_obj = this.command_queue.shift(), obj, i, len, key, val, type, timestamp, args, queue_len = this.command_queue.getLength(); + if(this.options.buffered_input) { + // If the buffered input option was specified, then the reply from the parser will be + // in the form of buffers. In this case, convert the reply to utf8 string if command + // arguments was not passed as Buffer(which is again the default in most cases) + reply = this.encode_reply(command_obj, reply); + } + if (this.subscriptions === false && queue_len === 0) { this.emit("idle"); this.command_queue = new Queue(); // explicitly reclaim storage from old Queue