Full Code of redis/hiredis-node for AI

master daa2eacb4e37 cached
19 files
26.6 KB
7.4k tokens
12 symbols
1 requests
Download .txt
Repository: redis/hiredis-node
Branch: master
Commit: daa2eacb4e37
Files: 19
Total size: 26.6 KB

Directory structure:
gitextract_wx808x3g/

├── .gitignore
├── .gitmodules
├── .travis.yml
├── CHANGELOG.md
├── COPYING
├── Makefile
├── README.md
├── appveyor.yml
├── bench.js
├── binding.gyp
├── deps/
│   └── hiredis.gyp
├── hiredis.js
├── package.json
├── src/
│   ├── hiredis.cc
│   ├── reader.cc
│   └── reader.h
└── test/
    ├── reader.js
    ├── testlib.js
    └── writer.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
/build
.lock-wscript
tmp
node_modules


================================================
FILE: .gitmodules
================================================
[submodule "deps/hiredis"]
	path = deps/hiredis
	url = git://github.com/redis/hiredis.git


================================================
FILE: .travis.yml
================================================
language: node_js
sudo: false
env:
  - CXX=g++-4.8
addons:
  apt:
    sources:
    - ubuntu-toolchain-r-test
    packages:
    - g++-4.8


before_install:
  - node --version | grep -q 'v0.8' && npm install -g npm@2 || true

node_js:
  - "6"
  - "5"
  - "4"
  - "0.12"
  - "0.10"

notifications:
  email: false


================================================
FILE: CHANGELOG.md
================================================
### 0.5.0 (2016-04-xy)

* Dropping support for EOL Node versions.
    * This does not mean it breaks right now, but we're not testing against v0.8 and iojs anymore.
* Do not cast a potentially non-String value to String (#117, iamstolis)
* Upgrade to new nan version (#119, nicolashenry), avoiding deprecation warnings in Node v6

### 0.4.1 (2015-08-22)

* Upgrade to latest nan to be compatible with io.js (Thanks, Benjamin Byholm)

### 0.4.0 (2015-05-25)

* Upgrade to latest nan to be compatible with io.js
* Update license attribute

### 0.3.0 (2015-04-03)

* Update to latest hiredis including basic windows support
* Refactor to use only the parser from hiredis source.

### 0.2.0 (2015-02-08)

* Update to use new hiredis 0.12
* Update nan to latest version to get io.js support for free (thanks @jonathanong)
* Bufferify writeCommand, to support unicode and non-string arguments and make it even faster (thanks @stephank)
* Remove support for Node 0.6


================================================
FILE: COPYING
================================================
Copyright (c) 2010-2012, Pieter Noordhuis
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of Redis nor the names of its contributors may be used to
  endorse or promote products derived from this software without specific prior
  written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: Makefile
================================================
all:
	node-gyp configure build

clean:
	node-gyp clean

temp:
	rm -rf tmp/hiredis
	mkdir -p tmp/hiredis
	cp -r README* COPYING *.js* binding.gyp src deps test tmp/hiredis
	cd tmp/hiredis && rm -rf deps/*/.git* deps/*/*.o deps/*/*.a

package: temp
	cd tmp && tar -czvf hiredis.tgz hiredis

check:
	npm test


================================================
FILE: README.md
================================================
# [Use node-redis](https://github.com/NodeRedis/node_redis)

`hiredis-node` is deprecated, unmaintained and not updated in forever. [Use node-redis](https://github.com/NodeRedis/node_redis).

---

[![Build Status](https://travis-ci.org/redis/hiredis-node.png?branch=master)](https://travis-ci.org/redis/hiredis-node)

# hiredis-node

Node extension that wraps [hiredis][hiredis].
Because Node is already good at doing I/O, hiredis-node only provides
bindings to the protocol parser.
The hiredis protocol parser is faster than JavaScript protocol parsers,
but the speedup only becomes noticeable for large replies.
If you use Redis for simple SET/GET operations, there won't be a big
benefit to using hiredis.
If you use Redis for big SUNION/SINTER/LRANGE/ZRANGE operations, the
benefit to using hiredis-node can be significant.

[hiredis]: http://github.com/redis/hiredis

## Install

Install with [NPM][npm]:

```
npm install hiredis
```

This requires:
* `gcc` / `g++` 4.8 or newer.
* `python` 2.7 or any newer 2.x version. `python` 3.x is not supported.

For running on Travis check the bundled [.travis.yml](.travis.yml).

[npm]: https://npmjs.org/

## Contribute

To work on the code, first fetch the bundled hiredis submodule, then build hiredis and run the tests.

```
git submodule update --init
npm install
npm test
```

## Usage

hiredis-node works out of the box with Matt Ranney's [node_redis][node_redis].
The latter has an optional dependency on hiredis-node, so maybe you're
already using it without knowing.

Alternatively, you can use it directly:

```javascript
var hiredis = require("hiredis"),
    reader = new hiredis.Reader();

// Data comes in
reader.feed("$5\r\nhello\r\n");

// Reply comes out
reader.get() // => "hello"
```

Instead of returning strings for bulk payloads, it can also return
buffers:

```javascript
var hiredis = require("hiredis"),
    reader = new hiredis.Reader({ return_buffers: true });

// Data comes in
reader.feed("$5\r\nhello\r\n");

// Reply comes out
reader.get() // => <Buffer 68 65 6c 6c 6f>
```

[node_redis]: http://github.com/mranney/node_redis

## Windows

Since Version 0.3.0 hiredis-node officially supports Windows.
A simple `npm install hiredis` should just work.
If not, please open a bug report.

There's also a [Windows fork][windows_fork] by Dmitry Gorbunos (@fuwaneko), which should now be unnecessary.

[windows_fork]: https://github.com/fuwaneko/hiredis-node

## License

This code is released under the BSD license, after the license of hiredis.


================================================
FILE: appveyor.yml
================================================
init:
    - git config --global core.autocrlf input

environment:
  matrix:
    - nodejs_version: 6
    - nodejs_version: 5
    - nodejs_version: 4
    - nodejs_version: 0.12
    - nodejs_version: 0.10

platform:
  - x86
  - x64

install:
  - ps: Install-Product node $env:nodejs_version $env:platform
  - git submodule update --init --recursive
  - npm install --msvs_version=2013

build: off

test_script:
  - node --version
  - npm --version
  - "node test/reader.js"
  - "node test/writer.js"


================================================
FILE: bench.js
================================================
var hiredis = require("./hiredis"),
    num_clients = 10,
    active_clients = 0,
    pipeline = 0,
    num_requests = parseInt(process.argv[2]) || 20000,
    issued_requests = 0,
    test_start;

var tests = [];
tests.push({
    descr: "PING",
    command: ["PING"]
});
tests.push({
    descr: "SET",
    command: ["SET", "foo", "bar"]
});
tests.push({
    descr: "GET",
    command: ["GET", "foo"]
});
tests.push({
    descr: "LPUSH 8 bytes",
    command: ["LPUSH", "mylist-8", new Buffer(Array(8).join("-"))]
});
tests.push({
    descr: "LPUSH 64 bytes",
    command: ["LPUSH", "mylist-64", new Buffer(Array(64).join("-"))]
});
tests.push({
    descr: "LPUSH 512 bytes",
    command: ["LPUSH", "mylist-512", new Buffer(Array(512).join("-"))]
});
tests.push({
    descr: "LRANGE 10 elements, 8 bytes",
    command: ["LRANGE", "mylist-8", "0", "9"]
});
tests.push({
    descr: "LRANGE 100 elements, 8 bytes",
    command: ["LRANGE", "mylist-8", "0", "99"]
});
tests.push({
    descr: "LRANGE 100 elements, 64 bytes",
    command: ["LRANGE", "mylist-64", "0", "99"]
});
tests.push({
    descr: "LRANGE 100 elements, 512 bytes",
    command: ["LRANGE", "mylist-512", "0", "99"]
});

function call(client, test) {
    client.on("reply", function() {
        if (issued_requests < num_requests) {
            request();
        } else {
            client.end();
            if (--active_clients == 0)
                done(test);
        }
    });

    function request() {
        issued_requests++;
        client.write.apply(client,test.command);
    };

    request();
}

function done(test) {
    var time = (new Date - test_start);
    var op_rate = (num_requests/(time/1000.0)).toFixed(2);
    console.log(test.descr + ": " + op_rate + " ops/sec");
    next();
}

function concurrent_test(test) {
    var i = num_clients;
    var client;

    issued_requests = 0;
    test_start = new Date;
    while(i-- && issued_requests < num_requests) {
        active_clients++;
        client = hiredis.createConnection();
        call(client, test);
    }
}

function pipelined_test(test) {
    var client = hiredis.createConnection();
    var received_replies = 0;

    issued_requests = 0;
    while (issued_requests < num_requests) {
        issued_requests++;
        client.write.apply(client,test.command);
    }

    test_start = new Date;
    client.on("reply", function() {
        if (++received_replies == num_requests) {
            client.end();
            done(test);
        }
    });
}

function next() {
    var test = tests.shift();
    if (test) {
        if (pipeline) {
            pipelined_test(test);
        } else {
            concurrent_test(test);
        }
    }
}

next();



================================================
FILE: binding.gyp
================================================
{
  'targets': [
    {
      'target_name': 'hiredis',
      'sources': [
          'src/hiredis.cc'
        , 'src/reader.cc'
      ],
      'include_dirs': ["<!(node -e \"require('nan')\")"],
      'dependencies': [
        'deps/hiredis.gyp:hiredis-c'
      ],
      'defines': [
          '_GNU_SOURCE'
      ],
      'cflags': [
          '-Wall',
          '-O3'
      ]
    }
  ]
}


================================================
FILE: deps/hiredis.gyp
================================================
{
  'targets': [
    {
      'target_name': 'hiredis-c',
      'type': 'static_library',
      'direct_dependent_settings': {
        'include_dirs': [ '.' ],
      },
      'sources': [
        './hiredis/sds.c',
        './hiredis/read.c',
      ],
      'conditions': [
        ['OS=="mac"', {
          'xcode_settings': {
            'GCC_C_LANGUAGE_STANDARD': 'c99'
          }
        }],
        ['OS=="solaris"', {
          'cflags+': [ '-std=c99' ]
        }]
      ]
    }
  ]
}


================================================
FILE: hiredis.js
================================================
var net = require("net"),
    hiredis = require('bindings')('hiredis.node');

var bufStar = new Buffer("*", "ascii");
var bufDollar = new Buffer("$", "ascii");
var bufCrlf = new Buffer("\r\n", "ascii");

exports.Reader = hiredis.Reader;

exports.writeCommand = function() {
    var args = arguments,
        bufLen = new Buffer(String(args.length), "ascii"),
        parts = [bufStar, bufLen, bufCrlf],
        size = 3 + bufLen.length;

    for (var i = 0; i < args.length; i++) {
        var arg = args[i];
        if (!Buffer.isBuffer(arg))
            arg = new Buffer(String(arg));

        bufLen = new Buffer(String(arg.length), "ascii");
        parts = parts.concat([
            bufDollar, bufLen, bufCrlf,
            arg, bufCrlf
        ]);
        size += 5 + bufLen.length + arg.length;
    }

    return Buffer.concat(parts, size);
}

exports.createConnection = function(port, host) {
    var s = net.createConnection(port || 6379, host);
    var r = new hiredis.Reader();
    var _write = s.write;

    s.write = function() {
        var data = exports.writeCommand.apply(this, arguments);
        return _write.call(s, data);
    }

    s.on("data", function(data) {
        var reply;
        r.feed(data);
        try {
            while((reply = r.get()) !== undefined)
                s.emit("reply", reply);
        } catch(err) {
            r = null;
            s.emit("error", err);
            s.destroy();
        }
    });

    return s;
}



================================================
FILE: package.json
================================================
{
  "name": "hiredis",
  "description": "Wrapper for reply processing code in hiredis",
  "version": "0.5.0",
  "homepage": "http://github.com/redis/hiredis-node",
  "author": "Jan-Erik Rediger <janerik@fnordig.de>",
  "contributors": [
    "Pieter Noordhuis <pcnoordhuis@gmail.com>"
  ],
  "main": "hiredis",
  "scripts": {
    "test": "node test/reader.js && node test/writer.js"
  },
  "dependencies": {
    "bindings": "^1.2.1",
    "nan": "^2.3.4"
  },
  "engines": {
    "node": ">= 0.10.0"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/redis/hiredis-node.git"
  },
  "bugs": {
    "url": "https://github.com/redis/hiredis-node/issues"
  },
  "license": "BSD-3-Clause"
}


================================================
FILE: src/hiredis.cc
================================================
#include "reader.h"

using namespace v8;

extern "C" {
    static NAN_MODULE_INIT(init) {
        hiredis::Reader::Initialize(target);
    }
    NODE_MODULE(hiredis, init)
}


================================================
FILE: src/reader.cc
================================================
#include <string.h>
#include <assert.h>
#include "reader.h"

using namespace hiredis;

static void *tryParentize(const redisReadTask *task, const Local<Value> &v) {
    Nan::HandleScope scope;

    Reader *r = reinterpret_cast<Reader*>(task->privdata);
    size_t pidx, vidx;

    if (task->parent != NULL) {
        pidx = (size_t)task->parent->obj;
        assert(pidx > 0 && pidx < 9);

        /* When there is a parent, it should be an array. */
        Local<Value> lvalue = Nan::New(r->handle[pidx]);
        assert(lvalue->IsArray());
        Local<Array> larray = lvalue.As<Array>();
        larray->Set(task->idx,v);

        /* Store the handle when this is an inner array. Otherwise, hiredis
         * doesn't care about the return value as long as the value is set in
         * its parent array. */
        vidx = pidx+1;
        if (v->IsArray()) {
            r->handle[vidx].Reset(v);
            return (void*)vidx;
        } else {
            /* Return value doesn't matter for inner value, as long as it is
             * not NULL (which means OOM for hiredis). */
            return (void*)0xcafef00d;
        }
    } else {
        /* There is no parent, so this value is the root object. */
        r->handle[1].Reset(v);
        return (void*)1;
    }
}

