forked from mirror/ledisdb
add node.js ledis client
This commit is contained in:
parent
47413340e1
commit
ea2e2754ca
|
@ -0,0 +1,77 @@
|
||||||
|
###Ledis - a node.js LedisDB client
|
||||||
|
This is a modification of [simplegeo/nodejs-redis](https://github.com/simplegeo/nodejs-redis) , aiming to be compatible with LedisDB.
|
||||||
|
|
||||||
|
###Setup
|
||||||
|
Just copy (or move) the ledis directory into your project's **node_modules** directory.
|
||||||
|
|
||||||
|
cp -r /path/to/github.com/src/ledisdb/client/nodejs/ledis /path/to/your/node_modules/
|
||||||
|
|
||||||
|
###Example
|
||||||
|
Below is the total content of example.js, including the ledisDB's special commands.
|
||||||
|
|
||||||
|
|
||||||
|
var ledis = require("ledis"),
|
||||||
|
client = ledis.createClient();
|
||||||
|
|
||||||
|
client.on("error", function (err) {
|
||||||
|
console.log("Error " + err);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.set("string key", "string val", ledis.print);
|
||||||
|
client.get("string key", ledis.print);
|
||||||
|
client.hset("hash key", "hashtest 1", "some value", ledis.print);
|
||||||
|
client.hset(["hash key", "hashtest 2", "some other value"], ledis.print);
|
||||||
|
client.hkeys("hash key", function (err, replies) {
|
||||||
|
console.log(replies.length + " replies:");
|
||||||
|
replies.forEach(function (reply, i) {
|
||||||
|
console.log(" " + i + ": " + reply);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//ledis special commands
|
||||||
|
client.lpush("list key", "1", "2", "3", ledis.print);
|
||||||
|
client.lrange("list key", "0", "2", ledis.print);
|
||||||
|
client.lclear("list key", ledis.print);
|
||||||
|
client.lrange("list key", "0", "2", ledis.print);
|
||||||
|
|
||||||
|
client.zadd("zset key", 100, "m", ledis.print);
|
||||||
|
client.zexpire("zset key", 40, ledis.print);
|
||||||
|
client.zttl("zset key", ledis.print);
|
||||||
|
|
||||||
|
client.bsetbit("bit key 1", 1, 1, ledis.print);
|
||||||
|
client.bsetbit("bit key 2", 1, 1, ledis.print);
|
||||||
|
client.bopt("and", "bit key 3", "bit key 1", "bit key 2", ledis.print);
|
||||||
|
client.bget("bit key 3", function(err, result){
|
||||||
|
if (result=="\x02"){
|
||||||
|
console.log("Reply: \\x02")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
client.quit();
|
||||||
|
|
||||||
|
Run the example in your project directory, and will display
|
||||||
|
|
||||||
|
wyk:~/my/project/dir/$ node example.js
|
||||||
|
|
||||||
|
Reply: OK
|
||||||
|
Reply: string val
|
||||||
|
Reply: 0
|
||||||
|
Reply: 0
|
||||||
|
2 replies:
|
||||||
|
0: hashtest 1
|
||||||
|
1: hashtest 2
|
||||||
|
Reply: 3
|
||||||
|
Reply: 3,2,1
|
||||||
|
Reply: 3
|
||||||
|
Reply:
|
||||||
|
Reply: 1
|
||||||
|
Reply: 1
|
||||||
|
Reply: 40
|
||||||
|
Reply: 1
|
||||||
|
Reply: 1
|
||||||
|
Reply: 2
|
||||||
|
Reply: \x02
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
var ledis = require("ledis"),
|
||||||
|
client = ledis.createClient();
|
||||||
|
|
||||||
|
client.on("error", function (err) {
|
||||||
|
console.log("Error " + err);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.set("string key", "string val", ledis.print);
|
||||||
|
client.get("string key", ledis.print);
|
||||||
|
client.hset("hash key", "hashtest 1", "some value", ledis.print);
|
||||||
|
client.hset(["hash key", "hashtest 2", "some other value"], ledis.print);
|
||||||
|
client.hkeys("hash key", function (err, replies) {
|
||||||
|
console.log(replies.length + " replies:");
|
||||||
|
replies.forEach(function (reply, i) {
|
||||||
|
console.log(" " + i + ": " + reply);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//ledis special commands
|
||||||
|
client.lpush("list key", "1", "2", "3", ledis.print);
|
||||||
|
client.lrange("list key", "0", "2", ledis.print);
|
||||||
|
client.lclear("list key", ledis.print);
|
||||||
|
client.lrange("list key", "0", "2", ledis.print);
|
||||||
|
|
||||||
|
client.zadd("zset key", 100, "m", ledis.print);
|
||||||
|
client.zexpire("zset key", 40, ledis.print);
|
||||||
|
client.zttl("zset key", ledis.print);
|
||||||
|
|
||||||
|
client.bsetbit("bit key 1", 1, 1, ledis.print);
|
||||||
|
client.bsetbit("bit key 2", 1, 1, ledis.print);
|
||||||
|
client.bopt("and", "bit key 3", "bit key 1", "bit key 2", ledis.print);
|
||||||
|
client.bget("bit key 3", function(err, result){
|
||||||
|
if (result=="\x02"){
|
||||||
|
console.log("Reply: \\x02")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
client.quit();
|
|
@ -0,0 +1,8 @@
|
||||||
|
examples/
|
||||||
|
benches/
|
||||||
|
test.js
|
||||||
|
diff_multi_bench_output.js
|
||||||
|
generate_commands.js
|
||||||
|
multi_bench.js
|
||||||
|
test-unref.js
|
||||||
|
changelog.md
|
|
@ -0,0 +1,80 @@
|
||||||
|
var net = require('net');
|
||||||
|
|
||||||
|
var proxyPort = 6379;
|
||||||
|
var counter = 0;
|
||||||
|
|
||||||
|
function breaker(conn) {
|
||||||
|
conn.end();
|
||||||
|
conn.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
var server = net.createServer(function(conn) {
|
||||||
|
counter++;
|
||||||
|
var proxyConn = net.createConnection({
|
||||||
|
port: proxyPort
|
||||||
|
});
|
||||||
|
conn.pipe(proxyConn);
|
||||||
|
proxyConn.pipe(conn);
|
||||||
|
proxyConn.on('end', function() {
|
||||||
|
conn.end();
|
||||||
|
});
|
||||||
|
conn.on('end', function() {
|
||||||
|
proxyConn.end();
|
||||||
|
});
|
||||||
|
conn.on('close', function() {
|
||||||
|
proxyConn.end();
|
||||||
|
});
|
||||||
|
proxyConn.on('close', function() {
|
||||||
|
conn.end();
|
||||||
|
});
|
||||||
|
proxyConn.on('error', function() {
|
||||||
|
conn.end();
|
||||||
|
});
|
||||||
|
conn.on('error', function() {
|
||||||
|
proxyConn.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(breaker.bind(null, conn), Math.floor(Math.random() * 2000));
|
||||||
|
});
|
||||||
|
server.listen(6479);
|
||||||
|
|
||||||
|
var redis = require('./');
|
||||||
|
|
||||||
|
var port = 6479;
|
||||||
|
|
||||||
|
var client = redis.createClient(6479, 'localhost');
|
||||||
|
|
||||||
|
function iter() {
|
||||||
|
var k = "k" + Math.floor(Math.random() * 10);
|
||||||
|
var coinflip = Math.random() > 0.5;
|
||||||
|
if (coinflip) {
|
||||||
|
client.set(k, k, function(err, resp) {
|
||||||
|
if (!err && resp !== "OK") {
|
||||||
|
console.log("Unexpected set response " + resp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
client.get(k, function(err, resp) {
|
||||||
|
if (!err) {
|
||||||
|
if (k !== resp) {
|
||||||
|
console.log("Key response mismatch: " + k + " " + resp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function iters() {
|
||||||
|
for (var i = 0; i < 100; ++i) {
|
||||||
|
iter();
|
||||||
|
}
|
||||||
|
setTimeout(iters, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
client.on("connect", function () {
|
||||||
|
iters();
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("error", function (err) {
|
||||||
|
console.log("Client error " + err);
|
||||||
|
});
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,99 @@
|
||||||
|
// This file was generated by ./generate_commands.js on Wed Apr 23 2014 14:51:21 GMT-0700 (PDT)
|
||||||
|
module.exports = [
|
||||||
|
"quit",
|
||||||
|
|
||||||
|
"bget",
|
||||||
|
"bdelete",
|
||||||
|
"bsetbit",
|
||||||
|
"bgetbit",
|
||||||
|
"bmsetbit",
|
||||||
|
"bcount",
|
||||||
|
"bopt",
|
||||||
|
"bexpire",
|
||||||
|
"bexpireat",
|
||||||
|
"bttl",
|
||||||
|
"bpersist",
|
||||||
|
|
||||||
|
|
||||||
|
"hdel",
|
||||||
|
"hexists",
|
||||||
|
"hget",
|
||||||
|
"hgetall",
|
||||||
|
"hincrby",
|
||||||
|
"hkeys",
|
||||||
|
"hlen",
|
||||||
|
"hmget",
|
||||||
|
"hmset",
|
||||||
|
"hset",
|
||||||
|
"hvals",
|
||||||
|
|
||||||
|
|
||||||
|
"hclear",
|
||||||
|
"hmclear",
|
||||||
|
"hexpire",
|
||||||
|
"hexpireat",
|
||||||
|
"httl",
|
||||||
|
"hpersist",
|
||||||
|
|
||||||
|
|
||||||
|
"decr",
|
||||||
|
"decrby",
|
||||||
|
"del",
|
||||||
|
"exists",
|
||||||
|
"get",
|
||||||
|
"getset",
|
||||||
|
"incr",
|
||||||
|
"incrby",
|
||||||
|
"mget",
|
||||||
|
"mset",
|
||||||
|
"set",
|
||||||
|
"setnx",
|
||||||
|
"expire",
|
||||||
|
"expireat",
|
||||||
|
"ttl",
|
||||||
|
"persist",
|
||||||
|
|
||||||
|
"lindex",
|
||||||
|
"llen",
|
||||||
|
"lpop",
|
||||||
|
"lrange",
|
||||||
|
"lpush",
|
||||||
|
"rpop",
|
||||||
|
"rpush",
|
||||||
|
|
||||||
|
|
||||||
|
"lclear",
|
||||||
|
"lmclear",
|
||||||
|
"lexpire",
|
||||||
|
"lexpireat",
|
||||||
|
"lttl",
|
||||||
|
"lpersist",
|
||||||
|
|
||||||
|
"slaveof",
|
||||||
|
"fullsync",
|
||||||
|
"sync",
|
||||||
|
|
||||||
|
|
||||||
|
"zadd",
|
||||||
|
"zcard",
|
||||||
|
"zcount",
|
||||||
|
"zincrby",
|
||||||
|
"zrange",
|
||||||
|
"zrangebyscore",
|
||||||
|
"zrank",
|
||||||
|
"zrem",
|
||||||
|
"zremrangebyrank",
|
||||||
|
"zremrangebyscore",
|
||||||
|
"zrevrange",
|
||||||
|
"zrevrank",
|
||||||
|
"zrevrangebyscore",
|
||||||
|
"zscore",
|
||||||
|
|
||||||
|
|
||||||
|
"zclear",
|
||||||
|
"zmclear",
|
||||||
|
"zexpire",
|
||||||
|
"zexpireat",
|
||||||
|
"zttl",
|
||||||
|
"zpersist",
|
||||||
|
];
|
|
@ -0,0 +1,46 @@
|
||||||
|
var events = require("events"),
|
||||||
|
util = require("../util"),
|
||||||
|
hiredis = require("hiredis");
|
||||||
|
|
||||||
|
exports.debug_mode = false;
|
||||||
|
exports.name = "hiredis";
|
||||||
|
|
||||||
|
function HiredisReplyParser(options) {
|
||||||
|
this.name = exports.name;
|
||||||
|
this.options = options || {};
|
||||||
|
this.reset();
|
||||||
|
events.EventEmitter.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(HiredisReplyParser, events.EventEmitter);
|
||||||
|
|
||||||
|
exports.Parser = HiredisReplyParser;
|
||||||
|
|
||||||
|
HiredisReplyParser.prototype.reset = function () {
|
||||||
|
this.reader = new hiredis.Reader({
|
||||||
|
return_buffers: this.options.return_buffers || false
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
HiredisReplyParser.prototype.execute = function (data) {
|
||||||
|
var reply;
|
||||||
|
this.reader.feed(data);
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
reply = this.reader.get();
|
||||||
|
} catch (err) {
|
||||||
|
this.emit("error", err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply === undefined) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply && reply.constructor === Error) {
|
||||||
|
this.emit("reply error", reply);
|
||||||
|
} else {
|
||||||
|
this.emit("reply", reply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,301 @@
|
||||||
|
var events = require("events"),
|
||||||
|
util = require("../util");
|
||||||
|
|
||||||
|
function Packet(type, size) {
|
||||||
|
this.type = type;
|
||||||
|
this.size = +size;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.name = "javascript";
|
||||||
|
exports.debug_mode = false;
|
||||||
|
|
||||||
|
function ReplyParser(options) {
|
||||||
|
this.name = exports.name;
|
||||||
|
this.options = options || { };
|
||||||
|
|
||||||
|
this._buffer = null;
|
||||||
|
this._offset = 0;
|
||||||
|
this._encoding = "utf-8";
|
||||||
|
this._debug_mode = options.debug_mode;
|
||||||
|
this._reply_type = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(ReplyParser, events.EventEmitter);
|
||||||
|
|
||||||
|
exports.Parser = ReplyParser;
|
||||||
|
|
||||||
|
function IncompleteReadBuffer(message) {
|
||||||
|
this.name = "IncompleteReadBuffer";
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
util.inherits(IncompleteReadBuffer, Error);
|
||||||
|
|
||||||
|
// Buffer.toString() is quite slow for small strings
|
||||||
|
function small_toString(buf, start, end) {
|
||||||
|
var tmp = "", i;
|
||||||
|
|
||||||
|
for (i = start; i < end; i++) {
|
||||||
|
tmp += String.fromCharCode(buf[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplyParser.prototype._parseResult = function (type) {
|
||||||
|
var start, end, offset, packetHeader;
|
||||||
|
|
||||||
|
if (type === 43 || type === 45) { // + or -
|
||||||
|
// up to the delimiter
|
||||||
|
end = this._packetEndOffset() - 1;
|
||||||
|
start = this._offset;
|
||||||
|
|
||||||
|
// include the delimiter
|
||||||
|
this._offset = end + 2;
|
||||||
|
|
||||||
|
if (end > this._buffer.length) {
|
||||||
|
this._offset = start;
|
||||||
|
throw new IncompleteReadBuffer("Wait for more data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.options.return_buffers) {
|
||||||
|
return this._buffer.slice(start, end);
|
||||||
|
} else {
|
||||||
|
if (end - start < 65536) { // completely arbitrary
|
||||||
|
return small_toString(this._buffer, start, end);
|
||||||
|
} else {
|
||||||
|
return this._buffer.toString(this._encoding, start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (type === 58) { // :
|
||||||
|
// up to the delimiter
|
||||||
|
end = this._packetEndOffset() - 1;
|
||||||
|
start = this._offset;
|
||||||
|
|
||||||
|
// include the delimiter
|
||||||
|
this._offset = end + 2;
|
||||||
|
|
||||||
|
if (end > this._buffer.length) {
|
||||||
|
this._offset = start;
|
||||||
|
throw new IncompleteReadBuffer("Wait for more data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.options.return_buffers) {
|
||||||
|
return this._buffer.slice(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the coerced numeric value
|
||||||
|
return +small_toString(this._buffer, start, end);
|
||||||
|
} else if (type === 36) { // $
|
||||||
|
// set a rewind point, as the packet could be larger than the
|
||||||
|
// buffer in memory
|
||||||
|
offset = this._offset - 1;
|
||||||
|
|
||||||
|
packetHeader = new Packet(type, this.parseHeader());
|
||||||
|
|
||||||
|
// packets with a size of -1 are considered null
|
||||||
|
if (packetHeader.size === -1) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
end = this._offset + packetHeader.size;
|
||||||
|
start = this._offset;
|
||||||
|
|
||||||
|
// set the offset to after the delimiter
|
||||||
|
this._offset = end + 2;
|
||||||
|
|
||||||
|
if (end > this._buffer.length) {
|
||||||
|
this._offset = offset;
|
||||||
|
throw new IncompleteReadBuffer("Wait for more data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.options.return_buffers) {
|
||||||
|
return this._buffer.slice(start, end);
|
||||||
|
} else {
|
||||||
|
return this._buffer.toString(this._encoding, start, end);
|
||||||
|
}
|
||||||
|
} else if (type === 42) { // *
|
||||||
|
offset = this._offset;
|
||||||
|
packetHeader = new Packet(type, this.parseHeader());
|
||||||
|
|
||||||
|
if (packetHeader.size < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packetHeader.size > this._bytesRemaining()) {
|
||||||
|
this._offset = offset - 1;
|
||||||
|
throw new IncompleteReadBuffer("Wait for more data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var reply = [ ];
|
||||||
|
var ntype, i, res;
|
||||||
|
|
||||||
|
offset = this._offset - 1;
|
||||||
|
|
||||||
|
for (i = 0; i < packetHeader.size; i++) {
|
||||||
|
ntype = this._buffer[this._offset++];
|
||||||
|
|
||||||
|
if (this._offset > this._buffer.length) {
|
||||||
|
throw new IncompleteReadBuffer("Wait for more data.");
|
||||||
|
}
|
||||||
|
res = this._parseResult(ntype);
|
||||||
|
if (res === undefined) {
|
||||||
|
res = null;
|
||||||
|
}
|
||||||
|
reply.push(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ReplyParser.prototype.execute = function (buffer) {
|
||||||
|
this.append(buffer);
|
||||||
|
|
||||||
|
var type, ret, offset;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
offset = this._offset;
|
||||||
|
try {
|
||||||
|
// at least 4 bytes: :1\r\n
|
||||||
|
if (this._bytesRemaining() < 4) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = this._buffer[this._offset++];
|
||||||
|
|
||||||
|
if (type === 43) { // +
|
||||||
|
ret = this._parseResult(type);
|
||||||
|
|
||||||
|
if (ret === null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.send_reply(ret);
|
||||||
|
} else if (type === 45) { // -
|
||||||
|
ret = this._parseResult(type);
|
||||||
|
|
||||||
|
if (ret === null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.send_error(ret);
|
||||||
|
} else if (type === 58) { // :
|
||||||
|
ret = this._parseResult(type);
|
||||||
|
|
||||||
|
if (ret === null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.send_reply(ret);
|
||||||
|
} else if (type === 36) { // $
|
||||||
|
ret = this._parseResult(type);
|
||||||
|
|
||||||
|
if (ret === null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the state for what is the result of
|
||||||
|
// a -1, set it back up for a null reply
|
||||||
|
if (ret === undefined) {
|
||||||
|
ret = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.send_reply(ret);
|
||||||
|
} else if (type === 42) { // *
|
||||||
|
// set a rewind point. if a failure occurs,
|
||||||
|
// wait for the next execute()/append() and try again
|
||||||
|
offset = this._offset - 1;
|
||||||
|
|
||||||
|
ret = this._parseResult(type);
|
||||||
|
|
||||||
|
this.send_reply(ret);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// catch the error (not enough data), rewind, and wait
|
||||||
|
// for the next packet to appear
|
||||||
|
if (! (err instanceof IncompleteReadBuffer)) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
this._offset = offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ReplyParser.prototype.append = function (newBuffer) {
|
||||||
|
if (!newBuffer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// first run
|
||||||
|
if (this._buffer === null) {
|
||||||
|
this._buffer = newBuffer;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// out of data
|
||||||
|
if (this._offset >= this._buffer.length) {
|
||||||
|
this._buffer = newBuffer;
|
||||||
|
this._offset = 0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// very large packet
|
||||||
|
// check for concat, if we have it, use it
|
||||||
|
if (Buffer.concat !== undefined) {
|
||||||
|
this._buffer = Buffer.concat([this._buffer.slice(this._offset), newBuffer]);
|
||||||
|
} else {
|
||||||
|
var remaining = this._bytesRemaining(),
|
||||||
|
newLength = remaining + newBuffer.length,
|
||||||
|
tmpBuffer = new Buffer(newLength);
|
||||||
|
|
||||||
|
this._buffer.copy(tmpBuffer, 0, this._offset);
|
||||||
|
newBuffer.copy(tmpBuffer, remaining, 0);
|
||||||
|
|
||||||
|
this._buffer = tmpBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._offset = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ReplyParser.prototype.parseHeader = function () {
|
||||||
|
var end = this._packetEndOffset(),
|
||||||
|
value = small_toString(this._buffer, this._offset, end - 1);
|
||||||
|
|
||||||
|
this._offset = end + 1;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
ReplyParser.prototype._packetEndOffset = function () {
|
||||||
|
var offset = this._offset;
|
||||||
|
|
||||||
|
while (this._buffer[offset] !== 0x0d && this._buffer[offset + 1] !== 0x0a) {
|
||||||
|
offset++;
|
||||||
|
|
||||||
|
if (offset >= this._buffer.length) {
|
||||||
|
throw new IncompleteReadBuffer("didn't see LF after NL reading multi bulk count (" + offset + " => " + this._buffer.length + ", " + this._offset + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offset++;
|
||||||
|
return offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
ReplyParser.prototype._bytesRemaining = function () {
|
||||||
|
return (this._buffer.length - this._offset) < 0 ? 0 : (this._buffer.length - this._offset);
|
||||||
|
};
|
||||||
|
|
||||||
|
ReplyParser.prototype.parser_error = function (message) {
|
||||||
|
this.emit("error", message);
|
||||||
|
};
|
||||||
|
|
||||||
|
ReplyParser.prototype.send_error = function (reply) {
|
||||||
|
this.emit("reply error", reply);
|
||||||
|
};
|
||||||
|
|
||||||
|
ReplyParser.prototype.send_reply = function (reply) {
|
||||||
|
this.emit("reply", reply);
|
||||||
|
};
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Queue class adapted from Tim Caswell's pattern library
|
||||||
|
// http://github.com/creationix/pattern/blob/master/lib/pattern/queue.js
|
||||||
|
|
||||||
|
function Queue() {
|
||||||
|
this.tail = [];
|
||||||
|
this.head = [];
|
||||||
|
this.offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Queue.prototype.shift = function () {
|
||||||
|
if (this.offset === this.head.length) {
|
||||||
|
var tmp = this.head;
|
||||||
|
tmp.length = 0;
|
||||||
|
this.head = this.tail;
|
||||||
|
this.tail = tmp;
|
||||||
|
this.offset = 0;
|
||||||
|
if (this.head.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.head[this.offset++]; // sorry, JSLint
|
||||||
|
};
|
||||||
|
|
||||||
|
Queue.prototype.push = function (item) {
|
||||||
|
return this.tail.push(item);
|
||||||
|
};
|
||||||
|
|
||||||
|
Queue.prototype.forEach = function (fn, thisv) {
|
||||||
|
var array = this.head.slice(this.offset), i, il;
|
||||||
|
|
||||||
|
array.push.apply(array, this.tail);
|
||||||
|
|
||||||
|
if (thisv) {
|
||||||
|
for (i = 0, il = array.length; i < il; i += 1) {
|
||||||
|
fn.call(thisv, array[i], i, array);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = 0, il = array.length; i < il; i += 1) {
|
||||||
|
fn(array[i], i, array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
};
|
||||||
|
|
||||||
|
Queue.prototype.getLength = function () {
|
||||||
|
return this.head.length - this.offset + this.tail.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.defineProperty(Queue.prototype, "length", {
|
||||||
|
get: function () {
|
||||||
|
return this.getLength();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof module !== "undefined" && module.exports) {
|
||||||
|
module.exports = Queue;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
function to_array(args) {
|
||||||
|
var len = args.length,
|
||||||
|
arr = new Array(len), i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i += 1) {
|
||||||
|
arr[i] = args[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = to_array;
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Support for very old versions of node where the module was called "sys". At some point, we should abandon this.
|
||||||
|
|
||||||
|
var util;
|
||||||
|
|
||||||
|
try {
|
||||||
|
util = require("util");
|
||||||
|
} catch (err) {
|
||||||
|
util = require("sys");
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = util;
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "ledis",
|
||||||
|
"version": "0.1",
|
||||||
|
"description": "Ledis client library",
|
||||||
|
"keywords": [
|
||||||
|
"ledis",
|
||||||
|
"nosql"
|
||||||
|
],
|
||||||
|
"main": "./index.js",
|
||||||
|
"devDependencies": {
|
||||||
|
"metrics": ">=0.1.5",
|
||||||
|
"colors": "~0.6.0-1",
|
||||||
|
"underscore": "~1.4.4"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue