|
|
@ -1,10 +1,14 @@ |
|
|
|
/*global Buffer require exports console setTimeout */ |
|
|
|
|
|
|
|
var events = require("events"), |
|
|
|
util = require("../util").util; |
|
|
|
|
|
|
|
exports.debug_mode = false; |
|
|
|
exports.name = "javascript"; |
|
|
|
|
|
|
|
function RedisReplyParser(options) { |
|
|
|
this.name = exports.name; |
|
|
|
this.options = options || {}; |
|
|
|
this.return_buffers = this.options.return_buffers; |
|
|
|
if (this.return_buffers == undefined) this.return_buffers = true; |
|
|
|
this.reset(); |
|
|
|
events.EventEmitter.call(this); |
|
|
|
} |
|
|
@ -12,8 +16,6 @@ function RedisReplyParser(options) { |
|
|
|
util.inherits(RedisReplyParser, events.EventEmitter); |
|
|
|
|
|
|
|
exports.Parser = RedisReplyParser; |
|
|
|
exports.debug_mode = false; |
|
|
|
exports.type = "javascript"; |
|
|
|
|
|
|
|
// Buffer.toString() is quite slow for small strings
|
|
|
|
function small_toString(buf) { |
|
|
@ -39,13 +41,18 @@ RedisReplyParser.prototype.reset = function () { |
|
|
|
this.multi_bulk_nested_replies = null; |
|
|
|
}; |
|
|
|
|
|
|
|
RedisReplyParser.prototype.parser_error = function (message) { |
|
|
|
this.emit("error", message); |
|
|
|
this.reset(); |
|
|
|
}; |
|
|
|
|
|
|
|
RedisReplyParser.prototype.execute = function (incoming_buf) { |
|
|
|
var pos = 0, bd_tmp, bd_str, i, il; |
|
|
|
//, state_times = {}, start_execute = new Date(), start_switch, end_switch, old_state;
|
|
|
|
//start_switch = new Date();
|
|
|
|
|
|
|
|
while (pos < incoming_buf.length) { |
|
|
|
// old_state = this.state;
|
|
|
|
// old_state = this.state;
|
|
|
|
// console.log("execute: " + this.state + ", " + pos + "/" + incoming_buf.length + ", " + String.fromCharCode(incoming_buf[pos]));
|
|
|
|
|
|
|
|
switch (this.state) { |
|
|
@ -137,11 +144,11 @@ RedisReplyParser.prototype.execute = function (incoming_buf) { |
|
|
|
this.send_reply(null); |
|
|
|
this.multi_bulk_length = 0; |
|
|
|
} else if (this.multi_bulk_length === 0) { |
|
|
|
this.multi_bulk_replies = null; |
|
|
|
this.send_reply([]); |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.emit("error", new Error("didn't see LF after NL reading multi bulk count")); |
|
|
|
this.reset(); |
|
|
|
this.parser_error(new Error("didn't see LF after NL reading multi bulk count")); |
|
|
|
return; |
|
|
|
} |
|
|
|
pos += 1; |
|
|
@ -171,13 +178,11 @@ RedisReplyParser.prototype.execute = function (incoming_buf) { |
|
|
|
console.log("Growing return_buffer from " + this.return_buffer.length + " to " + this.bulk_length); |
|
|
|
} |
|
|
|
this.return_buffer = new Buffer(this.bulk_length); |
|
|
|
// home the old one gets cleaned up somehow
|
|
|
|
} |
|
|
|
this.return_buffer.end = 0; |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.emit("error", new Error("didn't see LF after NL while reading bulk length")); |
|
|
|
this.reset(); |
|
|
|
this.parser_error(new Error("didn't see LF after NL while reading bulk length")); |
|
|
|
return; |
|
|
|
} |
|
|
|
pos += 1; |
|
|
@ -186,10 +191,9 @@ RedisReplyParser.prototype.execute = function (incoming_buf) { |
|
|
|
this.return_buffer[this.return_buffer.end] = incoming_buf[pos]; |
|
|
|
this.return_buffer.end += 1; |
|
|
|
pos += 1; |
|
|
|
// TODO - should be faster to use Bufer.copy() here, especially if the response is large.
|
|
|
|
// However, when the response is small, Buffer.copy() seems a lot slower. Computers are hard.
|
|
|
|
if (this.return_buffer.end === this.bulk_length) { |
|
|
|
bd_tmp = new Buffer(this.bulk_length); |
|
|
|
// When the response is small, Buffer.copy() is a lot slower.
|
|
|
|
if (this.bulk_length > 10) { |
|
|
|
this.return_buffer.copy(bd_tmp, 0, 0, this.bulk_length); |
|
|
|
} else { |
|
|
@ -206,8 +210,7 @@ RedisReplyParser.prototype.execute = function (incoming_buf) { |
|
|
|
this.state = "final lf"; |
|
|
|
pos += 1; |
|
|
|
} else { |
|
|
|
this.emit("error", new Error("saw " + incoming_buf[pos] + " when expecting final CR")); |
|
|
|
this.reset(); |
|
|
|
this.parser_error(new Error("saw " + incoming_buf[pos] + " when expecting final CR")); |
|
|
|
return; |
|
|
|
} |
|
|
|
break; |
|
|
@ -216,13 +219,12 @@ RedisReplyParser.prototype.execute = function (incoming_buf) { |
|
|
|
this.state = "type"; |
|
|
|
pos += 1; |
|
|
|
} else { |
|
|
|
this.emit("error", new Error("saw " + incoming_buf[pos] + " when expecting final LF")); |
|
|
|
this.reset(); |
|
|
|
this.parser_error(new Error("saw " + incoming_buf[pos] + " when expecting final LF")); |
|
|
|
return; |
|
|
|
} |
|
|
|
break; |
|
|
|
default: |
|
|
|
throw new Error("invalid state " + this.state); |
|
|
|
this.parser_error(new Error("invalid state " + this.state)); |
|
|
|
} |
|
|
|
// end_switch = new Date();
|
|
|
|
// if (state_times[old_state] === undefined) {
|
|
|
@ -248,14 +250,23 @@ RedisReplyParser.prototype.send_error = function (reply) { |
|
|
|
|
|
|
|
RedisReplyParser.prototype.send_reply = function (reply) { |
|
|
|
if (this.multi_bulk_length > 0 || this.multi_bulk_nested_length > 0) { |
|
|
|
if (!this.return_buffers && Buffer.isBuffer(reply)) { |
|
|
|
this.add_multi_bulk_reply(reply.toString("utf8")); |
|
|
|
if (!this.options.return_buffers && Buffer.isBuffer(reply)) { |
|
|
|
if (reply.end > 10) { |
|
|
|
this.add_multi_bulk_reply(reply.toString()); |
|
|
|
} else { |
|
|
|
this.add_multi_bulk_reply(small_toString(reply)); |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.add_multi_bulk_reply(reply); |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (!this.return_buffers && Buffer.isBuffer(reply)) { |
|
|
|
this.emit("reply", reply.toString("utf8")); |
|
|
|
if (!this.options.return_buffers && Buffer.isBuffer(reply)) { |
|
|
|
console.log("converting buffer to string of len " + reply.end + ", " + util.inspect(reply)); |
|
|
|
if (reply.length > 10) { |
|
|
|
this.emit("reply", reply.toString()); |
|
|
|
} else { |
|
|
|
this.emit("reply", small_toString(reply)); |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.emit("reply", reply); |
|
|
|
} |
|
|
@ -265,7 +276,6 @@ RedisReplyParser.prototype.send_reply = function (reply) { |
|
|
|
RedisReplyParser.prototype.add_multi_bulk_reply = function (reply) { |
|
|
|
if (this.multi_bulk_replies) { |
|
|
|
this.multi_bulk_replies.push(reply); |
|
|
|
// use "less than" here because a nil mb reply claims "0 length", but we need 1 slot to hold it
|
|
|
|
if (this.multi_bulk_replies.length < this.multi_bulk_length) { |
|
|
|
return; |
|
|
|
} |
|
|
@ -288,4 +298,3 @@ RedisReplyParser.prototype.add_multi_bulk_reply = function (reply) { |
|
|
|
this.multi_bulk_replies = null; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|