static void *createArray(const redisReadTask *task, int size) {
    Nan::HandleScope scope;

    return tryParentize(task, Nan::New<Array>(size));
}

static void *createString(const redisReadTask *task, char *str, size_t len) {
    Nan::HandleScope scope;

    Reader *r = reinterpret_cast<Reader*>(task->privdata);
    Local<Value> v(r->createString(str,len));

    if (task->type == REDIS_REPLY_ERROR)
        v = Exception::Error(v->ToString());
    return tryParentize(task,v);
}

static void *createInteger(const redisReadTask *task, long long value) {
    Nan::HandleScope scope;
    return tryParentize(task, Nan::New<Number>(value));
}

static void *createNil(const redisReadTask *task) {
    Nan::HandleScope scope;
    return tryParentize(task, Nan::Null());
}

static redisReplyObjectFunctions v8ReplyFunctions = {
    createString,
    createArray,
    createInteger,
    createNil,
    0 /* No free function: cleanup is done in Reader::Get. */
};

Reader::Reader(bool return_buffers) :
    return_buffers(return_buffers)
{
    Nan::HandleScope scope;

    reader = redisReaderCreateWithFunctions(&v8ReplyFunctions);
    reader->privdata = this;

#if _USE_CUSTOM_BUFFER_POOL
    if (return_buffers) {
        Local<Object> global = Context::GetCurrent()->Global();
        Local<Value> bv = global->Get(String::NewSymbol("Buffer"));
        assert(bv->IsFunction());
        Local<Function> bf = Local<Function>::Cast(bv);
        buffer_fn = Persistent<Function>::New(bf);

        buffer_pool_length = 8*1024; /* Same as node */
        buffer_pool_offset = 0;

        node::Buffer *b = node::Buffer::New(buffer_pool_length);
        buffer_pool = Persistent<Object>::New(b->handle_);
    }
#endif
}

Reader::~Reader() {
    redisReaderFree(reader);
}

/* Don't declare an extra scope here, so the objects are created within the
 * scope inherited from the caller (Reader::Get) and we don't have to the pay
 * the overhead. */
inline Local<Value> Reader::createString(char *str, size_t len) {
    if (return_buffers) {
#if _USE_CUSTOM_BUFFER_POOL
        if (len > buffer_pool_length) {
            node::Buffer *b = node::Buffer::New(str,len);
            return Local<Value>::New(b->handle_);
        } else {
            return createBufferFromPool(str,len);
        }
#else
        return Nan::CopyBuffer(str,len).ToLocalChecked();
#endif
    } else {
        return Nan::New<String>(str,len).ToLocalChecked();
    }
}

#if _USE_CUSTOM_BUFFER_POOL
Local<Value> Reader::createBufferFromPool(char *str, size_t len) {
    HandleScope scope;
    Local<Value> argv[3];
    Local<Object> instance;

    assert(len <= buffer_pool_length);
    if (buffer_pool_length - buffer_pool_offset < len) {
        node::Buffer *b = node::Buffer::New(buffer_pool_length);
        buffer_pool.Dispose();
        buffer_pool = Persistent<Object>::New(b->handle_);
        buffer_pool_offset = 0;
    }

    memcpy(node::Buffer::Data(buffer_pool)+buffer_pool_offset,str,len);

    argv[0] = Local<Value>::New(buffer_pool);
    argv[1] = Integer::New(len);
    argv[2] = Integer::New(buffer_pool_offset);
    instance = buffer_fn->NewInstance(3,argv);
    buffer_pool_offset += len;
    return scope.Close(instance);
}
#endif

NAN_METHOD(Reader::New) {
    bool return_buffers = false;

    if (info.Length() > 0 && info[0]->IsObject()) {
        Local<Value> bv = Nan::Get(info[0].As<Object>(), Nan::New("return_buffers").ToLocalChecked()).ToLocalChecked();
        if (bv->IsBoolean())
            return_buffers = Nan::To<bool>(bv).FromJust();
    }

    Reader *r = new Reader(return_buffers);
    r->Wrap(info.This());
    info.GetReturnValue().Set(info.This());
}

NAN_MODULE_INIT(Reader::Initialize) {
    Nan::HandleScope scope;

    Local<FunctionTemplate> t = Nan::New<FunctionTemplate>(New);

    t->InstanceTemplate()->SetInternalFieldCount(1);
    Nan::SetPrototypeMethod(t, "feed", Feed);
    Nan::SetPrototypeMethod(t, "get", Get);
    Nan::Set(target, Nan::New("Reader").ToLocalChecked(), Nan::GetFunction(t).ToLocalChecked());
}

NAN_METHOD(Reader::Feed) {
    Reader *r = Nan::ObjectWrap::Unwrap<Reader>(info.This());

    if (info.Length() == 0) {
        Nan::ThrowTypeError("First argument must be a string or buffer");
    } else {
        if (node::Buffer::HasInstance(info[0])) {
            Local<Object> buffer_object = info[0].As<Object>();
            char *data;
            size_t length;

            data = node::Buffer::Data(buffer_object);
            length = node::Buffer::Length(buffer_object);

            /* Can't handle OOM for now. */
            assert(redisReaderFeed(r->reader, data, length) == REDIS_OK);
        } else if (info[0]->IsString()) {
            Nan::Utf8String str(info[0].As<String>());
            redisReplyReaderFeed(r->reader, *str, str.length());
        } else {
            Nan::ThrowError("Invalid argument");
        }
    }

    info.GetReturnValue().Set(info.This());
}

NAN_METHOD(Reader::Get) {
    Reader *r = Nan::ObjectWrap::Unwrap<Reader>(info.This());
    void *index = NULL;
    Local<Value> reply;
    int i;

    if (redisReaderGetReply(r->reader,&index) == REDIS_OK) {
        if (index == 0) {
            return;
        } else {
            /* Complete replies should always have a root object at index 1. */
            assert((size_t)index == 1);
            reply = Nan::New(r->handle[1]);

            /* Dispose and clear used handles. */
            for (i = 1; i < 3; i++) {
                r->handle[i].Reset();
            }
        }
    } else {
        Nan::ThrowError(r->reader->errstr);
    }

    info.GetReturnValue().Set(reply);
}


================================================
FILE: src/reader.h
================================================
#include <nan.h>
#include <hiredis/read.h>

#if NODE_MODULE_VERSION < NODE_0_12_MODULE_VERSION
#define _USE_CUSTOM_BUFFER_POOL 1
#else
#define _USE_CUSTOM_BUFFER_POOL 0
#endif

namespace hiredis {

using namespace v8;

class Reader : public Nan::ObjectWrap {
public:
    Reader(bool);
    ~Reader();

    static NAN_MODULE_INIT(Initialize);
    static NAN_METHOD(New);
    static NAN_METHOD(Feed);
    static NAN_METHOD(Get);

    /* Objects created by the reply object functions need to get back to the
     * reader when the reply is requested via Reader::Get(). Keep temporary
     * objects in this handle. Use an array of handles because replies may
     * include nested multi bulks and child-elements need to be added to the
     * right respective parent. handle[0] will be unused, so the real index of
     * an object in this array can be returned from the reply object functions.
     * The returned value needs to be non-zero to distinguish complete replies
     * from incomplete replies. These are persistent handles because
     * Reader::Get might not return a full reply and the objects need to be
     * kept around for subsequent calls. */
    Nan::Persistent<Value> handle[9];

    /* Helper function to create string/buffer objects. */
    Local<Value> createString(char *str, size_t len);

private:
    redisReader *reader;

    /* Determines whether to return strings or buffers for single line and bulk
     * replies. This defaults to false, so strings are returned by default. */
    bool return_buffers;

#if _USE_CUSTOM_BUFFER_POOL
    Local<Value> createBufferFromPool(char *str, size_t len);
    Persistent<Function> buffer_fn;
    Persistent<Object> buffer_pool;
    size_t buffer_pool_length;
    size_t buffer_pool_offset;
#endif
};

};



================================================
FILE: test/reader.js
================================================
var assert = require("assert"),
    test = require("./testlib")(),
    hiredis = require("../hiredis");

test("CreateReader", function() {
    var reader = new hiredis.Reader();
    assert.notEqual(reader, null);
});

test("StatusReply", function() {
    var reader = new hiredis.Reader();
    reader.feed("+OK\r\n");
    assert.equal("OK", reader.get());
});

test("StatusReplyAsBuffer", function() {
    var reader = new hiredis.Reader({ return_buffers: true });
    reader.feed("+OK\r\n");
    var reply = reader.get();
    assert.ok(Buffer.isBuffer(reply));
    assert.equal("OK", reply.toString());
});

test("IntegerReply", function() {
    var reader = new hiredis.Reader();
    reader.feed(":1\r\n");
    assert.equal(1, reader.get());
});

test("LargeIntegerReply", function() {
    var reader = new hiredis.Reader();
    reader.feed(":9223372036854775807\r\n");
    // We test for a different value here, as JavaScript has no 64-bit integers,
    // only IEEE double precision floating point numbers
    assert.equal("9223372036854776000", String(reader.get()));
});

test("ErrorReply", function() {
    var reader = new hiredis.Reader();
    reader.feed("-ERR foo\r\n");
    var reply = reader.get();
    assert.equal(Error, reply.constructor);
    assert.equal("ERR foo", reply.message);
});

test("ErrorReplyWithReturnBuffers", function() {
    var reader = new hiredis.Reader({ return_buffers: true });
    reader.feed("-ERR foo\r\n");
    var reply = reader.get();
    assert.equal(Error, reply.constructor);
    assert.equal("ERR foo", reply.message);
});

test("NullBulkReply", function() {
    var reader = new hiredis.Reader();
    reader.feed("$-1\r\n");
    assert.equal(null, reader.get());
});

test("EmptyBulkReply", function() {
    var reader = new hiredis.Reader();
    reader.feed("$0\r\n\r\n");
    assert.equal("", reader.get());
});

test("BulkReply", function() {
    var reader = new hiredis.Reader();
    reader.feed("$3\r\nfoo\r\n");
    assert.equal("foo", reader.get());
});

test("BulkReplyAsBuffer", function() {
    var reader = new hiredis.Reader({ return_buffers: true });
    reader.feed("$3\r\nfoo\r\n");
    var reply = reader.get();
    assert.ok(Buffer.isBuffer(reply));
    assert.equal("foo", reply.toString());
});

test("BulkReplyWithEncoding", function() {
    var reader = new hiredis.Reader();
    reader.feed("$" + Buffer.byteLength("☃") + "\r\n☃\r\n");
    assert.equal("☃", reader.get());
});

test("NullMultiBulkReply", function() {
    var reader = new hiredis.Reader();
    reader.feed("*-1\r\n");
    assert.equal(null, reader.get());
});

test("EmptyMultiBulkReply", function() {
    var reader = new hiredis.Reader();
    reader.feed("*0\r\n");
    assert.deepEqual([], reader.get());
});

test("MultiBulkReply", function() {
    var reader = new hiredis.Reader();
    reader.feed("*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n");
    assert.deepEqual(["foo", "bar"], reader.get());
});

test("NestedMultiBulkReply", function() {
    var reader = new hiredis.Reader();
    reader.feed("*2\r\n*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$3\r\nqux\r\n");
    assert.deepEqual([["foo", "bar"], "qux"], reader.get());
});

test("DeeplyNestedMultiBulkReply", function() {
    var i;
    var reader = new hiredis.Reader();
    var expected = 1;

    for (i = 0; i < 8; i++) {
      reader.feed("*1\r\n");
      expected = [expected];
    }

    reader.feed(":1\r\n");

    assert.deepEqual(reader.get(), expected);
});

test("TooDeeplyNestedMultiBulkReply", function() {
    var i;
    var reader = new hiredis.Reader();

    for (i = 0; i < 9; i++) {
      reader.feed("*1\r\n");
    }

    reader.feed(":1\r\n");

    assert.throws(
      function() {
        reader.get();
      },
      /nested multi/
    );
});

test("MultiBulkReplyWithNonStringValues", function() {
    var reader = new hiredis.Reader();
    reader.feed("*3\r\n:1\r\n+OK\r\n$-1\r\n");
    assert.deepEqual([1, "OK", null], reader.get());
});

test("FeedWithBuffer", function() {
    var reader = new hiredis.Reader();
    reader.feed(new Buffer("$3\r\nfoo\r\n"));
    assert.deepEqual("foo", reader.get());
});

test("UndefinedReplyOnIncompleteFeed", function() {
    var reader = new hiredis.Reader();
    reader.feed("$3\r\nfoo");
    assert.deepEqual(undefined, reader.get());
    reader.feed("\r\n");
    assert.deepEqual("foo", reader.get());
});

test("Leaks", function() {
    /* The "leaks" utility is only available on OSX. */
    if (process.platform != "darwin") return;

    var done = 0;
    var leaks = require('child_process').spawn("leaks", [process.pid]);
    leaks.stdout.on("data", function(data) {
        var str = data.toString();
        var notice = "Node 0.2.5 always leaks 16 bytes (this is " + process.versions.node + ")";
        var matches;
        if ((matches = /(\d+) leaks?/i.exec(str)) != null) {
            if (parseInt(matches[1]) > 0) {
                console.log(str);
                console.log('\x1B[31mNotice: ' + notice + '\x1B[0m');
            }
        }
        done = 1;
    });

    process.on('exit', function() {
        assert.ok(done, "Leaks test should have completed");
    });
});


================================================
FILE: test/testlib.js
================================================
module.exports = function() {
    function test(str, fn) {
        try {
            fn();
            test.passed++;
        } catch (err) {
            console.log("\x1B[1;31m" + str + " failed!\x1B[0m");
            console.log(err.stack + "\n");
            test.failed++;
        }
    }

    test.passed = 0;
    test.failed = 0;

    return test;
}


================================================
FILE: test/writer.js
================================================
var assert = require("assert"),
    test = require("./testlib")(),
    hiredis = require("../hiredis");

test("WriteCommand", function() {
    var reader = new hiredis.Reader();
    reader.feed(hiredis.writeCommand("hello", "world"));
    assert.deepEqual(["hello", "world"], reader.get());
});

test("WriteUnicode", function() {
    var reader = new hiredis.Reader();
    reader.feed(hiredis.writeCommand("béép"));
    assert.deepEqual(["béép"], reader.get());
});

test("WriteBuffer", function() {
    var reader = new hiredis.Reader({ return_buffers: true });
    reader.feed(hiredis.writeCommand(new Buffer([0xC3, 0x28])));
    var command = reader.get();
    assert.equal(0xC3, command[0][0]);
    assert.equal(0x28, command[0][1]);
});

test("WriteNumber", function() {
    var reader = new hiredis.Reader();
    reader.feed(hiredis.writeCommand(3));
    assert.deepEqual(["3"], reader.get());
});
Download .txt
gitextract_wx808x3g/

├── .gitignore
├── .gitmodules
├── .travis.yml
├── CHANGELOG.md
├── COPYING
├── Makefile
├── README.md
├── appveyor.yml
├── bench.js
├── binding.gyp
├── deps/
│   └── hiredis.gyp
├── hiredis.js
├── package.json
├── src/
│   ├── hiredis.cc
│   ├── reader.cc
│   └── reader.h
└── test/
    ├── reader.js
    ├── testlib.js
    └── writer.js
Download .txt
SYMBOL INDEX (12 symbols across 5 files)

FILE: bench.js
  function call (line 51) | function call(client, test) {
  function done (line 70) | function done(test) {
  function concurrent_test (line 77) | function concurrent_test(test) {
  function pipelined_test (line 90) | function pipelined_test(test) {
  function next (line 109) | function next() {

FILE: src/hiredis.cc
  function NAN_MODULE_INIT (line 6) | static NAN_MODULE_INIT(init) {

FILE: src/reader.cc
  function NAN_METHOD (line 151) | NAN_METHOD(Reader::New) {
  function NAN_MODULE_INIT (line 165) | NAN_MODULE_INIT(Reader::Initialize) {
  function NAN_METHOD (line 176) | NAN_METHOD(Reader::Feed) {
  function NAN_METHOD (line 203) | NAN_METHOD(Reader::Get) {

FILE: src/reader.h
  function namespace (line 10) | namespace hiredis {

FILE: test/testlib.js
  function test (line 2) | function test(str, fn) {
Condensed preview — 19 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (30K chars).
[
  {
    "path": ".gitignore",
    "chars": 38,
    "preview": "/build\n.lock-wscript\ntmp\nnode_modules\n"
  },
  {
    "path": ".gitmodules",
    "chars": 90,
    "preview": "[submodule \"deps/hiredis\"]\n\tpath = deps/hiredis\n\turl = git://github.com/redis/hiredis.git\n"
  },
  {
    "path": ".travis.yml",
    "chars": 310,
    "preview": "language: node_js\nsudo: false\nenv:\n  - CXX=g++-4.8\naddons:\n  apt:\n    sources:\n    - ubuntu-toolchain-r-test\n    package"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 960,
    "preview": "### 0.5.0 (2016-04-xy)\n\n* Dropping support for EOL Node versions.\n    * This does not mean it breaks right now, but we'r"
  },
  {
    "path": "COPYING",
    "chars": 1483,
    "preview": "Copyright (c) 2010-2012, Pieter Noordhuis\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with "
  },
  {
    "path": "Makefile",
    "chars": 306,
    "preview": "all:\n\tnode-gyp configure build\n\nclean:\n\tnode-gyp clean\n\ntemp:\n\trm -rf tmp/hiredis\n\tmkdir -p tmp/hiredis\n\tcp -r README* C"
  },
  {
    "path": "README.md",
    "chars": 2518,
    "preview": "# [Use node-redis](https://github.com/NodeRedis/node_redis)\n\n`hiredis-node` is deprecated, unmaintained and not updated "
  },
  {
    "path": "appveyor.yml",
    "chars": 497,
    "preview": "init:\n    - git config --global core.autocrlf input\n\nenvironment:\n  matrix:\n    - nodejs_version: 6\n    - nodejs_version"
  },
  {
    "path": "bench.js",
    "chars": 2701,
    "preview": "var hiredis = require(\"./hiredis\"),\n    num_clients = 10,\n    active_clients = 0,\n    pipeline = 0,\n    num_requests = p"
  },
  {
    "path": "binding.gyp",
    "chars": 389,
    "preview": "{\n  'targets': [\n    {\n      'target_name': 'hiredis',\n      'sources': [\n          'src/hiredis.cc'\n        , 'src/read"
  },
  {
    "path": "deps/hiredis.gyp",
    "chars": 491,
    "preview": "{\n  'targets': [\n    {\n      'target_name': 'hiredis-c',\n      'type': 'static_library',\n      'direct_dependent_setting"
  },
  {
    "path": "hiredis.js",
    "chars": 1471,
    "preview": "var net = require(\"net\"),\n    hiredis = require('bindings')('hiredis.node');\n\nvar bufStar = new Buffer(\"*\", \"ascii\");\nva"
  },
  {
    "path": "package.json",
    "chars": 704,
    "preview": "{\n  \"name\": \"hiredis\",\n  \"description\": \"Wrapper for reply processing code in hiredis\",\n  \"version\": \"0.5.0\",\n  \"homepag"
  },
  {
    "path": "src/hiredis.cc",
    "chars": 174,
    "preview": "#include \"reader.h\"\n\nusing namespace v8;\n\nextern \"C\" {\n    static NAN_MODULE_INIT(init) {\n        hiredis::Reader::Initi"
  },
  {
    "path": "src/reader.cc",
    "chars": 6912,
    "preview": "#include <string.h>\n#include <assert.h>\n#include \"reader.h\"\n\nusing namespace hiredis;\n\nstatic void *tryParentize(const r"
  },
  {
    "path": "src/reader.h",
    "chars": 1771,
    "preview": "#include <nan.h>\n#include <hiredis/read.h>\n\n#if NODE_MODULE_VERSION < NODE_0_12_MODULE_VERSION\n#define _USE_CUSTOM_BUFFE"
  },
  {
    "path": "test/reader.js",
    "chars": 5146,
    "preview": "var assert = require(\"assert\"),\n    test = require(\"./testlib\")(),\n    hiredis = require(\"../hiredis\");\n\ntest(\"CreateRea"
  },
  {
    "path": "test/testlib.js",
    "chars": 356,
    "preview": "module.exports = function() {\n    function test(str, fn) {\n        try {\n            fn();\n            test.passed++;\n  "
  },
  {
    "path": "test/writer.js",
    "chars": 904,
    "preview": "var assert = require(\"assert\"),\n    test = require(\"./testlib\")(),\n    hiredis = require(\"../hiredis\");\n\ntest(\"WriteComm"
  }
]

About this extraction

This page contains the full source code of the redis/hiredis-node GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 19 files (26.6 KB), approximately 7.4k tokens, and a symbol index with 12 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!