aboutsummaryrefslogtreecommitdiffstats
path: root/signaling-server/node_modules/socket.io/node_modules/redis
diff options
context:
space:
mode:
Diffstat (limited to 'signaling-server/node_modules/socket.io/node_modules/redis')
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/.npmignore1
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/README.md691
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/benches/buffer_bench.js89
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/benches/hiredis_parser.js38
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/benches/re_sub_test.js14
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/benches/reconnect_test.js29
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/codec.js16
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/pubsub/pub.js38
-rwxr-xr-xsignaling-server/node_modules/socket.io/node_modules/redis/benches/stress/pubsub/run10
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/pubsub/server.js23
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/rpushblpop/pub.js49
-rwxr-xr-xsignaling-server/node_modules/socket.io/node_modules/redis/benches/stress/rpushblpop/run6
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/rpushblpop/server.js30
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/0013
-rwxr-xr-xsignaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/plot13
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/size-rate.pngbin0 -> 6672 bytes
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/speed.js84
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/benches/sub_quit_test.js18
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/changelog.md219
-rwxr-xr-xsignaling-server/node_modules/socket.io/node_modules/redis/diff_multi_bench_output.js87
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/auth.js5
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/backpressure_drain.js33
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/eval.js9
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/extend.js24
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/file.js32
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/mget.js5
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/monitor.js10
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/multi.js46
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/multi2.js29
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/psubscribe.js33
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/pub_sub.js41
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/simple.js24
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/sort.js17
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/subqueries.js15
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/subquery.js19
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/unix_socket.js29
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/examples/web_server.js31
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/generate_commands.js39
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/index.js1113
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/lib/commands.js147
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/lib/parser/hiredis.js46
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js317
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/lib/queue.js61
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/lib/to_array.js12
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/lib/util.js11
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/mem.js11
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/multi_bench.js225
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/package.json48
-rw-r--r--signaling-server/node_modules/socket.io/node_modules/redis/test.js1618
49 files changed, 5518 insertions, 0 deletions
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/.npmignore b/signaling-server/node_modules/socket.io/node_modules/redis/.npmignore
new file mode 100644
index 0000000..3c3629e
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/.npmignore
@@ -0,0 +1 @@
+node_modules
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/README.md b/signaling-server/node_modules/socket.io/node_modules/redis/README.md
new file mode 100644
index 0000000..46e7018
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/README.md
@@ -0,0 +1,691 @@
+redis - a node.js redis client
+===========================
+
+This is a complete Redis client for node.js. It supports all Redis commands, including many recently added commands like EVAL from
+experimental Redis server branches.
+
+
+Install with:
+
+ npm install redis
+
+Pieter Noordhuis has provided a binding to the official `hiredis` C library, which is non-blocking and fast. To use `hiredis`, do:
+
+ npm install hiredis redis
+
+If `hiredis` is installed, `node_redis` will use it by default. Otherwise, a pure JavaScript parser will be used.
+
+If you use `hiredis`, be sure to rebuild it whenever you upgrade your version of node. There are mysterious failures that can
+happen between node and native code modules after a node upgrade.
+
+
+## Usage
+
+Simple example, included as `examples/simple.js`:
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient();
+
+ // if you'd like to select database 3, instead of 0 (default), call
+ // client.select(3, function() { /* ... */ });
+
+ client.on("error", function (err) {
+ console.log("Error " + err);
+ });
+
+ client.set("string key", "string val", redis.print);
+ client.hset("hash key", "hashtest 1", "some value", redis.print);
+ client.hset(["hash key", "hashtest 2", "some other value"], redis.print);
+ client.hkeys("hash key", function (err, replies) {
+ console.log(replies.length + " replies:");
+ replies.forEach(function (reply, i) {
+ console.log(" " + i + ": " + reply);
+ });
+ client.quit();
+ });
+```
+
+This will display:
+
+ mjr:~/work/node_redis (master)$ node example.js
+ Reply: OK
+ Reply: 0
+ Reply: 0
+ 2 replies:
+ 0: hashtest 1
+ 1: hashtest 2
+ mjr:~/work/node_redis (master)$
+
+
+## Performance
+
+Here are typical results of `multi_bench.js` which is similar to `redis-benchmark` from the Redis distribution.
+It uses 50 concurrent connections with no pipelining.
+
+JavaScript parser:
+
+ PING: 20000 ops 42283.30 ops/sec 0/5/1.182
+ SET: 20000 ops 32948.93 ops/sec 1/7/1.515
+ GET: 20000 ops 28694.40 ops/sec 0/9/1.740
+ INCR: 20000 ops 39370.08 ops/sec 0/8/1.269
+ LPUSH: 20000 ops 36429.87 ops/sec 0/8/1.370
+ LRANGE (10 elements): 20000 ops 9891.20 ops/sec 1/9/5.048
+ LRANGE (100 elements): 20000 ops 1384.56 ops/sec 10/91/36.072
+
+hiredis parser:
+
+ PING: 20000 ops 46189.38 ops/sec 1/4/1.082
+ SET: 20000 ops 41237.11 ops/sec 0/6/1.210
+ GET: 20000 ops 39682.54 ops/sec 1/7/1.257
+ INCR: 20000 ops 40080.16 ops/sec 0/8/1.242
+ LPUSH: 20000 ops 41152.26 ops/sec 0/3/1.212
+ LRANGE (10 elements): 20000 ops 36563.07 ops/sec 1/8/1.363
+ LRANGE (100 elements): 20000 ops 21834.06 ops/sec 0/9/2.287
+
+The performance of `node_redis` improves dramatically with pipelining, which happens automatically in most normal programs.
+
+
+### Sending Commands
+
+Each Redis command is exposed as a function on the `client` object.
+All functions take either an `args` Array plus optional `callback` Function or
+a variable number of individual arguments followed by an optional callback.
+Here is an example of passing an array of arguments and a callback:
+
+ client.mset(["test keys 1", "test val 1", "test keys 2", "test val 2"], function (err, res) {});
+
+Here is that same call in the second style:
+
+ client.mset("test keys 1", "test val 1", "test keys 2", "test val 2", function (err, res) {});
+
+Note that in either form the `callback` is optional:
+
+ client.set("some key", "some val");
+ client.set(["some other key", "some val"]);
+
+If the key is missing, reply will be null (probably):
+
+ client.get("missingkey", function(err, reply) {
+ // reply is null when the key is missing
+ console.log(reply);
+ });
+
+For a list of Redis commands, see [Redis Command Reference](http://redis.io/commands)
+
+The commands can be specified in uppercase or lowercase for convenience. `client.get()` is the same as `client.GET()`.
+
+Minimal parsing is done on the replies. Commands that return a single line reply return JavaScript Strings,
+integer replies return JavaScript Numbers, "bulk" replies return node Buffers, and "multi bulk" replies return a
+JavaScript Array of node Buffers. `HGETALL` returns an Object with Buffers keyed by the hash keys.
+
+# API
+
+## Connection Events
+
+`client` will emit some events about the state of the connection to the Redis server.
+
+### "ready"
+
+`client` will emit `ready` a connection is established to the Redis server and the server reports
+that it is ready to receive commands. Commands issued before the `ready` event are queued,
+then replayed just before this event is emitted.
+
+### "connect"
+
+`client` will emit `connect` at the same time as it emits `ready` unless `client.options.no_ready_check`
+is set. If this options is set, `connect` will be emitted when the stream is connected, and then
+you are free to try to send commands.
+
+### "error"
+
+`client` will emit `error` when encountering an error connecting to the Redis server.
+
+Note that "error" is a special event type in node. If there are no listeners for an
+"error" event, node will exit. This is usually what you want, but it can lead to some
+cryptic error messages like this:
+
+ mjr:~/work/node_redis (master)$ node example.js
+
+ node.js:50
+ throw e;
+ ^
+ Error: ECONNREFUSED, Connection refused
+ at IOWatcher.callback (net:870:22)
+ at node.js:607:9
+
+Not very useful in diagnosing the problem, but if your program isn't ready to handle this,
+it is probably the right thing to just exit.
+
+`client` will also emit `error` if an exception is thrown inside of `node_redis` for whatever reason.
+It would be nice to distinguish these two cases.
+
+### "end"
+
+`client` will emit `end` when an established Redis server connection has closed.
+
+### "drain"
+
+`client` will emit `drain` when the TCP connection to the Redis server has been buffering, but is now
+writable. This event can be used to stream commands in to Redis and adapt to backpressure. Right now,
+you need to check `client.command_queue.length` to decide when to reduce your send rate. Then you can
+resume sending when you get `drain`.
+
+### "idle"
+
+`client` will emit `idle` when there are no outstanding commands that are awaiting a response.
+
+## redis.createClient(port, host, options)
+
+Create a new client connection. `port` defaults to `6379` and `host` defaults
+to `127.0.0.1`. If you have `redis-server` running on the same computer as node, then the defaults for
+port and host are probably fine. `options` in an object with the following possible properties:
+
+* `parser`: which Redis protocol reply parser to use. Defaults to `hiredis` if that module is installed.
+This may also be set to `javascript`.
+* `return_buffers`: defaults to `false`. If set to `true`, then all replies will be sent to callbacks as node Buffer
+objects instead of JavaScript Strings.
+* `detect_buffers`: default to `false`. If set to `true`, then replies will be sent to callbacks as node Buffer objects
+if any of the input arguments to the original command were Buffer objects.
+This option lets you switch between Buffers and Strings on a per-command basis, whereas `return_buffers` applies to
+every command on a client.
+* `socket_nodelay`: defaults to `true`. Whether to call setNoDelay() on the TCP stream, which disables the
+Nagle algorithm on the underlying socket. Setting this option to `false` can result in additional throughput at the
+cost of more latency. Most applications will want this set to `true`.
+* `no_ready_check`: defaults to `false`. When a connection is established to the Redis server, the server might still
+be loading the database from disk. While loading, the server not respond to any commands. To work around this,
+`node_redis` has a "ready check" which sends the `INFO` command to the server. The response from the `INFO` command
+indicates whether the server is ready for more commands. When ready, `node_redis` emits a `ready` event.
+Setting `no_ready_check` to `true` will inhibit this check.
+* `enable_offline_queue`: defaults to `true`. By default, if there is no active
+connection to the redis server, commands are added to a queue and are executed
+once the connection has been established. Setting `enable_offline_queue` to
+`false` will disable this feature and the callback will be execute immediately
+with an error, or an error will be thrown if no callback is specified.
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient(null, null, {detect_buffers: true});
+
+ client.set("foo_rand000000000000", "OK");
+
+ // This will return a JavaScript String
+ client.get("foo_rand000000000000", function (err, reply) {
+ console.log(reply.toString()); // Will print `OK`
+ });
+
+ // This will return a Buffer since original key is specified as a Buffer
+ client.get(new Buffer("foo_rand000000000000"), function (err, reply) {
+ console.log(reply.toString()); // Will print `<Buffer 4f 4b>`
+ });
+ client.end();
+```
+
+`createClient()` returns a `RedisClient` object that is named `client` in all of the examples here.
+
+## client.auth(password, callback)
+
+When connecting to Redis servers that require authentication, the `AUTH` command must be sent as the
+first command after connecting. This can be tricky to coordinate with reconnections, the ready check,
+etc. To make this easier, `client.auth()` stashes `password` and will send it after each connection,
+including reconnections. `callback` is invoked only once, after the response to the very first
+`AUTH` command sent.
+NOTE: Your call to `client.auth()` should not be inside the ready handler. If
+you are doing this wrong, `client` will emit an error that looks
+something like this `Error: Ready check failed: ERR operation not permitted`.
+
+## client.end()
+
+Forcibly close the connection to the Redis server. Note that this does not wait until all replies have been parsed.
+If you want to exit cleanly, call `client.quit()` to send the `QUIT` command after you have handled all replies.
+
+This example closes the connection to the Redis server before the replies have been read. You probably don't
+want to do this:
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient();
+
+ client.set("foo_rand000000000000", "some fantastic value");
+ client.get("foo_rand000000000000", function (err, reply) {
+ console.log(reply.toString());
+ });
+ client.end();
+```
+
+`client.end()` is useful for timeout cases where something is stuck or taking too long and you want
+to start over.
+
+## Friendlier hash commands
+
+Most Redis commands take a single String or an Array of Strings as arguments, and replies are sent back as a single String or an Array of Strings.
+When dealing with hash values, there are a couple of useful exceptions to this.
+
+### client.hgetall(hash)
+
+The reply from an HGETALL command will be converted into a JavaScript Object by `node_redis`. That way you can interact
+with the responses using JavaScript syntax.
+
+Example:
+
+ client.hmset("hosts", "mjr", "1", "another", "23", "home", "1234");
+ client.hgetall("hosts", function (err, obj) {
+ console.dir(obj);
+ });
+
+Output:
+
+ { mjr: '1', another: '23', home: '1234' }
+
+### client.hmset(hash, obj, [callback])
+
+Multiple values in a hash can be set by supplying an object:
+
+ client.HMSET(key2, {
+ "0123456789": "abcdefghij", // NOTE: the key and value must both be strings
+ "some manner of key": "a type of value"
+ });
+
+The properties and values of this Object will be set as keys and values in the Redis hash.
+
+### client.hmset(hash, key1, val1, ... keyn, valn, [callback])
+
+Multiple values may also be set by supplying a list:
+
+ client.HMSET(key1, "0123456789", "abcdefghij", "some manner of key", "a type of value");
+
+
+## Publish / Subscribe
+
+Here is a simple example of the API for publish / subscribe. This program opens two
+client connections, subscribes to a channel on one of them, and publishes to that
+channel on the other:
+
+```js
+ var redis = require("redis"),
+ client1 = redis.createClient(), client2 = redis.createClient(),
+ msg_count = 0;
+
+ client1.on("subscribe", function (channel, count) {
+ client2.publish("a nice channel", "I am sending a message.");
+ client2.publish("a nice channel", "I am sending a second message.");
+ client2.publish("a nice channel", "I am sending my last message.");
+ });
+
+ client1.on("message", function (channel, message) {
+ console.log("client1 channel " + channel + ": " + message);
+ msg_count += 1;
+ if (msg_count === 3) {
+ client1.unsubscribe();
+ client1.end();
+ client2.end();
+ }
+ });
+
+ client1.incr("did a thing");
+ client1.subscribe("a nice channel");
+```
+
+When a client issues a `SUBSCRIBE` or `PSUBSCRIBE`, that connection is put into "pub/sub" mode.
+At that point, only commands that modify the subscription set are valid. When the subscription
+set is empty, the connection is put back into regular mode.
+
+If you need to send regular commands to Redis while in pub/sub mode, just open another connection.
+
+## Pub / Sub Events
+
+If a client has subscriptions active, it may emit these events:
+
+### "message" (channel, message)
+
+Client will emit `message` for every message received that matches an active subscription.
+Listeners are passed the channel name as `channel` and the message Buffer as `message`.
+
+### "pmessage" (pattern, channel, message)
+
+Client will emit `pmessage` for every message received that matches an active subscription pattern.
+Listeners are passed the original pattern used with `PSUBSCRIBE` as `pattern`, the sending channel
+name as `channel`, and the message Buffer as `message`.
+
+### "subscribe" (channel, count)
+
+Client will emit `subscribe` in response to a `SUBSCRIBE` command. Listeners are passed the
+channel name as `channel` and the new count of subscriptions for this client as `count`.
+
+### "psubscribe" (pattern, count)
+
+Client will emit `psubscribe` in response to a `PSUBSCRIBE` command. Listeners are passed the
+original pattern as `pattern`, and the new count of subscriptions for this client as `count`.
+
+### "unsubscribe" (channel, count)
+
+Client will emit `unsubscribe` in response to a `UNSUBSCRIBE` command. Listeners are passed the
+channel name as `channel` and the new count of subscriptions for this client as `count`. When
+`count` is 0, this client has left pub/sub mode and no more pub/sub events will be emitted.
+
+### "punsubscribe" (pattern, count)
+
+Client will emit `punsubscribe` in response to a `PUNSUBSCRIBE` command. Listeners are passed the
+channel name as `channel` and the new count of subscriptions for this client as `count`. When
+`count` is 0, this client has left pub/sub mode and no more pub/sub events will be emitted.
+
+## client.multi([commands])
+
+`MULTI` commands are queued up until an `EXEC` is issued, and then all commands are run atomically by
+Redis. The interface in `node_redis` is to return an individual `Multi` object by calling `client.multi()`.
+
+```js
+ var redis = require("./index"),
+ client = redis.createClient(), set_size = 20;
+
+ client.sadd("bigset", "a member");
+ client.sadd("bigset", "another member");
+
+ while (set_size > 0) {
+ client.sadd("bigset", "member " + set_size);
+ set_size -= 1;
+ }
+
+ // multi chain with an individual callback
+ client.multi()
+ .scard("bigset")
+ .smembers("bigset")
+ .keys("*", function (err, replies) {
+ // NOTE: code in this callback is NOT atomic
+ // this only happens after the the .exec call finishes.
+ client.mget(replies, redis.print);
+ })
+ .dbsize()
+ .exec(function (err, replies) {
+ console.log("MULTI got " + replies.length + " replies");
+ replies.forEach(function (reply, index) {
+ console.log("Reply " + index + ": " + reply.toString());
+ });
+ });
+```
+
+`client.multi()` is a constructor that returns a `Multi` object. `Multi` objects share all of the
+same command methods as `client` objects do. Commands are queued up inside the `Multi` object
+until `Multi.exec()` is invoked.
+
+You can either chain together `MULTI` commands as in the above example, or you can queue individual
+commands while still sending regular client command as in this example:
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient(), multi;
+
+ // start a separate multi command queue
+ multi = client.multi();
+ multi.incr("incr thing", redis.print);
+ multi.incr("incr other thing", redis.print);
+
+ // runs immediately
+ client.mset("incr thing", 100, "incr other thing", 1, redis.print);
+
+ // drains multi queue and runs atomically
+ multi.exec(function (err, replies) {
+ console.log(replies); // 101, 2
+ });
+
+ // you can re-run the same transaction if you like
+ multi.exec(function (err, replies) {
+ console.log(replies); // 102, 3
+ client.quit();
+ });
+```
+
+In addition to adding commands to the `MULTI` queue individually, you can also pass an array
+of commands and arguments to the constructor:
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient(), multi;
+
+ client.multi([
+ ["mget", "multifoo", "multibar", redis.print],
+ ["incr", "multifoo"],
+ ["incr", "multibar"]
+ ]).exec(function (err, replies) {
+ console.log(replies);
+ });
+```
+
+
+## Monitor mode
+
+Redis supports the `MONITOR` command, which lets you see all commands received by the Redis server
+across all client connections, including from other client libraries and other computers.
+
+After you send the `MONITOR` command, no other commands are valid on that connection. `node_redis`
+will emit a `monitor` event for every new monitor message that comes across. The callback for the
+`monitor` event takes a timestamp from the Redis server and an array of command arguments.
+
+Here is a simple example:
+
+```js
+ var client = require("redis").createClient(),
+ util = require("util");
+
+ client.monitor(function (err, res) {
+ console.log("Entering monitoring mode.");
+ });
+
+ client.on("monitor", function (time, args) {
+ console.log(time + ": " + util.inspect(args));
+ });
+```
+
+# Extras
+
+Some other things you might like to know about.
+
+## client.server_info
+
+After the ready probe completes, the results from the INFO command are saved in the `client.server_info`
+object.
+
+The `versions` key contains an array of the elements of the version string for easy comparison.
+
+ > client.server_info.redis_version
+ '2.3.0'
+ > client.server_info.versions
+ [ 2, 3, 0 ]
+
+## redis.print()
+
+A handy callback function for displaying return values when testing. Example:
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient();
+
+ client.on("connect", function () {
+ client.set("foo_rand000000000000", "some fantastic value", redis.print);
+ client.get("foo_rand000000000000", redis.print);
+ });
+```
+
+This will print:
+
+ Reply: OK
+ Reply: some fantastic value
+
+Note that this program will not exit cleanly because the client is still connected.
+
+## redis.debug_mode
+
+Boolean to enable debug mode and protocol tracing.
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient();
+
+ redis.debug_mode = true;
+
+ client.on("connect", function () {
+ client.set("foo_rand000000000000", "some fantastic value");
+ });
+```
+
+This will display:
+
+ mjr:~/work/node_redis (master)$ node ~/example.js
+ send command: *3
+ $3
+ SET
+ $20
+ foo_rand000000000000
+ $20
+ some fantastic value
+
+ on_data: +OK
+
+`send command` is data sent into Redis and `on_data` is data received from Redis.
+
+## client.send_command(command_name, args, callback)
+
+Used internally to send commands to Redis. For convenience, nearly all commands that are published on the Redis
+Wiki have been added to the `client` object. However, if I missed any, or if new commands are introduced before
+this library is updated, you can use `send_command()` to send arbitrary commands to Redis.
+
+All commands are sent as multi-bulk commands. `args` can either be an Array of arguments, or omitted.
+
+## client.connected
+
+Boolean tracking the state of the connection to the Redis server.
+
+## client.command_queue.length
+
+The number of commands that have been sent to the Redis server but not yet replied to. You can use this to
+enforce some kind of maximum queue depth for commands while connected.
+
+Don't mess with `client.command_queue` though unless you really know what you are doing.
+
+## client.offline_queue.length
+
+The number of commands that have been queued up for a future connection. You can use this to enforce
+some kind of maximum queue depth for pre-connection commands.
+
+## client.retry_delay
+
+Current delay in milliseconds before a connection retry will be attempted. This starts at `250`.
+
+## client.retry_backoff
+
+Multiplier for future retry timeouts. This should be larger than 1 to add more time between retries.
+Defaults to 1.7. The default initial connection retry is 250, so the second retry will be 425, followed by 723.5, etc.
+
+### Commands with Optional and Keyword arguments
+
+This applies to anything that uses an optional `[WITHSCORES]` or `[LIMIT offset count]` in the [redis.io/commands](http://redis.io/commands) documentation.
+
+Example:
+```js
+var args = [ 'myzset', 1, 'one', 2, 'two', 3, 'three', 99, 'ninety-nine' ];
+client.zadd(args, function (err, response) {
+ if (err) throw err;
+ console.log('added '+response+' items.');
+
+ // -Infinity and +Infinity also work
+ var args1 = [ 'myzset', '+inf', '-inf' ];
+ client.zrevrangebyscore(args1, function (err, response) {
+ if (err) throw err;
+ console.log('example1', response);
+ // write your code here
+ });
+
+ var max = 3, min = 1, offset = 1, count = 2;
+ var args2 = [ 'myzset', max, min, 'WITHSCORES', 'LIMIT', offset, count ];
+ client.zrevrangebyscore(args2, function (err, response) {
+ if (err) throw err;
+ console.log('example2', response);
+ // write your code here
+ });
+});
+```
+
+## TODO
+
+Better tests for auth, disconnect/reconnect, and all combinations thereof.
+
+Stream large set/get values into and out of Redis. Otherwise the entire value must be in node's memory.
+
+Performance can be better for very large values.
+
+I think there are more performance improvements left in there for smaller values, especially for large lists of small values.
+
+## How to Contribute
+- open a pull request and then wait for feedback (if
+ [DTrejo](http://github.com/dtrejo) does not get back to you within 2 days,
+ comment again with indignation!)
+
+## Contributors
+Some people have have added features and fixed bugs in `node_redis` other than me.
+
+Ordered by date of first contribution.
+[Auto-generated](http://github.com/dtrejo/node-authors) on Wed Jul 25 2012 19:14:59 GMT-0700 (PDT).
+
+- [Matt Ranney aka `mranney`](https://github.com/mranney)
+- [Tim-Smart aka `tim-smart`](https://github.com/tim-smart)
+- [Tj Holowaychuk aka `visionmedia`](https://github.com/visionmedia)
+- [rick aka `technoweenie`](https://github.com/technoweenie)
+- [Orion Henry aka `orionz`](https://github.com/orionz)
+- [Aivo Paas aka `aivopaas`](https://github.com/aivopaas)
+- [Hank Sims aka `hanksims`](https://github.com/hanksims)
+- [Paul Carey aka `paulcarey`](https://github.com/paulcarey)
+- [Pieter Noordhuis aka `pietern`](https://github.com/pietern)
+- [nithesh aka `nithesh`](https://github.com/nithesh)
+- [Andy Ray aka `andy2ray`](https://github.com/andy2ray)
+- [unknown aka `unknowdna`](https://github.com/unknowdna)
+- [Dave Hoover aka `redsquirrel`](https://github.com/redsquirrel)
+- [Vladimir Dronnikov aka `dvv`](https://github.com/dvv)
+- [Umair Siddique aka `umairsiddique`](https://github.com/umairsiddique)
+- [Louis-Philippe Perron aka `lp`](https://github.com/lp)
+- [Mark Dawson aka `markdaws`](https://github.com/markdaws)
+- [Ian Babrou aka `bobrik`](https://github.com/bobrik)
+- [Felix Geisendörfer aka `felixge`](https://github.com/felixge)
+- [Jean-Hugues Pinson aka `undefined`](https://github.com/undefined)
+- [Maksim Lin aka `maks`](https://github.com/maks)
+- [Owen Smith aka `orls`](https://github.com/orls)
+- [Zachary Scott aka `zzak`](https://github.com/zzak)
+- [TEHEK Firefox aka `TEHEK`](https://github.com/TEHEK)
+- [Isaac Z. Schlueter aka `isaacs`](https://github.com/isaacs)
+- [David Trejo aka `DTrejo`](https://github.com/DTrejo)
+- [Brian Noguchi aka `bnoguchi`](https://github.com/bnoguchi)
+- [Philip Tellis aka `bluesmoon`](https://github.com/bluesmoon)
+- [Marcus Westin aka `marcuswestin2`](https://github.com/marcuswestin2)
+- [Jed Schmidt aka `jed`](https://github.com/jed)
+- [Dave Peticolas aka `jdavisp3`](https://github.com/jdavisp3)
+- [Trae Robrock aka `trobrock`](https://github.com/trobrock)
+- [Shankar Karuppiah aka `shankar0306`](https://github.com/shankar0306)
+- [Ignacio Burgueño aka `ignacio`](https://github.com/ignacio)
+
+Thanks.
+
+## LICENSE - "MIT License"
+
+Copyright (c) 2010 Matthew Ranney, http://ranney.com/
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+![spacer](http://ranney.com/1px.gif)
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/buffer_bench.js b/signaling-server/node_modules/socket.io/node_modules/redis/benches/buffer_bench.js
new file mode 100644
index 0000000..a504fbc
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/buffer_bench.js
@@ -0,0 +1,89 @@
+var source = new Buffer(100),
+ dest = new Buffer(100), i, j, k, tmp, count = 1000000, bytes = 100;
+
+for (i = 99 ; i >= 0 ; i--) {
+ source[i] = 120;
+}
+
+var str = "This is a nice String.",
+ buf = new Buffer("This is a lovely Buffer.");
+
+var start = new Date();
+for (i = count * 100; i > 0 ; i--) {
+ if (Buffer.isBuffer(str)) {}
+}
+var end = new Date();
+console.log("Buffer.isBuffer(str) " + (end - start) + " ms");
+
+var start = new Date();
+for (i = count * 100; i > 0 ; i--) {
+ if (Buffer.isBuffer(buf)) {}
+}
+var end = new Date();
+console.log("Buffer.isBuffer(buf) " + (end - start) + " ms");
+
+var start = new Date();
+for (i = count * 100; i > 0 ; i--) {
+ if (str instanceof Buffer) {}
+}
+var end = new Date();
+console.log("str instanceof Buffer " + (end - start) + " ms");
+
+var start = new Date();
+for (i = count * 100; i > 0 ; i--) {
+ if (buf instanceof Buffer) {}
+}
+var end = new Date();
+console.log("buf instanceof Buffer " + (end - start) + " ms");
+
+for (i = bytes ; i > 0 ; i --) {
+ var start = new Date();
+ for (j = count ; j > 0; j--) {
+ tmp = source.toString("ascii", 0, bytes);
+ }
+ var end = new Date();
+ console.log("toString() " + i + " bytes " + (end - start) + " ms");
+}
+
+for (i = bytes ; i > 0 ; i --) {
+ var start = new Date();
+ for (j = count ; j > 0; j--) {
+ tmp = "";
+ for (k = 0; k <= i ; k++) {
+ tmp += String.fromCharCode(source[k]);
+ }
+ }
+ var end = new Date();
+ console.log("manual string " + i + " bytes " + (end - start) + " ms");
+}
+
+for (i = bytes ; i > 0 ; i--) {
+ var start = new Date();
+ for (j = count ; j > 0 ; j--) {
+ for (k = i ; k > 0 ; k--) {
+ dest[k] = source[k];
+ }
+ }
+ var end = new Date();
+ console.log("Manual copy " + i + " bytes " + (end - start) + " ms");
+}
+
+for (i = bytes ; i > 0 ; i--) {
+ var start = new Date();
+ for (j = count ; j > 0 ; j--) {
+ for (k = i ; k > 0 ; k--) {
+ dest[k] = 120;
+ }
+ }
+ var end = new Date();
+ console.log("Direct assignment " + i + " bytes " + (end - start) + " ms");
+}
+
+for (i = bytes ; i > 0 ; i--) {
+ var start = new Date();
+ for (j = count ; j > 0 ; j--) {
+ source.copy(dest, 0, 0, i);
+ }
+ var end = new Date();
+ console.log("Buffer.copy() " + i + " bytes " + (end - start) + " ms");
+}
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/hiredis_parser.js b/signaling-server/node_modules/socket.io/node_modules/redis/benches/hiredis_parser.js
new file mode 100644
index 0000000..f1515b1
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/hiredis_parser.js
@@ -0,0 +1,38 @@
+var Parser = require('../lib/parser/hiredis').Parser;
+var assert = require('assert');
+
+/*
+This test makes sure that exceptions thrown inside of "reply" event handlers
+are not trapped and mistakenly emitted as parse errors.
+*/
+(function testExecuteDoesNotCatchReplyCallbackExceptions() {
+ var parser = new Parser();
+ var replies = [{}];
+
+ parser.reader = {
+ feed: function() {},
+ get: function() {
+ return replies.shift();
+ }
+ };
+
+ var emittedError = false;
+ var caughtException = false;
+
+ parser
+ .on('error', function() {
+ emittedError = true;
+ })
+ .on('reply', function() {
+ throw new Error('bad');
+ });
+
+ try {
+ parser.execute();
+ } catch (err) {
+ caughtException = true;
+ }
+
+ assert.equal(caughtException, true);
+ assert.equal(emittedError, false);
+})();
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/re_sub_test.js b/signaling-server/node_modules/socket.io/node_modules/redis/benches/re_sub_test.js
new file mode 100644
index 0000000..64b8f31
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/re_sub_test.js
@@ -0,0 +1,14 @@
+var client = require('../index').createClient()
+ , client2 = require('../index').createClient()
+ , assert = require('assert');
+
+client.once('subscribe', function (channel, count) {
+ client.unsubscribe('x');
+ client.subscribe('x', function () {
+ client.quit();
+ client2.quit();
+ });
+ client2.publish('x', 'hi');
+});
+
+client.subscribe('x');
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/reconnect_test.js b/signaling-server/node_modules/socket.io/node_modules/redis/benches/reconnect_test.js
new file mode 100644
index 0000000..7abdd51
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/reconnect_test.js
@@ -0,0 +1,29 @@
+var redis = require("../index").createClient(null, null, {
+// max_attempts: 4
+});
+
+redis.on("error", function (err) {
+ console.log("Redis says: " + err);
+});
+
+redis.on("ready", function () {
+ console.log("Redis ready.");
+});
+
+redis.on("reconnecting", function (arg) {
+ console.log("Redis reconnecting: " + JSON.stringify(arg));
+});
+redis.on("connect", function () {
+ console.log("Redis connected.");
+});
+
+setInterval(function () {
+ var now = Date.now();
+ redis.set("now", now, function (err, res) {
+ if (err) {
+ console.log(now + " Redis reply error: " + err);
+ } else {
+ console.log(now + " Redis reply: " + res);
+ }
+ });
+}, 100);
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/codec.js b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/codec.js
new file mode 100644
index 0000000..7d764f6
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/codec.js
@@ -0,0 +1,16 @@
+var json = {
+ encode: JSON.stringify,
+ decode: JSON.parse
+};
+
+var MsgPack = require('node-msgpack');
+msgpack = {
+ encode: MsgPack.pack,
+ decode: function(str) { return MsgPack.unpack(new Buffer(str)); }
+};
+
+bison = require('bison');
+
+module.exports = json;
+//module.exports = msgpack;
+//module.exports = bison;
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/pubsub/pub.js b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/pubsub/pub.js
new file mode 100644
index 0000000..0acde7a
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/pubsub/pub.js
@@ -0,0 +1,38 @@
+'use strict';
+
+var freemem = require('os').freemem;
+var profiler = require('v8-profiler');
+var codec = require('../codec');
+
+var sent = 0;
+
+var pub = require('redis').createClient(null, null, {
+ //command_queue_high_water: 5,
+ //command_queue_low_water: 1
+})
+.on('ready', function() {
+ this.emit('drain');
+})
+.on('drain', function() {
+ process.nextTick(exec);
+});
+
+var payload = '1'; for (var i = 0; i < 12; ++i) payload += payload;
+console.log('Message payload length', payload.length);
+
+function exec() {
+ pub.publish('timeline', codec.encode({ foo: payload }));
+ ++sent;
+ if (!pub.should_buffer) {
+ process.nextTick(exec);
+ }
+}
+
+profiler.takeSnapshot('s_0');
+
+exec();
+
+setInterval(function() {
+ profiler.takeSnapshot('s_' + sent);
+ console.error('sent', sent, 'free', freemem(), 'cmdqlen', pub.command_queue.length, 'offqlen', pub.offline_queue.length);
+}, 2000);
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/pubsub/run b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/pubsub/run
new file mode 100755
index 0000000..bd9ac39
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/pubsub/run
@@ -0,0 +1,10 @@
+#!/bin/sh
+node server.js &
+node server.js &
+node server.js &
+node server.js &
+node server.js &
+node server.js &
+node server.js &
+node server.js &
+node --debug pub.js
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/pubsub/server.js b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/pubsub/server.js
new file mode 100644
index 0000000..035e6b7
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/pubsub/server.js
@@ -0,0 +1,23 @@
+'use strict';
+
+var freemem = require('os').freemem;
+var codec = require('../codec');
+
+var id = Math.random();
+var recv = 0;
+
+var sub = require('redis').createClient()
+ .on('ready', function() {
+ this.subscribe('timeline');
+ })
+ .on('message', function(channel, message) {
+ var self = this;
+ if (message) {
+ message = codec.decode(message);
+ ++recv;
+ }
+ });
+
+setInterval(function() {
+ console.error('id', id, 'received', recv, 'free', freemem());
+}, 2000);
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/rpushblpop/pub.js b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/rpushblpop/pub.js
new file mode 100644
index 0000000..9caf1d0
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/rpushblpop/pub.js
@@ -0,0 +1,49 @@
+'use strict';
+
+var freemem = require('os').freemem;
+//var profiler = require('v8-profiler');
+var codec = require('../codec');
+
+var sent = 0;
+
+var pub = require('redis').createClient(null, null, {
+ //command_queue_high_water: 5,
+ //command_queue_low_water: 1
+})
+.on('ready', function() {
+ this.del('timeline');
+ this.emit('drain');
+})
+.on('drain', function() {
+ process.nextTick(exec);
+});
+
+var payload = '1'; for (var i = 0; i < 12; ++i) payload += payload;
+console.log('Message payload length', payload.length);
+
+function exec() {
+ pub.rpush('timeline', codec.encode({ foo: payload }));
+ ++sent;
+ if (!pub.should_buffer) {
+ process.nextTick(exec);
+ }
+}
+
+//profiler.takeSnapshot('s_0');
+
+exec();
+
+setInterval(function() {
+ //var ss = profiler.takeSnapshot('s_' + sent);
+ //console.error(ss.stringify());
+ pub.llen('timeline', function(err, result) {
+ console.error('sent', sent, 'free', freemem(),
+ 'cmdqlen', pub.command_queue.length, 'offqlen', pub.offline_queue.length,
+ 'llen', result
+ );
+ });
+}, 2000);
+
+/*setTimeout(function() {
+ process.exit();
+}, 30000);*/
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/rpushblpop/run b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/rpushblpop/run
new file mode 100755
index 0000000..8045ae8
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/rpushblpop/run
@@ -0,0 +1,6 @@
+#!/bin/sh
+node server.js &
+#node server.js &
+#node server.js &
+#node server.js &
+node --debug pub.js
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/rpushblpop/server.js b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/rpushblpop/server.js
new file mode 100644
index 0000000..9cbcdd9
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/rpushblpop/server.js
@@ -0,0 +1,30 @@
+'use strict';
+
+var freemem = require('os').freemem;
+var codec = require('../codec');
+
+var id = Math.random();
+var recv = 0;
+
+var cmd = require('redis').createClient();
+var sub = require('redis').createClient()
+ .on('ready', function() {
+ this.emit('timeline');
+ })
+ .on('timeline', function() {
+ var self = this;
+ this.blpop('timeline', 0, function(err, result) {
+ var message = result[1];
+ if (message) {
+ message = codec.decode(message);
+ ++recv;
+ }
+ self.emit('timeline');
+ });
+ });
+
+setInterval(function() {
+ cmd.llen('timeline', function(err, result) {
+ console.error('id', id, 'received', recv, 'free', freemem(), 'llen', result);
+ });
+}, 2000);
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/00 b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/00
new file mode 100644
index 0000000..29d7bf7
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/00
@@ -0,0 +1,13 @@
+# size JSON msgpack bison
+26602 2151.0170848180414
+25542 ? 2842.589272665782
+24835 ? ? 7280.4538397469805
+6104 6985.234528557929
+5045 ? 7217.461392841478
+4341 ? ? 14261.406335354604
+4180 15864.633685636572
+4143 ? 12954.806235781925
+4141 ? ? 44650.70733912719
+75 114227.07313350472
+40 ? 30162.440062810834
+39 ? ? 119815.66013519121
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/plot b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/plot
new file mode 100755
index 0000000..2563797
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/plot
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+gnuplot >size-rate.jpg << _EOF_
+
+set terminal png nocrop enhanced font verdana 12 size 640,480
+set logscale x
+set logscale y
+set grid
+set xlabel 'Serialized object size, octets'
+set ylabel 'decode(encode(obj)) rate, 1/sec'
+plot '00' using 1:2 title 'json' smooth bezier, '00' using 1:3 title 'msgpack' smooth bezier, '00' using 1:4 title 'bison' smooth bezier
+
+_EOF_
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/size-rate.png b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/size-rate.png
new file mode 100644
index 0000000..c9c2bee
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/size-rate.png
Binary files differ
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/speed.js b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/speed.js
new file mode 100644
index 0000000..8e43cbc
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/stress/speed/speed.js
@@ -0,0 +1,84 @@
+var msgpack = require('node-msgpack');
+var bison = require('bison');
+var codec = {
+ JSON: {
+ encode: JSON.stringify,
+ decode: JSON.parse
+ },
+ msgpack: {
+ encode: msgpack.pack,
+ decode: msgpack.unpack
+ },
+ bison: bison
+};
+
+var obj, l;
+
+var s = '0';
+for (var i = 0; i < 12; ++i) s += s;
+
+obj = {
+ foo: s,
+ arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333],
+ rand: [],
+ a: s,
+ ccc: s,
+ b: s + s + s
+};
+for (i = 0; i < 100; ++i) obj.rand.push(Math.random());
+forObj(obj);
+
+obj = {
+ foo: s,
+ arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333],
+ rand: []
+};
+for (i = 0; i < 100; ++i) obj.rand.push(Math.random());
+forObj(obj);
+
+obj = {
+ foo: s,
+ arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333],
+ rand: []
+};
+forObj(obj);
+
+obj = {
+ arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333],
+ rand: []
+};
+forObj(obj);
+
+function run(obj, codec) {
+ var t1 = Date.now();
+ var n = 10000;
+ for (var i = 0; i < n; ++i) {
+ codec.decode(l = codec.encode(obj));
+ }
+ var t2 = Date.now();
+ //console.log('DONE', n*1000/(t2-t1), 'codecs/sec, length=', l.length);
+ return [n*1000/(t2-t1), l.length];
+}
+
+function series(obj, cname, n) {
+ var rate = 0;
+ var len = 0;
+ for (var i = 0; i < n; ++i) {
+ var r = run(obj, codec[cname]);
+ rate += r[0];
+ len += r[1];
+ }
+ rate /= n;
+ len /= n;
+ console.log(cname + ' ' + rate + ' ' + len);
+ return [rate, len];
+}
+
+function forObj(obj) {
+ var r = {
+ JSON: series(obj, 'JSON', 20),
+ msgpack: series(obj, 'msgpack', 20),
+ bison: series(obj, 'bison', 20)
+ };
+ return r;
+}
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/benches/sub_quit_test.js b/signaling-server/node_modules/socket.io/node_modules/redis/benches/sub_quit_test.js
new file mode 100644
index 0000000..ad1f413
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/benches/sub_quit_test.js
@@ -0,0 +1,18 @@
+var client = require("redis").createClient(),
+ client2 = require("redis").createClient();
+
+client.subscribe("something");
+client.on("subscribe", function (channel, count) {
+ console.log("Got sub: " + channel);
+ client.unsubscribe("something");
+});
+
+client.on("unsubscribe", function (channel, count) {
+ console.log("Got unsub: " + channel + ", quitting");
+ client.quit();
+});
+
+// exercise unsub before sub
+client2.unsubscribe("something");
+client2.subscribe("another thing");
+client2.quit();
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/changelog.md b/signaling-server/node_modules/socket.io/node_modules/redis/changelog.md
new file mode 100644
index 0000000..4248288
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/changelog.md
@@ -0,0 +1,219 @@
+Changelog
+=========
+
+## v0.7.2 - April 29, 2012
+
+Many contributed fixes. Thank you, contributors.
+
+* [GH-190] - pub/sub mode fix (Brian Noguchi)
+* [GH-165] - parser selection fix (TEHEK)
+* numerous documentation and examples updates
+* auth errors emit Errors instead of Strings (David Trejo)
+
+## v0.7.1 - November 15, 2011
+
+Fix regression in reconnect logic.
+
+Very much need automated tests for reconnection and queue logic.
+
+## v0.7.0 - November 14, 2011
+
+Many contributed fixes. Thanks everybody.
+
+* [GH-127] - properly re-initialize parser on reconnect
+* [GH-136] - handle passing undefined as callback (Ian Babrou)
+* [GH-139] - properly handle exceptions thrown in pub/sub event handlers (Felix Geisendörfer)
+* [GH-141] - detect closing state on stream error (Felix Geisendörfer)
+* [GH-142] - re-select database on reconnection (Jean-Hugues Pinson)
+* [GH-146] - add sort example (Maksim Lin)
+
+Some more goodies:
+
+* Fix bugs with node 0.6
+* Performance improvements
+* New version of `multi_bench.js` that tests more realistic scenarios
+* [GH-140] - support optional callback for subscribe commands
+* Properly flush and error out command queue when connection fails
+* Initial work on reconnection thresholds
+
+## v0.6.7 - July 30, 2011
+
+(accidentally skipped v0.6.6)
+
+Fix and test for [GH-123]
+
+Passing an Array as as the last argument should expand as users
+expect. The old behavior was to coerce the arguments into Strings,
+which did surprising things with Arrays.
+
+## v0.6.5 - July 6, 2011
+
+Contributed changes:
+
+* Support SlowBuffers (Umair Siddique)
+* Add Multi to exports (Louis-Philippe Perron)
+* Fix for drain event calculation (Vladimir Dronnikov)
+
+Thanks!
+
+## v0.6.4 - June 30, 2011
+
+Fix bug with optional callbacks for hmset.
+
+## v0.6.2 - June 30, 2011
+
+Bugs fixed:
+
+* authentication retry while server is loading db (danmaz74) [GH-101]
+* command arguments processing issue with arrays
+
+New features:
+
+* Auto update of new commands from redis.io (Dave Hoover)
+* Performance improvements and backpressure controls.
+* Commands now return the true/false value from the underlying socket write(s).
+* Implement command_queue high water and low water for more better control of queueing.
+
+See `examples/backpressure_drain.js` for more information.
+
+## v0.6.1 - June 29, 2011
+
+Add support and tests for Redis scripting through EXEC command.
+
+Bug fix for monitor mode. (forddg)
+
+Auto update of new commands from redis.io (Dave Hoover)
+
+## v0.6.0 - April 21, 2011
+
+Lots of bugs fixed.
+
+* connection error did not properly trigger reconnection logic [GH-85]
+* client.hmget(key, [val1, val2]) was not expanding properly [GH-66]
+* client.quit() while in pub/sub mode would throw an error [GH-87]
+* client.multi(['hmset', 'key', {foo: 'bar'}]) fails [GH-92]
+* unsubscribe before subscribe would make things very confused [GH-88]
+* Add BRPOPLPUSH [GH-79]
+
+## v0.5.11 - April 7, 2011
+
+Added DISCARD
+
+I originally didn't think DISCARD would do anything here because of the clever MULTI interface, but somebody
+pointed out to me that DISCARD can be used to flush the WATCH set.
+
+## v0.5.10 - April 6, 2011
+
+Added HVALS
+
+## v0.5.9 - March 14, 2011
+
+Fix bug with empty Array arguments - Andy Ray
+
+## v0.5.8 - March 14, 2011
+
+Add `MONITOR` command and special monitor command reply parsing.
+
+## v0.5.7 - February 27, 2011
+
+Add magical auth command.
+
+Authentication is now remembered by the client and will be automatically sent to the server
+on every connection, including any reconnections.
+
+## v0.5.6 - February 22, 2011
+
+Fix bug in ready check with `return_buffers` set to `true`.
+
+Thanks to Dean Mao and Austin Chau.
+
+## v0.5.5 - February 16, 2011
+
+Add probe for server readiness.
+
+When a Redis server starts up, it might take a while to load the dataset into memory.
+During this time, the server will accept connections, but will return errors for all non-INFO
+commands. Now node_redis will send an INFO command whenever it connects to a server.
+If the info command indicates that the server is not ready, the client will keep trying until
+the server is ready. Once it is ready, the client will emit a "ready" event as well as the
+"connect" event. The client will queue up all commands sent before the server is ready, just
+like it did before. When the server is ready, all offline/non-ready commands will be replayed.
+This should be backward compatible with previous versions.
+
+To disable this ready check behavior, set `options.no_ready_check` when creating the client.
+
+As a side effect of this change, the key/val params from the info command are available as
+`client.server_options`. Further, the version string is decomposed into individual elements
+in `client.server_options.versions`.
+
+## v0.5.4 - February 11, 2011
+
+Fix excess memory consumption from Queue backing store.
+
+Thanks to Gustaf Sjöberg.
+
+## v0.5.3 - February 5, 2011
+
+Fix multi/exec error reply callback logic.
+
+Thanks to Stella Laurenzo.
+
+## v0.5.2 - January 18, 2011
+
+Fix bug where unhandled error replies confuse the parser.
+
+## v0.5.1 - January 18, 2011
+
+Fix bug where subscribe commands would not handle redis-server startup error properly.
+
+## v0.5.0 - December 29, 2010
+
+Some bug fixes:
+
+* An important bug fix in reconnection logic. Previously, reply callbacks would be invoked twice after
+ a reconnect.
+* Changed error callback argument to be an actual Error object.
+
+New feature:
+
+* Add friendly syntax for HMSET using an object.
+
+## v0.4.1 - December 8, 2010
+
+Remove warning about missing hiredis. You probably do want it though.
+
+## v0.4.0 - December 5, 2010
+
+Support for multiple response parsers and hiredis C library from Pieter Noordhuis.
+Return Strings instead of Buffers by default.
+Empty nested mb reply bug fix.
+
+## v0.3.9 - November 30, 2010
+
+Fix parser bug on failed EXECs.
+
+## v0.3.8 - November 10, 2010
+
+Fix for null MULTI response when WATCH condition fails.
+
+## v0.3.7 - November 9, 2010
+
+Add "drain" and "idle" events.
+
+## v0.3.6 - November 3, 2010
+
+Add all known Redis commands from Redis master, even ones that are coming in 2.2 and beyond.
+
+Send a friendlier "error" event message on stream errors like connection refused / reset.
+
+## v0.3.5 - October 21, 2010
+
+A few bug fixes.
+
+* Fixed bug with `nil` multi-bulk reply lengths that showed up with `BLPOP` timeouts.
+* Only emit `end` once when connection goes away.
+* Fixed bug in `test.js` where driver finished before all tests completed.
+
+## unversioned wasteland
+
+See the git history for what happened before.
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/diff_multi_bench_output.js b/signaling-server/node_modules/socket.io/node_modules/redis/diff_multi_bench_output.js
new file mode 100755
index 0000000..99fdf4d
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/diff_multi_bench_output.js
@@ -0,0 +1,87 @@
+#!/usr/bin/env node
+
+var colors = require('colors'),
+ fs = require('fs'),
+ _ = require('underscore'),
+ metrics = require('metrics'),
+
+ // `node diff_multi_bench_output.js before.txt after.txt`
+ before = process.argv[2],
+ after = process.argv[3];
+
+if (!before || !after) {
+ console.log('Please supply two file arguments:');
+ var n = __filename;
+ n = n.substring(n.lastIndexOf('/', n.length));
+ console.log(' ./' + n + ' multiBenchBefore.txt multiBenchAfter.txt');
+ console.log('To generate multiBenchBefore.txt, run');
+ console.log(' node multi_bench.js > multiBenchBefore.txt');
+ console.log('Thank you for benchmarking responsibly.');
+ return;
+}
+
+var before_lines = fs.readFileSync(before, 'utf8').split('\n'),
+ after_lines = fs.readFileSync(after, 'utf8').split('\n');
+
+console.log('Comparing before,', before.green, '(', before_lines.length,
+ 'lines)', 'to after,', after.green, '(', after_lines.length, 'lines)');
+
+var total_ops = new metrics.Histogram.createUniformHistogram();
+
+before_lines.forEach(function(b, i) {
+ var a = after_lines[i];
+ if (!a || !b || !b.trim() || !a.trim()) {
+ // console.log('#ignored#', '>'+a+'<', '>'+b+'<');
+ return;
+ }
+
+ b_words = b.split(' ').filter(is_whitespace);
+ a_words = a.split(' ').filter(is_whitespace);
+
+ var ops =
+ [b_words, a_words]
+ .map(function(words) {
+ // console.log(words);
+ return parseInt10(words.slice(-2, -1));
+ }).filter(function(num) {
+ var isNaN = !num && num !== 0;
+ return !isNaN;
+ });
+ if (ops.length != 2) return
+
+ var delta = ops[1] - ops[0];
+
+ total_ops.update(delta);
+
+ delta = humanize_diff(delta);
+ console.log(
+ // name of test
+ command_name(a_words) == command_name(b_words)
+ ? command_name(a_words) + ':'
+ : '404:',
+ // results of test
+ ops.join(' -> '), 'ops/sec (∆', delta, ')');
+});
+
+console.log('Mean difference in ops/sec:', humanize_diff(total_ops.mean()));
+
+function is_whitespace(s) {
+ return !!s.trim();
+}
+
+function parseInt10(s) {
+ return parseInt(s, 10);
+}
+
+// green if greater than 0, red otherwise
+function humanize_diff(num) {
+ if (num > 0) {
+ return ('+' + num).green;
+ }
+ return ('' + num).red;
+}
+
+function command_name(words) {
+ var line = words.join(' ');
+ return line.substr(0, line.indexOf(','));
+}
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/auth.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/auth.js
new file mode 100644
index 0000000..6c0a563
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/auth.js
@@ -0,0 +1,5 @@
+var redis = require("redis"),
+ client = redis.createClient();
+
+// This command is magical. Client stashes the password and will issue on every connect.
+client.auth("somepass");
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/backpressure_drain.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/backpressure_drain.js
new file mode 100644
index 0000000..3488ef4
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/backpressure_drain.js
@@ -0,0 +1,33 @@
+var redis = require("../index"),
+ client = redis.createClient(null, null, {
+ command_queue_high_water: 5,
+ command_queue_low_water: 1
+ }),
+ remaining_ops = 100000, paused = false;
+
+function op() {
+ if (remaining_ops <= 0) {
+ console.error("Finished.");
+ process.exit(0);
+ }
+
+ remaining_ops--;
+ if (client.hset("test hash", "val " + remaining_ops, remaining_ops) === false) {
+ console.log("Pausing at " + remaining_ops);
+ paused = true;
+ } else {
+ process.nextTick(op);
+ }
+}
+
+client.on("drain", function () {
+ if (paused) {
+ console.log("Resuming at " + remaining_ops);
+ paused = false;
+ process.nextTick(op);
+ } else {
+ console.log("Got drain while not paused at " + remaining_ops);
+ }
+});
+
+op();
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/eval.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/eval.js
new file mode 100644
index 0000000..c1fbf8a
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/eval.js
@@ -0,0 +1,9 @@
+var redis = require("./index"),
+ client = redis.createClient();
+
+redis.debug_mode = true;
+
+client.eval("return 100.5", 0, function (err, res) {
+ console.dir(err);
+ console.dir(res);
+});
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/extend.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/extend.js
new file mode 100644
index 0000000..488b8c2
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/extend.js
@@ -0,0 +1,24 @@
+var redis = require("redis"),
+ client = redis.createClient();
+
+// Extend the RedisClient prototype to add a custom method
+// This one converts the results from "INFO" into a JavaScript Object
+
+redis.RedisClient.prototype.parse_info = function (callback) {
+ this.info(function (err, res) {
+ var lines = res.toString().split("\r\n").sort();
+ var obj = {};
+ lines.forEach(function (line) {
+ var parts = line.split(':');
+ if (parts[1]) {
+ obj[parts[0]] = parts[1];
+ }
+ });
+ callback(obj)
+ });
+};
+
+client.parse_info(function (info) {
+ console.dir(info);
+ client.quit();
+});
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/file.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/file.js
new file mode 100644
index 0000000..4d2b5d1
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/file.js
@@ -0,0 +1,32 @@
+// Read a file from disk, store it in Redis, then read it back from Redis.
+
+var redis = require("redis"),
+ client = redis.createClient(),
+ fs = require("fs"),
+ filename = "kids_in_cart.jpg";
+
+// Get the file I use for testing like this:
+// curl http://ranney.com/kids_in_cart.jpg -o kids_in_cart.jpg
+// or just use your own file.
+
+// Read a file from fs, store it in Redis, get it back from Redis, write it back to fs.
+fs.readFile(filename, function (err, data) {
+ if (err) throw err
+ console.log("Read " + data.length + " bytes from filesystem.");
+
+ client.set(filename, data, redis.print); // set entire file
+ client.get(filename, function (err, reply) { // get entire file
+ if (err) {
+ console.log("Get error: " + err);
+ } else {
+ fs.writeFile("duplicate_" + filename, reply, function (err) {
+ if (err) {
+ console.log("Error on write: " + err)
+ } else {
+ console.log("File written.");
+ }
+ client.end();
+ });
+ }
+ });
+});
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/mget.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/mget.js
new file mode 100644
index 0000000..936740d
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/mget.js
@@ -0,0 +1,5 @@
+var client = require("redis").createClient();
+
+client.mget(["sessions started", "sessions started", "foo"], function (err, res) {
+ console.dir(res);
+}); \ No newline at end of file
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/monitor.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/monitor.js
new file mode 100644
index 0000000..2cb6a4e
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/monitor.js
@@ -0,0 +1,10 @@
+var client = require("../index").createClient(),
+ util = require("util");
+
+client.monitor(function (err, res) {
+ console.log("Entering monitoring mode.");
+});
+
+client.on("monitor", function (time, args) {
+ console.log(time + ": " + util.inspect(args));
+});
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/multi.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/multi.js
new file mode 100644
index 0000000..35c08e1
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/multi.js
@@ -0,0 +1,46 @@
+var redis = require("redis"),
+ client = redis.createClient(), set_size = 20;
+
+client.sadd("bigset", "a member");
+client.sadd("bigset", "another member");
+
+while (set_size > 0) {
+ client.sadd("bigset", "member " + set_size);
+ set_size -= 1;
+}
+
+// multi chain with an individual callback
+client.multi()
+ .scard("bigset")
+ .smembers("bigset")
+ .keys("*", function (err, replies) {
+ client.mget(replies, redis.print);
+ })
+ .dbsize()
+ .exec(function (err, replies) {
+ console.log("MULTI got " + replies.length + " replies");
+ replies.forEach(function (reply, index) {
+ console.log("Reply " + index + ": " + reply.toString());
+ });
+ });
+
+client.mset("incr thing", 100, "incr other thing", 1, redis.print);
+
+// start a separate multi command queue
+var multi = client.multi();
+multi.incr("incr thing", redis.print);
+multi.incr("incr other thing", redis.print);
+
+// runs immediately
+client.get("incr thing", redis.print); // 100
+
+// drains multi queue and runs atomically
+multi.exec(function (err, replies) {
+ console.log(replies); // 101, 2
+});
+
+// you can re-run the same transaction if you like
+multi.exec(function (err, replies) {
+ console.log(replies); // 102, 3
+ client.quit();
+});
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/multi2.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/multi2.js
new file mode 100644
index 0000000..8be4d73
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/multi2.js
@@ -0,0 +1,29 @@
+var redis = require("redis"),
+ client = redis.createClient(), multi;
+
+// start a separate command queue for multi
+multi = client.multi();
+multi.incr("incr thing", redis.print);
+multi.incr("incr other thing", redis.print);
+
+// runs immediately
+client.mset("incr thing", 100, "incr other thing", 1, redis.print);
+
+// drains multi queue and runs atomically
+multi.exec(function (err, replies) {
+ console.log(replies); // 101, 2
+});
+
+// you can re-run the same transaction if you like
+multi.exec(function (err, replies) {
+ console.log(replies); // 102, 3
+ client.quit();
+});
+
+client.multi([
+ ["mget", "multifoo", "multibar", redis.print],
+ ["incr", "multifoo"],
+ ["incr", "multibar"]
+]).exec(function (err, replies) {
+ console.log(replies.toString());
+});
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/psubscribe.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/psubscribe.js
new file mode 100644
index 0000000..c57117b
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/psubscribe.js
@@ -0,0 +1,33 @@
+var redis = require("redis"),
+ client1 = redis.createClient(),
+ client2 = redis.createClient(),
+ client3 = redis.createClient(),
+ client4 = redis.createClient(),
+ msg_count = 0;
+
+redis.debug_mode = false;
+
+client1.on("psubscribe", function (pattern, count) {
+ console.log("client1 psubscribed to " + pattern + ", " + count + " total subscriptions");
+ client2.publish("channeltwo", "Me!");
+ client3.publish("channelthree", "Me too!");
+ client4.publish("channelfour", "And me too!");
+});
+
+client1.on("punsubscribe", function (pattern, count) {
+ console.log("client1 punsubscribed from " + pattern + ", " + count + " total subscriptions");
+ client4.end();
+ client3.end();
+ client2.end();
+ client1.end();
+});
+
+client1.on("pmessage", function (pattern, channel, message) {
+ console.log("("+ pattern +")" + " client1 received message on " + channel + ": " + message);
+ msg_count += 1;
+ if (msg_count === 3) {
+ client1.punsubscribe();
+ }
+});
+
+client1.psubscribe("channel*");
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/pub_sub.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/pub_sub.js
new file mode 100644
index 0000000..aa508d6
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/pub_sub.js
@@ -0,0 +1,41 @@
+var redis = require("redis"),
+ client1 = redis.createClient(), msg_count = 0,
+ client2 = redis.createClient();
+
+redis.debug_mode = false;
+
+// Most clients probably don't do much on "subscribe". This example uses it to coordinate things within one program.
+client1.on("subscribe", function (channel, count) {
+ console.log("client1 subscribed to " + channel + ", " + count + " total subscriptions");
+ if (count === 2) {
+ client2.publish("a nice channel", "I am sending a message.");
+ client2.publish("another one", "I am sending a second message.");
+ client2.publish("a nice channel", "I am sending my last message.");
+ }
+});
+
+client1.on("unsubscribe", function (channel, count) {
+ console.log("client1 unsubscribed from " + channel + ", " + count + " total subscriptions");
+ if (count === 0) {
+ client2.end();
+ client1.end();
+ }
+});
+
+client1.on("message", function (channel, message) {
+ console.log("client1 channel " + channel + ": " + message);
+ msg_count += 1;
+ if (msg_count === 3) {
+ client1.unsubscribe();
+ }
+});
+
+client1.on("ready", function () {
+ // if you need auth, do it here
+ client1.incr("did a thing");
+ client1.subscribe("a nice channel", "another one");
+});
+
+client2.on("ready", function () {
+ // if you need auth, do it here
+});
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/simple.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/simple.js
new file mode 100644
index 0000000..f1f2e32
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/simple.js
@@ -0,0 +1,24 @@
+var redis = require("redis"),
+ client = redis.createClient();
+
+client.on("error", function (err) {
+ console.log("error event - " + client.host + ":" + client.port + " - " + err);
+});
+
+client.set("string key", "string val", redis.print);
+client.hset("hash key", "hashtest 1", "some value", redis.print);
+client.hset(["hash key", "hashtest 2", "some other value"], redis.print);
+client.hkeys("hash key", function (err, replies) {
+ if (err) {
+ return console.error("error response - " + err);
+ }
+
+ console.log(replies.length + " replies:");
+ replies.forEach(function (reply, i) {
+ console.log(" " + i + ": " + reply);
+ });
+});
+
+client.quit(function (err, res) {
+ console.log("Exiting from quit command.");
+});
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/sort.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/sort.js
new file mode 100644
index 0000000..e7c6249
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/sort.js
@@ -0,0 +1,17 @@
+var redis = require("redis"),
+ client = redis.createClient();
+
+client.sadd("mylist", 1);
+client.sadd("mylist", 2);
+client.sadd("mylist", 3);
+
+client.set("weight_1", 5);
+client.set("weight_2", 500);
+client.set("weight_3", 1);
+
+client.set("object_1", "foo");
+client.set("object_2", "bar");
+client.set("object_3", "qux");
+
+client.sort("mylist", "by", "weight_*", "get", "object_*", redis.print);
+// Prints Reply: qux,foo,bar \ No newline at end of file
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/subqueries.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/subqueries.js
new file mode 100644
index 0000000..560db24
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/subqueries.js
@@ -0,0 +1,15 @@
+// Sending commands in response to other commands.
+// This example runs "type" against every key in the database
+//
+var client = require("redis").createClient();
+
+client.keys("*", function (err, keys) {
+ keys.forEach(function (key, pos) {
+ client.type(key, function (err, keytype) {
+ console.log(key + " is " + keytype);
+ if (pos === (keys.length - 1)) {
+ client.quit();
+ }
+ });
+ });
+});
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/subquery.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/subquery.js
new file mode 100644
index 0000000..861657e
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/subquery.js
@@ -0,0 +1,19 @@
+var client = require("redis").createClient();
+
+function print_results(obj) {
+ console.dir(obj);
+}
+
+// build a map of all keys and their types
+client.keys("*", function (err, all_keys) {
+ var key_types = {};
+
+ all_keys.forEach(function (key, pos) { // use second arg of forEach to get pos
+ client.type(key, function (err, type) {
+ key_types[key] = type;
+ if (pos === all_keys.length - 1) { // callbacks all run in order
+ print_results(key_types);
+ }
+ });
+ });
+});
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/unix_socket.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/unix_socket.js
new file mode 100644
index 0000000..4a5e0bb
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/unix_socket.js
@@ -0,0 +1,29 @@
+var redis = require("redis"),
+ client = redis.createClient("/tmp/redis.sock"),
+ profiler = require("v8-profiler");
+
+client.on("connect", function () {
+ console.log("Got Unix socket connection.")
+});
+
+client.on("error", function (err) {
+ console.log(err.message);
+});
+
+client.set("space chars", "space value");
+
+setInterval(function () {
+ client.get("space chars");
+}, 100);
+
+function done() {
+ client.info(function (err, reply) {
+ console.log(reply.toString());
+ client.quit();
+ });
+}
+
+setTimeout(function () {
+ console.log("Taking snapshot.");
+ var snap = profiler.takeSnapshot();
+}, 5000);
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/examples/web_server.js b/signaling-server/node_modules/socket.io/node_modules/redis/examples/web_server.js
new file mode 100644
index 0000000..9fd8592
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/examples/web_server.js
@@ -0,0 +1,31 @@
+// A simple web server that generates dyanmic content based on responses from Redis
+
+var http = require("http"), server,
+ redis_client = require("redis").createClient();
+
+server = http.createServer(function (request, response) {
+ response.writeHead(200, {
+ "Content-Type": "text/plain"
+ });
+
+ var redis_info, total_requests;
+
+ redis_client.info(function (err, reply) {
+ redis_info = reply; // stash response in outer scope
+ });
+ redis_client.incr("requests", function (err, reply) {
+ total_requests = reply; // stash response in outer scope
+ });
+ redis_client.hincrby("ip", request.connection.remoteAddress, 1);
+ redis_client.hgetall("ip", function (err, reply) {
+ // This is the last reply, so all of the previous replies must have completed already
+ response.write("This page was generated after talking to redis.\n\n" +
+ "Redis info:\n" + redis_info + "\n" +
+ "Total requests: " + total_requests + "\n\n" +
+ "IP count: \n");
+ Object.keys(reply).forEach(function (ip) {
+ response.write(" " + ip + ": " + reply[ip] + "\n");
+ });
+ response.end();
+ });
+}).listen(80);
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/generate_commands.js b/signaling-server/node_modules/socket.io/node_modules/redis/generate_commands.js
new file mode 100644
index 0000000..e6949d3
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/generate_commands.js
@@ -0,0 +1,39 @@
+var http = require("http"),
+ fs = require("fs");
+
+function prettyCurrentTime() {
+ var date = new Date();
+ return date.toLocaleString();
+}
+
+function write_file(commands, path) {
+ var file_contents, out_commands;
+
+ console.log("Writing " + Object.keys(commands).length + " commands to " + path);
+
+ file_contents = "// This file was generated by ./generate_commands.js on " + prettyCurrentTime() + "\n";
+
+ out_commands = Object.keys(commands).map(function (key) {
+ return key.toLowerCase();
+ });
+
+ file_contents += "module.exports = " + JSON.stringify(out_commands, null, " ") + ";\n";
+
+ fs.writeFile(path, file_contents);
+}
+
+http.get({host: "redis.io", path: "/commands.json"}, function (res) {
+ var body = "";
+
+ console.log("Response from redis.io/commands.json: " + res.statusCode);
+
+ res.on('data', function (chunk) {
+ body += chunk;
+ });
+
+ res.on('end', function () {
+ write_file(JSON.parse(body), "lib/commands.js");
+ });
+}).on('error', function (e) {
+ console.log("Error fetching command list from redis.io: " + e.message);
+});
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/index.js b/signaling-server/node_modules/socket.io/node_modules/redis/index.js
new file mode 100644
index 0000000..61cb4e9
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/index.js
@@ -0,0 +1,1113 @@
+/*global Buffer require exports console setTimeout */
+
+var net = require("net"),
+ util = require("./lib/util"),
+ Queue = require("./lib/queue"),
+ to_array = require("./lib/to_array"),
+ events = require("events"),
+ crypto = require("crypto"),
+ parsers = [], commands,
+ connection_id = 0,
+ default_port = 6379,
+ default_host = "127.0.0.1";
+
+// can set this to true to enable for all connections
+exports.debug_mode = false;
+
+// hiredis might not be installed
+try {
+ require("./lib/parser/hiredis");
+ parsers.push(require("./lib/parser/hiredis"));
+} catch (err) {
+ if (exports.debug_mode) {
+ console.warn("hiredis parser not installed.");
+ }
+}
+
+parsers.push(require("./lib/parser/javascript"));
+
+function RedisClient(stream, options) {
+ this.stream = stream;
+ this.options = options = options || {};
+
+ this.connection_id = ++connection_id;
+ this.connected = false;
+ this.ready = false;
+ this.connections = 0;
+ if (this.options.socket_nodelay === undefined) {
+ this.options.socket_nodelay = true;
+ }
+ this.should_buffer = false;
+ this.command_queue_high_water = this.options.command_queue_high_water || 1000;
+ this.command_queue_low_water = this.options.command_queue_low_water || 0;
+ this.max_attempts = null;
+ if (options.max_attempts && !isNaN(options.max_attempts) && options.max_attempts > 0) {
+ this.max_attempts = +options.max_attempts;
+ }
+ this.command_queue = new Queue(); // holds sent commands to de-pipeline them
+ this.offline_queue = new Queue(); // holds commands issued but not able to be sent
+ this.commands_sent = 0;
+ this.connect_timeout = false;
+ if (options.connect_timeout && !isNaN(options.connect_timeout) && options.connect_timeout > 0) {
+ this.connect_timeout = +options.connect_timeout;
+ }
+
+ this.enable_offline_queue = true;
+ if (typeof this.options.enable_offline_queue === "boolean") {
+ this.enable_offline_queue = this.options.enable_offline_queue;
+ }
+
+ this.initialize_retry_vars();
+ this.pub_sub_mode = false;
+ this.subscription_set = {};
+ this.monitoring = false;
+ this.closing = false;
+ this.server_info = {};
+ this.auth_pass = null;
+ this.parser_module = null;
+ this.selected_db = null; // save the selected db here, used when reconnecting
+
+ this.old_state = null;
+
+ var self = this;
+
+ this.stream.on("connect", function () {
+ self.on_connect();
+ });
+
+ this.stream.on("data", function (buffer_from_socket) {
+ self.on_data(buffer_from_socket);
+ });
+
+ this.stream.on("error", function (msg) {
+ self.on_error(msg.message);
+ });
+
+ this.stream.on("close", function () {
+ self.connection_gone("close");
+ });
+
+ this.stream.on("end", function () {
+ self.connection_gone("end");
+ });
+
+ this.stream.on("drain", function () {
+ self.should_buffer = false;
+ self.emit("drain");
+ });
+
+ events.EventEmitter.call(this);
+}
+util.inherits(RedisClient, events.EventEmitter);
+exports.RedisClient = RedisClient;
+
+RedisClient.prototype.initialize_retry_vars = function () {
+ this.retry_timer = null;
+ this.retry_totaltime = 0;
+ this.retry_delay = 150;
+ this.retry_backoff = 1.7;
+ this.attempts = 1;
+};
+
+// flush offline_queue and command_queue, erroring any items with a callback first
+RedisClient.prototype.flush_and_error = function (message) {
+ var command_obj;
+ while (this.offline_queue.length > 0) {
+ command_obj = this.offline_queue.shift();
+ if (typeof command_obj.callback === "function") {
+ command_obj.callback(message);
+ }
+ }
+ this.offline_queue = new Queue();
+
+ while (this.command_queue.length > 0) {
+ command_obj = this.command_queue.shift();
+ if (typeof command_obj.callback === "function") {
+ command_obj.callback(message);
+ }
+ }
+ this.command_queue = new Queue();
+};
+
+RedisClient.prototype.on_error = function (msg) {
+ var message = "Redis connection to " + this.host + ":" + this.port + " failed - " + msg,
+ self = this, command_obj;
+
+ if (this.closing) {
+ return;
+ }
+
+ if (exports.debug_mode) {
+ console.warn(message);
+ }
+
+ this.flush_and_error(message);
+
+ this.connected = false;
+ this.ready = false;
+
+ this.emit("error", new Error(message));
+ // "error" events get turned into exceptions if they aren't listened for. If the user handled this error
+ // then we should try to reconnect.
+ this.connection_gone("error");
+};
+
+RedisClient.prototype.do_auth = function () {
+ var self = this;
+
+ if (exports.debug_mode) {
+ console.log("Sending auth to " + self.host + ":" + self.port + " id " + self.connection_id);
+ }
+ self.send_anyway = true;
+ self.send_command("auth", [this.auth_pass], function (err, res) {
+ if (err) {
+ if (err.toString().match("LOADING")) {
+ // if redis is still loading the db, it will not authenticate and everything else will fail
+ console.log("Redis still loading, trying to authenticate later");
+ setTimeout(function () {
+ self.do_auth();
+ }, 2000); // TODO - magic number alert
+ return;
+ } else {
+ return self.emit("error", new Error("Auth error: " + err.message));
+ }
+ }
+ if (res.toString() !== "OK") {
+ return self.emit("error", new Error("Auth failed: " + res.toString()));
+ }
+ if (exports.debug_mode) {
+ console.log("Auth succeeded " + self.host + ":" + self.port + " id " + self.connection_id);
+ }
+ if (self.auth_callback) {
+ self.auth_callback(err, res);
+ self.auth_callback = null;
+ }
+
+ // now we are really connected
+ self.emit("connect");
+ if (self.options.no_ready_check) {
+ self.on_ready();
+ } else {
+ self.ready_check();
+ }
+ });
+ self.send_anyway = false;
+};
+
+RedisClient.prototype.on_connect = function () {
+ if (exports.debug_mode) {
+ console.log("Stream connected " + this.host + ":" + this.port + " id " + this.connection_id);
+ }
+ var self = this;
+
+ this.connected = true;
+ this.ready = false;
+ this.attempts = 0;
+ this.connections += 1;
+ this.command_queue = new Queue();
+ this.emitted_end = false;
+ this.initialize_retry_vars();
+ if (this.options.socket_nodelay) {
+ this.stream.setNoDelay();
+ }
+ this.stream.setTimeout(0);
+
+ this.init_parser();
+
+ if (this.auth_pass) {
+ this.do_auth();
+ } else {
+ this.emit("connect");
+
+ if (this.options.no_ready_check) {
+ this.on_ready();
+ } else {
+ this.ready_check();
+ }
+ }
+};
+
+RedisClient.prototype.init_parser = function () {
+ var self = this;
+
+ if (this.options.parser) {
+ if (! parsers.some(function (parser) {
+ if (parser.name === self.options.parser) {
+ self.parser_module = parser;
+ if (exports.debug_mode) {
+ console.log("Using parser module: " + self.parser_module.name);
+ }
+ return true;
+ }
+ })) {
+ throw new Error("Couldn't find named parser " + self.options.parser + " on this system");
+ }
+ } else {
+ if (exports.debug_mode) {
+ console.log("Using default parser module: " + parsers[0].name);
+ }
+ this.parser_module = parsers[0];
+ }
+
+ this.parser_module.debug_mode = exports.debug_mode;
+
+ // return_buffers sends back Buffers from parser to callback. detect_buffers sends back Buffers from parser, but
+ // converts to Strings if the input arguments are not Buffers.
+ this.reply_parser = new this.parser_module.Parser({
+ return_buffers: self.options.return_buffers || self.options.detect_buffers || false
+ });
+
+ // "reply error" is an error sent back by Redis
+ this.reply_parser.on("reply error", function (reply) {
+ self.return_error(new Error(reply));
+ });
+ this.reply_parser.on("reply", function (reply) {
+ self.return_reply(reply);
+ });
+ // "error" is bad. Somehow the parser got confused. It'll try to reset and continue.
+ this.reply_parser.on("error", function (err) {
+ self.emit("error", new Error("Redis reply parser error: " + err.stack));
+ });
+};
+
+RedisClient.prototype.on_ready = function () {
+ var self = this;
+
+ this.ready = true;
+
+ if (this.old_state !== null) {
+ this.monitoring = this.old_state.monitoring;
+ this.pub_sub_mode = this.old_state.pub_sub_mode;
+ this.selected_db = this.old_state.selected_db;
+ this.old_state = null;
+ }
+
+ // magically restore any modal commands from a previous connection
+ if (this.selected_db !== null) {
+ this.send_command('select', [this.selected_db]);
+ }
+ if (this.pub_sub_mode === true) {
+ // only emit "ready" when all subscriptions were made again
+ var callback_count = 0;
+ var callback = function() {
+ callback_count--;
+ if (callback_count == 0) {
+ self.emit("ready");
+ }
+ }
+ Object.keys(this.subscription_set).forEach(function (key) {
+ var parts = key.split(" ");
+ if (exports.debug_mode) {
+ console.warn("sending pub/sub on_ready " + parts[0] + ", " + parts[1]);
+ }
+ callback_count++;
+ self.send_command(parts[0] + "scribe", [parts[1]], callback);
+ });
+ return;
+ } else if (this.monitoring) {
+ this.send_command("monitor");
+ } else {
+ this.send_offline_queue();
+ }
+ this.emit("ready");
+};
+
+RedisClient.prototype.on_info_cmd = function (err, res) {
+ var self = this, obj = {}, lines, retry_time;
+
+ if (err) {
+ return self.emit("error", new Error("Ready check failed: " + err.message));
+ }
+
+ lines = res.toString().split("\r\n");
+
+ lines.forEach(function (line) {
+ var parts = line.split(':');
+ if (parts[1]) {
+ obj[parts[0]] = parts[1];
+ }
+ });
+
+ obj.versions = [];
+ obj.redis_version.split('.').forEach(function (num) {
+ obj.versions.push(+num);
+ });
+
+ // expose info key/vals to users
+ this.server_info = obj;
+
+ if (!obj.loading || (obj.loading && obj.loading === "0")) {
+ if (exports.debug_mode) {
+ console.log("Redis server ready.");
+ }
+ this.on_ready();
+ } else {
+ retry_time = obj.loading_eta_seconds * 1000;
+ if (retry_time > 1000) {
+ retry_time = 1000;
+ }
+ if (exports.debug_mode) {
+ console.log("Redis server still loading, trying again in " + retry_time);
+ }
+ setTimeout(function () {
+ self.ready_check();
+ }, retry_time);
+ }
+};
+
+RedisClient.prototype.ready_check = function () {
+ var self = this;
+
+ if (exports.debug_mode) {
+ console.log("checking server ready state...");
+ }
+
+ this.send_anyway = true; // secret flag to send_command to send something even if not "ready"
+ this.info(function (err, res) {
+ self.on_info_cmd(err, res);
+ });
+ this.send_anyway = false;
+};
+
+RedisClient.prototype.send_offline_queue = function () {
+ var command_obj, buffered_writes = 0;
+
+ while (this.offline_queue.length > 0) {
+ command_obj = this.offline_queue.shift();
+ if (exports.debug_mode) {
+ console.log("Sending offline command: " + command_obj.command);
+ }
+ buffered_writes += !this.send_command(command_obj.command, command_obj.args, command_obj.callback);
+ }
+ this.offline_queue = new Queue();
+ // Even though items were shifted off, Queue backing store still uses memory until next add, so just get a new Queue
+
+ if (!buffered_writes) {
+ this.should_buffer = false;
+ this.emit("drain");
+ }
+};
+
+RedisClient.prototype.connection_gone = function (why) {
+ var self = this, message;
+
+ // If a retry is already in progress, just let that happen
+ if (this.retry_timer) {
+ return;
+ }
+
+ if (exports.debug_mode) {
+ console.warn("Redis connection is gone from " + why + " event.");
+ }
+ this.connected = false;
+ this.ready = false;
+
+ if (this.old_state === null) {
+ var state = {
+ monitoring: this.monitoring,
+ pub_sub_mode: this.pub_sub_mode,
+ selected_db: this.selected_db
+ };
+ this.old_state = state;
+ this.monitoring = false;
+ this.pub_sub_mode = false;
+ this.selected_db = null;
+ }
+
+ // since we are collapsing end and close, users don't expect to be called twice
+ if (! this.emitted_end) {
+ this.emit("end");
+ this.emitted_end = true;
+ }
+
+ this.flush_and_error("Redis connection gone from " + why + " event.");
+
+ // If this is a requested shutdown, then don't retry
+ if (this.closing) {
+ this.retry_timer = null;
+ if (exports.debug_mode) {
+ console.warn("connection ended from quit command, not retrying.");
+ }
+ return;
+ }
+
+ this.retry_delay = Math.floor(this.retry_delay * this.retry_backoff);
+
+ if (exports.debug_mode) {
+ console.log("Retry connection in " + this.current_retry_delay + " ms");
+ }
+
+ if (this.max_attempts && this.attempts >= this.max_attempts) {
+ this.retry_timer = null;
+ // TODO - some people need a "Redis is Broken mode" for future commands that errors immediately, and others
+ // want the program to exit. Right now, we just log, which doesn't really help in either case.
+ console.error("node_redis: Couldn't get Redis connection after " + this.max_attempts + " attempts.");
+ return;
+ }
+
+ this.attempts += 1;
+ this.emit("reconnecting", {
+ delay: self.retry_delay,
+ attempt: self.attempts
+ });
+ this.retry_timer = setTimeout(function () {
+ if (exports.debug_mode) {
+ console.log("Retrying connection...");
+ }
+
+ self.retry_totaltime += self.current_retry_delay;
+
+ if (self.connect_timeout && self.retry_totaltime >= self.connect_timeout) {
+ self.retry_timer = null;
+ // TODO - engage Redis is Broken mode for future commands, or whatever
+ console.error("node_redis: Couldn't get Redis connection after " + self.retry_totaltime + "ms.");
+ return;
+ }
+
+ self.stream.connect(self.port, self.host);
+ self.retry_timer = null;
+ }, this.retry_delay);
+};
+
+RedisClient.prototype.on_data = function (data) {
+ if (exports.debug_mode) {
+ console.log("net read " + this.host + ":" + this.port + " id " + this.connection_id + ": " + data.toString());
+ }
+
+ try {
+ this.reply_parser.execute(data);
+ } catch (err) {
+ // This is an unexpected parser problem, an exception that came from the parser code itself.
+ // Parser should emit "error" events if it notices things are out of whack.
+ // Callbacks that throw exceptions will land in return_reply(), below.
+ // TODO - it might be nice to have a different "error" event for different types of errors
+ this.emit("error", err);
+ }
+};
+
+RedisClient.prototype.return_error = function (err) {
+ var command_obj = this.command_queue.shift(), queue_len = this.command_queue.getLength();
+
+ if (this.pub_sub_mode === false && queue_len === 0) {
+ this.emit("idle");
+ this.command_queue = new Queue();
+ }
+ if (this.should_buffer && queue_len <= this.command_queue_low_water) {
+ this.emit("drain");
+ this.should_buffer = false;
+ }
+
+ if (command_obj && typeof command_obj.callback === "function") {
+ try {
+ command_obj.callback(err);
+ } catch (callback_err) {
+ // if a callback throws an exception, re-throw it on a new stack so the parser can keep going
+ process.nextTick(function () {
+ throw callback_err;
+ });
+ }
+ } else {
+ console.log("node_redis: no callback to send error: " + err.message);
+ // this will probably not make it anywhere useful, but we might as well throw
+ process.nextTick(function () {
+ throw err;
+ });
+ }
+};
+
+// if a callback throws an exception, re-throw it on a new stack so the parser can keep going.
+// put this try/catch in its own function because V8 doesn't optimize this well yet.
+function try_callback(callback, reply) {
+ try {
+ callback(null, reply);
+ } catch (err) {
+ process.nextTick(function () {
+ throw err;
+ });
+ }
+}
+
+// hgetall converts its replies to an Object. If the reply is empty, null is returned.
+function reply_to_object(reply) {
+ var obj = {}, j, jl, key, val;
+
+ if (reply.length === 0) {
+ return null;
+ }
+
+ for (j = 0, jl = reply.length; j < jl; j += 2) {
+ key = reply[j].toString();
+ val = reply[j + 1];
+ obj[key] = val;
+ }
+
+ return obj;
+}
+
+function reply_to_strings(reply) {
+ var i;
+
+ if (Buffer.isBuffer(reply)) {
+ return reply.toString();
+ }
+
+ if (Array.isArray(reply)) {
+ for (i = 0; i < reply.length; i++) {
+ reply[i] = reply[i].toString();
+ }
+ return reply;
+ }
+
+ return reply;
+}
+
+RedisClient.prototype.return_reply = function (reply) {
+ var command_obj, obj, i, len, type, timestamp, argindex, args, queue_len;
+
+ command_obj = this.command_queue.shift(),
+ queue_len = this.command_queue.getLength();
+
+ if (this.pub_sub_mode === false && queue_len === 0) {
+ this.emit("idle");
+ this.command_queue = new Queue(); // explicitly reclaim storage from old Queue
+ }
+ if (this.should_buffer && queue_len <= this.command_queue_low_water) {
+ this.emit("drain");
+ this.should_buffer = false;
+ }
+
+ if (command_obj && !command_obj.sub_command) {
+ if (typeof command_obj.callback === "function") {
+ if (this.options.detect_buffers && command_obj.buffer_args === false) {
+ // If detect_buffers option was specified, then the reply from the parser will be Buffers.
+ // If this command did not use Buffer arguments, then convert the reply to Strings here.
+ reply = reply_to_strings(reply);
+ }
+
+ // TODO - confusing and error-prone that hgetall is special cased in two places
+ if (reply && 'hgetall' === command_obj.command.toLowerCase()) {
+ reply = reply_to_object(reply);
+ }
+
+ try_callback(command_obj.callback, reply);
+ } else if (exports.debug_mode) {
+ console.log("no callback for reply: " + (reply && reply.toString && reply.toString()));
+ }
+ } else if (this.pub_sub_mode || (command_obj && command_obj.sub_command)) {
+ if (Array.isArray(reply)) {
+ type = reply[0].toString();
+
+ if (type === "message") {
+ this.emit("message", reply[1].toString(), reply[2]); // channel, message
+ } else if (type === "pmessage") {
+ this.emit("pmessage", reply[1].toString(), reply[2].toString(), reply[3]); // pattern, channel, message
+ } else if (type === "subscribe" || type === "unsubscribe" || type === "psubscribe" || type === "punsubscribe") {
+ if (reply[2] === 0) {
+ this.pub_sub_mode = false;
+ if (this.debug_mode) {
+ console.log("All subscriptions removed, exiting pub/sub mode");
+ }
+ } else {
+ this.pub_sub_mode = true;
+ }
+ // subscribe commands take an optional callback and also emit an event, but only the first response is included in the callback
+ // TODO - document this or fix it so it works in a more obvious way
+ if (command_obj && typeof command_obj.callback === "function") {
+ try_callback(command_obj.callback, reply[1].toString());
+ }
+ this.emit(type, reply[1].toString(), reply[2]); // channel, count
+ } else {
+ throw new Error("subscriptions are active but got unknown reply type " + type);
+ }
+ } else if (! this.closing) {
+ throw new Error("subscriptions are active but got an invalid reply: " + reply);
+ }
+ } else if (this.monitoring) {
+ len = reply.indexOf(" ");
+ timestamp = reply.slice(0, len);
+ argindex = reply.indexOf('"');
+ args = reply.slice(argindex + 1, -1).split('" "').map(function (elem) {
+ return elem.replace(/\\"/g, '"');
+ });
+ this.emit("monitor", timestamp, args);
+ } else {
+ throw new Error("node_redis command queue state error. If you can reproduce this, please report it.");
+ }
+};
+
+// This Command constructor is ever so slightly faster than using an object literal, but more importantly, using
+// a named constructor helps it show up meaningfully in the V8 CPU profiler and in heap snapshots.
+function Command(command, args, sub_command, buffer_args, callback) {
+ this.command = command;
+ this.args = args;
+ this.sub_command = sub_command;
+ this.buffer_args = buffer_args;
+ this.callback = callback;
+}
+
+RedisClient.prototype.send_command = function (command, args, callback) {
+ var arg, this_args, command_obj, i, il, elem_count, buffer_args, stream = this.stream, command_str = "", buffered_writes = 0, last_arg_type;
+
+ if (typeof command !== "string") {
+ throw new Error("First argument to send_command must be the command name string, not " + typeof command);
+ }
+
+ if (Array.isArray(args)) {
+ if (typeof callback === "function") {
+ // probably the fastest way:
+ // client.command([arg1, arg2], cb); (straight passthrough)
+ // send_command(command, [arg1, arg2], cb);
+ } else if (! callback) {
+ // most people find this variable argument length form more convenient, but it uses arguments, which is slower
+ // client.command(arg1, arg2, cb); (wraps up arguments into an array)
+ // send_command(command, [arg1, arg2, cb]);
+ // client.command(arg1, arg2); (callback is optional)
+ // send_command(command, [arg1, arg2]);
+ // client.command(arg1, arg2, undefined); (callback is undefined)
+ // send_command(command, [arg1, arg2, undefined]);
+ last_arg_type = typeof args[args.length - 1];
+ if (last_arg_type === "function" || last_arg_type === "undefined") {
+ callback = args.pop();
+ }
+ } else {
+ throw new Error("send_command: last argument must be a callback or undefined");
+ }
+ } else {
+ throw new Error("send_command: second argument must be an array");
+ }
+
+ // if the last argument is an array and command is sadd, expand it out:
+ // client.sadd(arg1, [arg2, arg3, arg4], cb);
+ // converts to:
+ // client.sadd(arg1, arg2, arg3, arg4, cb);
+ if ((command === 'sadd' || command === 'SADD') && args.length > 0 && Array.isArray(args[args.length - 1])) {
+ args = args.slice(0, -1).concat(args[args.length - 1]);
+ }
+
+ buffer_args = false;
+ for (i = 0, il = args.length, arg; i < il; i += 1) {
+ if (Buffer.isBuffer(args[i])) {
+ buffer_args = true;
+ }
+ }
+
+ command_obj = new Command(command, args, false, buffer_args, callback);
+
+ if ((!this.ready && !this.send_anyway) || !stream.writable) {
+ if (exports.debug_mode) {
+ if (!stream.writable) {
+ console.log("send command: stream is not writeable.");
+ }
+ }
+
+ if (this.enable_offline_queue) {
+ if (exports.debug_mode) {
+ console.log("Queueing " + command + " for next server connection.");
+ }
+ this.offline_queue.push(command_obj);
+ this.should_buffer = true;
+ } else {
+ var not_writeable_error = new Error('send_command: stream not writeable. enable_offline_queue is false');
+ if (command_obj.callback) {
+ command_obj.callback(not_writeable_error);
+ } else {
+ throw not_writeable_error;
+ }
+ }
+
+ return false;
+ }
+
+ if (command === "subscribe" || command === "psubscribe" || command === "unsubscribe" || command === "punsubscribe") {
+ this.pub_sub_command(command_obj);
+ } else if (command === "monitor") {
+ this.monitoring = true;
+ } else if (command === "quit") {
+ this.closing = true;
+ } else if (this.pub_sub_mode === true) {
+ throw new Error("Connection in pub/sub mode, only pub/sub commands may be used");
+ }
+ this.command_queue.push(command_obj);
+ this.commands_sent += 1;
+
+ elem_count = args.length + 1;
+
+ // Always use "Multi bulk commands", but if passed any Buffer args, then do multiple writes, one for each arg.
+ // This means that using Buffers in commands is going to be slower, so use Strings if you don't already have a Buffer.
+
+ command_str = "*" + elem_count + "\r\n$" + command.length + "\r\n" + command + "\r\n";
+
+ if (! buffer_args) { // Build up a string and send entire command in one write
+ for (i = 0, il = args.length, arg; i < il; i += 1) {
+ arg = args[i];
+ if (typeof arg !== "string") {
+ arg = String(arg);
+ }
+ command_str += "$" + Buffer.byteLength(arg) + "\r\n" + arg + "\r\n";
+ }
+ if (exports.debug_mode) {
+ console.log("send " + this.host + ":" + this.port + " id " + this.connection_id + ": " + command_str);
+ }
+ buffered_writes += !stream.write(command_str);
+ } else {
+ if (exports.debug_mode) {
+ console.log("send command (" + command_str + ") has Buffer arguments");
+ }
+ buffered_writes += !stream.write(command_str);
+
+ for (i = 0, il = args.length, arg; i < il; i += 1) {
+ arg = args[i];
+ if (!(Buffer.isBuffer(arg) || arg instanceof String)) {
+ arg = String(arg);
+ }
+
+ if (Buffer.isBuffer(arg)) {
+ if (arg.length === 0) {
+ if (exports.debug_mode) {
+ console.log("send_command: using empty string for 0 length buffer");
+ }
+ buffered_writes += !stream.write("$0\r\n\r\n");
+ } else {
+ buffered_writes += !stream.write("$" + arg.length + "\r\n");
+ buffered_writes += !stream.write(arg);
+ buffered_writes += !stream.write("\r\n");
+ if (exports.debug_mode) {
+ console.log("send_command: buffer send " + arg.length + " bytes");
+ }
+ }
+ } else {
+ if (exports.debug_mode) {
+ console.log("send_command: string send " + Buffer.byteLength(arg) + " bytes: " + arg);
+ }
+ buffered_writes += !stream.write("$" + Buffer.byteLength(arg) + "\r\n" + arg + "\r\n");
+ }
+ }
+ }
+ if (exports.debug_mode) {
+ console.log("send_command buffered_writes: " + buffered_writes, " should_buffer: " + this.should_buffer);
+ }
+ if (buffered_writes || this.command_queue.getLength() >= this.command_queue_high_water) {
+ this.should_buffer = true;
+ }
+ return !this.should_buffer;
+};
+
+RedisClient.prototype.pub_sub_command = function (command_obj) {
+ var i, key, command, args;
+
+ if (this.pub_sub_mode === false && exports.debug_mode) {
+ console.log("Entering pub/sub mode from " + command_obj.command);
+ }
+ this.pub_sub_mode = true;
+ command_obj.sub_command = true;
+
+ command = command_obj.command;
+ args = command_obj.args;
+ if (command === "subscribe" || command === "psubscribe") {
+ if (command === "subscribe") {
+ key = "sub";
+ } else {
+ key = "psub";
+ }
+ for (i = 0; i < args.length; i++) {
+ this.subscription_set[key + " " + args[i]] = true;
+ }
+ } else {
+ if (command === "unsubscribe") {
+ key = "sub";
+ } else {
+ key = "psub";
+ }
+ for (i = 0; i < args.length; i++) {
+ delete this.subscription_set[key + " " + args[i]];
+ }
+ }
+};
+
+RedisClient.prototype.end = function () {
+ this.stream._events = {};
+ this.connected = false;
+ this.ready = false;
+ return this.stream.end();
+};
+
+function Multi(client, args) {
+ this.client = client;
+ this.queue = [["MULTI"]];
+ if (Array.isArray(args)) {
+ this.queue = this.queue.concat(args);
+ }
+}
+
+exports.Multi = Multi;
+
+// take 2 arrays and return the union of their elements
+function set_union(seta, setb) {
+ var obj = {};
+
+ seta.forEach(function (val) {
+ obj[val] = true;
+ });
+ setb.forEach(function (val) {
+ obj[val] = true;
+ });
+ return Object.keys(obj);
+}
+
+// This static list of commands is updated from time to time. ./lib/commands.js can be updated with generate_commands.js
+commands = set_union(["get", "set", "setnx", "setex", "append", "strlen", "del", "exists", "setbit", "getbit", "setrange", "getrange", "substr",
+ "incr", "decr", "mget", "rpush", "lpush", "rpushx", "lpushx", "linsert", "rpop", "lpop", "brpop", "brpoplpush", "blpop", "llen", "lindex",
+ "lset", "lrange", "ltrim", "lrem", "rpoplpush", "sadd", "srem", "smove", "sismember", "scard", "spop", "srandmember", "sinter", "sinterstore",
+ "sunion", "sunionstore", "sdiff", "sdiffstore", "smembers", "zadd", "zincrby", "zrem", "zremrangebyscore", "zremrangebyrank", "zunionstore",
+ "zinterstore", "zrange", "zrangebyscore", "zrevrangebyscore", "zcount", "zrevrange", "zcard", "zscore", "zrank", "zrevrank", "hset", "hsetnx",
+ "hget", "hmset", "hmget", "hincrby", "hdel", "hlen", "hkeys", "hvals", "hgetall", "hexists", "incrby", "decrby", "getset", "mset", "msetnx",
+ "randomkey", "select", "move", "rename", "renamenx", "expire", "expireat", "keys", "dbsize", "auth", "ping", "echo", "save", "bgsave",
+ "bgrewriteaof", "shutdown", "lastsave", "type", "multi", "exec", "discard", "sync", "flushdb", "flushall", "sort", "info", "monitor", "ttl",
+ "persist", "slaveof", "debug", "config", "subscribe", "unsubscribe", "psubscribe", "punsubscribe", "publish", "watch", "unwatch", "cluster",
+ "restore", "migrate", "dump", "object", "client", "eval", "evalsha"], require("./lib/commands"));
+
+commands.forEach(function (command) {
+ RedisClient.prototype[command] = function (args, callback) {
+ if (Array.isArray(args) && typeof callback === "function") {
+ return this.send_command(command, args, callback);
+ } else {
+ return this.send_command(command, to_array(arguments));
+ }
+ };
+ RedisClient.prototype[command.toUpperCase()] = RedisClient.prototype[command];
+
+ Multi.prototype[command] = function () {
+ this.queue.push([command].concat(to_array(arguments)));
+ return this;
+ };
+ Multi.prototype[command.toUpperCase()] = Multi.prototype[command];
+});
+
+// store db in this.select_db to restore it on reconnect
+RedisClient.prototype.select = function (db, callback) {
+ var self = this;
+
+ this.send_command('select', [db], function (err, res) {
+ if (err === null) {
+ self.selected_db = db;
+ }
+ if (typeof(callback) === 'function') {
+ callback(err, res);
+ }
+ });
+};
+RedisClient.prototype.SELECT = RedisClient.prototype.select;
+
+// Stash auth for connect and reconnect. Send immediately if already connected.
+RedisClient.prototype.auth = function () {
+ var args = to_array(arguments);
+ this.auth_pass = args[0];
+ this.auth_callback = args[1];
+ if (exports.debug_mode) {
+ console.log("Saving auth as " + this.auth_pass);
+ }
+
+ if (this.connected) {
+ this.send_command("auth", args);
+ }
+};
+RedisClient.prototype.AUTH = RedisClient.prototype.auth;
+
+RedisClient.prototype.hmget = function (arg1, arg2, arg3) {
+ if (Array.isArray(arg2) && typeof arg3 === "function") {
+ return this.send_command("hmget", [arg1].concat(arg2), arg3);
+ } else if (Array.isArray(arg1) && typeof arg2 === "function") {
+ return this.send_command("hmget", arg1, arg2);
+ } else {
+ return this.send_command("hmget", to_array(arguments));
+ }
+};
+RedisClient.prototype.HMGET = RedisClient.prototype.hmget;
+
+RedisClient.prototype.hmset = function (args, callback) {
+ var tmp_args, tmp_keys, i, il, key;
+
+ if (Array.isArray(args) && typeof callback === "function") {
+ return this.send_command("hmset", args, callback);
+ }
+
+ args = to_array(arguments);
+ if (typeof args[args.length - 1] === "function") {
+ callback = args[args.length - 1];
+ args.length -= 1;
+ } else {
+ callback = null;
+ }
+
+ if (args.length === 2 && typeof args[0] === "string" && typeof args[1] === "object") {
+ // User does: client.hmset(key, {key1: val1, key2: val2})
+ tmp_args = [ args[0] ];
+ tmp_keys = Object.keys(args[1]);
+ for (i = 0, il = tmp_keys.length; i < il ; i++) {
+ key = tmp_keys[i];
+ tmp_args.push(key);
+ if (typeof args[1][key] !== "string") {
+ var err = new Error("hmset expected value to be a string", key, ":", args[1][key]);
+ if (callback) return callback(err);
+ else throw err;
+ }
+ tmp_args.push(args[1][key]);
+ }
+ args = tmp_args;
+ }
+
+ return this.send_command("hmset", args, callback);
+};
+RedisClient.prototype.HMSET = RedisClient.prototype.hmset;
+
+Multi.prototype.hmset = function () {
+ var args = to_array(arguments), tmp_args;
+ if (args.length >= 2 && typeof args[0] === "string" && typeof args[1] === "object") {
+ tmp_args = [ "hmset", args[0] ];
+ Object.keys(args[1]).map(function (key) {
+ tmp_args.push(key);
+ tmp_args.push(args[1][key]);
+ });
+ if (args[2]) {
+ tmp_args.push(args[2]);
+ }
+ args = tmp_args;
+ } else {
+ args.unshift("hmset");
+ }
+
+ this.queue.push(args);
+ return this;
+};
+Multi.prototype.HMSET = Multi.prototype.hmset;
+
+Multi.prototype.exec = function (callback) {
+ var self = this;
+
+ // drain queue, callback will catch "QUEUED" or error
+ // TODO - get rid of all of these anonymous functions which are elegant but slow
+ this.queue.forEach(function (args, index) {
+ var command = args[0], obj;
+ if (typeof args[args.length - 1] === "function") {
+ args = args.slice(1, -1);
+ } else {
+ args = args.slice(1);
+ }
+ if (args.length === 1 && Array.isArray(args[0])) {
+ args = args[0];
+ }
+ if (command.toLowerCase() === 'hmset' && typeof args[1] === 'object') {
+ obj = args.pop();
+ Object.keys(obj).forEach(function (key) {
+ args.push(key);
+ args.push(obj[key]);
+ });
+ }
+ this.client.send_command(command, args, function (err, reply) {
+ if (err) {
+ var cur = self.queue[index];
+ if (typeof cur[cur.length - 1] === "function") {
+ cur[cur.length - 1](err);
+ } else {
+ throw new Error(err);
+ }
+ self.queue.splice(index, 1);
+ }
+ });
+ }, this);
+
+ // TODO - make this callback part of Multi.prototype instead of creating it each time
+ return this.client.send_command("EXEC", [], function (err, replies) {
+ if (err) {
+ if (callback) {
+ callback(new Error(err));
+ return;
+ } else {
+ throw new Error(err);
+ }
+ }
+
+ var i, il, j, jl, reply, args;
+
+ if (replies) {
+ for (i = 1, il = self.queue.length; i < il; i += 1) {
+ reply = replies[i - 1];
+ args = self.queue[i];
+
+ // TODO - confusing and error-prone that hgetall is special cased in two places
+ if (reply && args[0].toLowerCase() === "hgetall") {
+ replies[i - 1] = reply = reply_to_object(reply);
+ }
+
+ if (typeof args[args.length - 1] === "function") {
+ args[args.length - 1](null, reply);
+ }
+ }
+ }
+
+ if (callback) {
+ callback(null, replies);
+ }
+ });
+};
+Multi.prototype.EXEC = Multi.prototype.exec;
+
+RedisClient.prototype.multi = function (args) {
+ return new Multi(this, args);
+};
+RedisClient.prototype.MULTI = function (args) {
+ return new Multi(this, args);
+};
+
+
+// stash original eval method
+var eval = RedisClient.prototype.eval;
+// hook eval with an attempt to evalsha for cached scripts
+RedisClient.prototype.eval =
+RedisClient.prototype.EVAL = function () {
+ var self = this,
+ args = to_array(arguments),
+ callback;
+
+ if (typeof args[args.length - 1] === "function") {
+ callback = args.pop();
+ }
+
+ // replace script source with sha value
+ var source = args[0];
+ args[0] = crypto.createHash("sha1").update(source).digest("hex");
+
+ self.evalsha(args, function (err, reply) {
+ if (err && /NOSCRIPT/.test(err.message)) {
+ args[0] = source;
+ eval.call(self, args, callback);
+
+ } else if (callback) {
+ callback(err, reply);
+ }
+ });
+};
+
+
+exports.createClient = function (port_arg, host_arg, options) {
+ var port = port_arg || default_port,
+ host = host_arg || default_host,
+ redis_client, net_client;
+
+ net_client = net.createConnection(port, host);
+
+ redis_client = new RedisClient(net_client, options);
+
+ redis_client.port = port;
+ redis_client.host = host;
+
+ return redis_client;
+};
+
+exports.print = function (err, reply) {
+ if (err) {
+ console.log("Error: " + err);
+ } else {
+ console.log("Reply: " + reply);
+ }
+};
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/lib/commands.js b/signaling-server/node_modules/socket.io/node_modules/redis/lib/commands.js
new file mode 100644
index 0000000..f57cca9
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/lib/commands.js
@@ -0,0 +1,147 @@
+// This file was generated by ./generate_commands.js on Mon Aug 06 2012 15:04:06 GMT-0700 (PDT)
+module.exports = [
+ "append",
+ "auth",
+ "bgrewriteaof",
+ "bgsave",
+ "bitcount",
+ "bitop",
+ "blpop",
+ "brpop",
+ "brpoplpush",
+ "client kill",
+ "client list",
+ "config get",
+ "config set",
+ "config resetstat",
+ "dbsize",
+ "debug object",
+ "debug segfault",
+ "decr",
+ "decrby",
+ "del",
+ "discard",
+ "dump",
+ "echo",
+ "eval",
+ "evalsha",
+ "exec",
+ "exists",
+ "expire",
+ "expireat",
+ "flushall",
+ "flushdb",
+ "get",
+ "getbit",
+ "getrange",
+ "getset",
+ "hdel",
+ "hexists",
+ "hget",
+ "hgetall",
+ "hincrby",
+ "hincrbyfloat",
+ "hkeys",
+ "hlen",
+ "hmget",
+ "hmset",
+ "hset",
+ "hsetnx",
+ "hvals",
+ "incr",
+ "incrby",
+ "incrbyfloat",
+ "info",
+ "keys",
+ "lastsave",
+ "lindex",
+ "linsert",
+ "llen",
+ "lpop",
+ "lpush",
+ "lpushx",
+ "lrange",
+ "lrem",
+ "lset",
+ "ltrim",
+ "mget",
+ "migrate",
+ "monitor",
+ "move",
+ "mset",
+ "msetnx",
+ "multi",
+ "object",
+ "persist",
+ "pexpire",
+ "pexpireat",
+ "ping",
+ "psetex",
+ "psubscribe",
+ "pttl",
+ "publish",
+ "punsubscribe",
+ "quit",
+ "randomkey",
+ "rename",
+ "renamenx",
+ "restore",
+ "rpop",
+ "rpoplpush",
+ "rpush",
+ "rpushx",
+ "sadd",
+ "save",
+ "scard",
+ "script exists",
+ "script flush",
+ "script kill",
+ "script load",
+ "sdiff",
+ "sdiffstore",
+ "select",
+ "set",
+ "setbit",
+ "setex",
+ "setnx",
+ "setrange",
+ "shutdown",
+ "sinter",
+ "sinterstore",
+ "sismember",
+ "slaveof",
+ "slowlog",
+ "smembers",
+ "smove",
+ "sort",
+ "spop",
+ "srandmember",
+ "srem",
+ "strlen",
+ "subscribe",
+ "sunion",
+ "sunionstore",
+ "sync",
+ "time",
+ "ttl",
+ "type",
+ "unsubscribe",
+ "unwatch",
+ "watch",
+ "zadd",
+ "zcard",
+ "zcount",
+ "zincrby",
+ "zinterstore",
+ "zrange",
+ "zrangebyscore",
+ "zrank",
+ "zrem",
+ "zremrangebyrank",
+ "zremrangebyscore",
+ "zrevrange",
+ "zrevrangebyscore",
+ "zrevrank",
+ "zscore",
+ "zunionstore"
+];
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/lib/parser/hiredis.js b/signaling-server/node_modules/socket.io/node_modules/redis/lib/parser/hiredis.js
new file mode 100644
index 0000000..cbb15ba
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/lib/parser/hiredis.js
@@ -0,0 +1,46 @@
+/*global Buffer require exports console setTimeout */
+
+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);
+ }
+ }
+};
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js b/signaling-server/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js
new file mode 100644
index 0000000..b8f5bc6
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/lib/parser/javascript.js
@@ -0,0 +1,317 @@
+/*global Buffer require exports console setTimeout */
+
+// TODO - incorporate these V8 pro tips:
+// pre-allocate Arrays if length is known in advance
+// do not use delete
+// use numbers for parser state
+
+var events = require("events"),
+ util = require("../util");
+
+exports.debug_mode = false;
+exports.name = "javascript";
+
+function RedisReplyParser(options) {
+ this.name = exports.name;
+ this.options = options || {};
+ this.reset();
+ events.EventEmitter.call(this);
+}
+
+util.inherits(RedisReplyParser, events.EventEmitter);
+
+exports.Parser = RedisReplyParser;
+
+// Buffer.toString() is quite slow for small strings
+function small_toString(buf, len) {
+ var tmp = "", i;
+
+ for (i = 0; i < len; i += 1) {
+ tmp += String.fromCharCode(buf[i]);
+ }
+
+ return tmp;
+}
+
+// Reset parser to it's original state.
+RedisReplyParser.prototype.reset = function () {
+ this.return_buffer = new Buffer(16384); // for holding replies, might grow
+ this.return_string = "";
+ this.tmp_string = ""; // for holding size fields
+
+ this.multi_bulk_length = 0;
+ this.multi_bulk_replies = null;
+ this.multi_bulk_pos = 0;
+ this.multi_bulk_nested_length = 0;
+ this.multi_bulk_nested_replies = null;
+
+ this.states = {
+ TYPE: 1,
+ SINGLE_LINE: 2,
+ MULTI_BULK_COUNT: 3,
+ INTEGER_LINE: 4,
+ BULK_LENGTH: 5,
+ ERROR_LINE: 6,
+ BULK_DATA: 7,
+ UNKNOWN_TYPE: 8,
+ FINAL_CR: 9,
+ FINAL_LF: 10,
+ MULTI_BULK_COUNT_LF: 11,
+ BULK_LF: 12
+ };
+
+ this.state = this.states.TYPE;
+};
+
+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, states = this.states;
+ //, 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;
+ // console.log("execute: " + this.state + ", " + pos + "/" + incoming_buf.length + ", " + String.fromCharCode(incoming_buf[pos]));
+
+ switch (this.state) {
+ case 1: // states.TYPE
+ this.type = incoming_buf[pos];
+ pos += 1;
+
+ switch (this.type) {
+ case 43: // +
+ this.state = states.SINGLE_LINE;
+ this.return_buffer.end = 0;
+ this.return_string = "";
+ break;
+ case 42: // *
+ this.state = states.MULTI_BULK_COUNT;
+ this.tmp_string = "";
+ break;
+ case 58: // :
+ this.state = states.INTEGER_LINE;
+ this.return_buffer.end = 0;
+ this.return_string = "";
+ break;
+ case 36: // $
+ this.state = states.BULK_LENGTH;
+ this.tmp_string = "";
+ break;
+ case 45: // -
+ this.state = states.ERROR_LINE;
+ this.return_buffer.end = 0;
+ this.return_string = "";
+ break;
+ default:
+ this.state = states.UNKNOWN_TYPE;
+ }
+ break;
+ case 4: // states.INTEGER_LINE
+ if (incoming_buf[pos] === 13) {
+ this.send_reply(+small_toString(this.return_buffer, this.return_buffer.end));
+ this.state = states.FINAL_LF;
+ } else {
+ this.return_buffer[this.return_buffer.end] = incoming_buf[pos];
+ this.return_buffer.end += 1;
+ }
+ pos += 1;
+ break;
+ case 6: // states.ERROR_LINE
+ if (incoming_buf[pos] === 13) {
+ this.send_error(this.return_buffer.toString("ascii", 0, this.return_buffer.end));
+ this.state = states.FINAL_LF;
+ } else {
+ this.return_buffer[this.return_buffer.end] = incoming_buf[pos];
+ this.return_buffer.end += 1;
+ }
+ pos += 1;
+ break;
+ case 2: // states.SINGLE_LINE
+ if (incoming_buf[pos] === 13) {
+ this.send_reply(this.return_string);
+ this.state = states.FINAL_LF;
+ } else {
+ this.return_string += String.fromCharCode(incoming_buf[pos]);
+ }
+ pos += 1;
+ break;
+ case 3: // states.MULTI_BULK_COUNT
+ if (incoming_buf[pos] === 13) { // \r
+ this.state = states.MULTI_BULK_COUNT_LF;
+ } else {
+ this.tmp_string += String.fromCharCode(incoming_buf[pos]);
+ }
+ pos += 1;
+ break;
+ case 11: // states.MULTI_BULK_COUNT_LF
+ if (incoming_buf[pos] === 10) { // \n
+ if (this.multi_bulk_length) { // nested multi-bulk
+ this.multi_bulk_nested_length = this.multi_bulk_length;
+ this.multi_bulk_nested_replies = this.multi_bulk_replies;
+ this.multi_bulk_nested_pos = this.multi_bulk_pos;
+ }
+ this.multi_bulk_length = +this.tmp_string;
+ this.multi_bulk_pos = 0;
+ this.state = states.TYPE;
+ if (this.multi_bulk_length < 0) {
+ this.send_reply(null);
+ this.multi_bulk_length = 0;
+ } else if (this.multi_bulk_length === 0) {
+ this.multi_bulk_pos = 0;
+ this.multi_bulk_replies = null;
+ this.send_reply([]);
+ } else {
+ this.multi_bulk_replies = new Array(this.multi_bulk_length);
+ }
+ } else {
+ this.parser_error(new Error("didn't see LF after NL reading multi bulk count"));
+ return;
+ }
+ pos += 1;
+ break;
+ case 5: // states.BULK_LENGTH
+ if (incoming_buf[pos] === 13) { // \r
+ this.state = states.BULK_LF;
+ } else {
+ this.tmp_string += String.fromCharCode(incoming_buf[pos]);
+ }
+ pos += 1;
+ break;
+ case 12: // states.BULK_LF
+ if (incoming_buf[pos] === 10) { // \n
+ this.bulk_length = +this.tmp_string;
+ if (this.bulk_length === -1) {
+ this.send_reply(null);
+ this.state = states.TYPE;
+ } else if (this.bulk_length === 0) {
+ this.send_reply(new Buffer(""));
+ this.state = states.FINAL_CR;
+ } else {
+ this.state = states.BULK_DATA;
+ if (this.bulk_length > this.return_buffer.length) {
+ if (exports.debug_mode) {
+ console.log("Growing return_buffer from " + this.return_buffer.length + " to " + this.bulk_length);
+ }
+ this.return_buffer = new Buffer(this.bulk_length);
+ }
+ this.return_buffer.end = 0;
+ }
+ } else {
+ this.parser_error(new Error("didn't see LF after NL while reading bulk length"));
+ return;
+ }
+ pos += 1;
+ break;
+ case 7: // states.BULK_DATA
+ this.return_buffer[this.return_buffer.end] = incoming_buf[pos];
+ this.return_buffer.end += 1;
+ pos += 1;
+ 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 {
+ for (i = 0, il = this.bulk_length; i < il; i += 1) {
+ bd_tmp[i] = this.return_buffer[i];
+ }
+ }
+ this.send_reply(bd_tmp);
+ this.state = states.FINAL_CR;
+ }
+ break;
+ case 9: // states.FINAL_CR
+ if (incoming_buf[pos] === 13) { // \r
+ this.state = states.FINAL_LF;
+ pos += 1;
+ } else {
+ this.parser_error(new Error("saw " + incoming_buf[pos] + " when expecting final CR"));
+ return;
+ }
+ break;
+ case 10: // states.FINAL_LF
+ if (incoming_buf[pos] === 10) { // \n
+ this.state = states.TYPE;
+ pos += 1;
+ } else {
+ this.parser_error(new Error("saw " + incoming_buf[pos] + " when expecting final LF"));
+ return;
+ }
+ break;
+ default:
+ this.parser_error(new Error("invalid state " + this.state));
+ }
+ // end_switch = new Date();
+ // if (state_times[old_state] === undefined) {
+ // state_times[old_state] = 0;
+ // }
+ // state_times[old_state] += (end_switch - start_switch);
+ // start_switch = end_switch;
+ }
+ // console.log("execute ran for " + (Date.now() - start_execute) + " ms, on " + incoming_buf.length + " Bytes. ");
+ // Object.keys(state_times).forEach(function (state) {
+ // console.log(" " + state + ": " + state_times[state]);
+ // });
+};
+
+RedisReplyParser.prototype.send_error = function (reply) {
+ if (this.multi_bulk_length > 0 || this.multi_bulk_nested_length > 0) {
+ // TODO - can this happen? Seems like maybe not.
+ this.add_multi_bulk_reply(reply);
+ } else {
+ this.emit("reply error", reply);
+ }
+};
+
+RedisReplyParser.prototype.send_reply = function (reply) {
+ if (this.multi_bulk_length > 0 || this.multi_bulk_nested_length > 0) {
+ if (!this.options.return_buffers && Buffer.isBuffer(reply)) {
+ this.add_multi_bulk_reply(reply.toString("utf8"));
+ } else {
+ this.add_multi_bulk_reply(reply);
+ }
+ } else {
+ if (!this.options.return_buffers && Buffer.isBuffer(reply)) {
+ this.emit("reply", reply.toString("utf8"));
+ } else {
+ this.emit("reply", reply);
+ }
+ }
+};
+
+RedisReplyParser.prototype.add_multi_bulk_reply = function (reply) {
+ if (this.multi_bulk_replies) {
+ this.multi_bulk_replies[this.multi_bulk_pos] = reply;
+ this.multi_bulk_pos += 1;
+ if (this.multi_bulk_pos < this.multi_bulk_length) {
+ return;
+ }
+ } else {
+ this.multi_bulk_replies = reply;
+ }
+
+ if (this.multi_bulk_nested_length > 0) {
+ this.multi_bulk_nested_replies[this.multi_bulk_nested_pos] = this.multi_bulk_replies;
+ this.multi_bulk_nested_pos += 1;
+
+ this.multi_bulk_length = 0;
+ this.multi_bulk_replies = null;
+ this.multi_bulk_pos = 0;
+
+ if (this.multi_bulk_nested_length === this.multi_bulk_nested_pos) {
+ this.emit("reply", this.multi_bulk_nested_replies);
+ this.multi_bulk_nested_length = 0;
+ this.multi_bulk_nested_pos = 0;
+ this.multi_bulk_nested_replies = null;
+ }
+ } else {
+ this.emit("reply", this.multi_bulk_replies);
+ this.multi_bulk_length = 0;
+ this.multi_bulk_replies = null;
+ this.multi_bulk_pos = 0;
+ }
+};
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/lib/queue.js b/signaling-server/node_modules/socket.io/node_modules/redis/lib/queue.js
new file mode 100644
index 0000000..56254e1
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/lib/queue.js
@@ -0,0 +1,61 @@
+var to_array = require("./to_array");
+
+// 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;
+}
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/lib/to_array.js b/signaling-server/node_modules/socket.io/node_modules/redis/lib/to_array.js
new file mode 100644
index 0000000..88a57e1
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/lib/to_array.js
@@ -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;
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/lib/util.js b/signaling-server/node_modules/socket.io/node_modules/redis/lib/util.js
new file mode 100644
index 0000000..fc255ae
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/lib/util.js
@@ -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;
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/mem.js b/signaling-server/node_modules/socket.io/node_modules/redis/mem.js
new file mode 100644
index 0000000..5144ab2
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/mem.js
@@ -0,0 +1,11 @@
+var client = require("redis").createClient();
+
+client.set("foo", "barvalskdjlksdjflkdsjflksdjdflkdsjflksdjflksdj", function (err, res) {
+ if (err) {
+ console.log("Got an error, please adapt somehow.");
+ } else {
+ console.log("Got a result: " + res);
+ }
+});
+
+client.quit();
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/multi_bench.js b/signaling-server/node_modules/socket.io/node_modules/redis/multi_bench.js
new file mode 100644
index 0000000..5be2e56
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/multi_bench.js
@@ -0,0 +1,225 @@
+var redis = require("./index"),
+ metrics = require("metrics"),
+ num_clients = parseInt(process.argv[2], 10) || 5,
+ num_requests = 20000,
+ tests = [],
+ versions_logged = false,
+ client_options = {
+ return_buffers: false
+ },
+ small_str, large_str, small_buf, large_buf;
+
+redis.debug_mode = false;
+
+function lpad(input, len, chr) {
+ var str = input.toString();
+ chr = chr || " ";
+
+ while (str.length < len) {
+ str = chr + str;
+ }
+ return str;
+}
+
+metrics.Histogram.prototype.print_line = function () {
+ var obj = this.printObj();
+
+ return lpad(obj.min, 4) + "/" + lpad(obj.max, 4) + "/" + lpad(obj.mean.toFixed(2), 7) + "/" + lpad(obj.p95.toFixed(2), 7);
+};
+
+function Test(args) {
+ var self = this;
+
+ this.args = args;
+
+ this.callback = null;
+ this.clients = [];
+ this.clients_ready = 0;
+ this.commands_sent = 0;
+ this.commands_completed = 0;
+ this.max_pipeline = this.args.pipeline || num_requests;
+ this.client_options = args.client_options || client_options;
+
+ this.connect_latency = new metrics.Histogram();
+ this.ready_latency = new metrics.Histogram();
+ this.command_latency = new metrics.Histogram();
+}
+
+Test.prototype.run = function (callback) {
+ var self = this, i;
+
+ this.callback = callback;
+
+ for (i = 0; i < num_clients ; i++) {
+ this.new_client(i);
+ }
+};
+
+Test.prototype.new_client = function (id) {
+ var self = this, new_client;
+
+ new_client = redis.createClient(6379, "127.0.0.1", this.client_options);
+ new_client.create_time = Date.now();
+
+ new_client.on("connect", function () {
+ self.connect_latency.update(Date.now() - new_client.create_time);
+ });
+
+ new_client.on("ready", function () {
+ if (! versions_logged) {
+ console.log("Client count: " + num_clients + ", node version: " + process.versions.node + ", server version: " +
+ new_client.server_info.redis_version + ", parser: " + new_client.reply_parser.name);
+ versions_logged = true;
+ }
+ self.ready_latency.update(Date.now() - new_client.create_time);
+ self.clients_ready++;
+ if (self.clients_ready === self.clients.length) {
+ self.on_clients_ready();
+ }
+ });
+
+ self.clients[id] = new_client;
+};
+
+Test.prototype.on_clients_ready = function () {
+ process.stdout.write(lpad(this.args.descr, 13) + ", " + lpad(this.args.pipeline, 5) + "/" + this.clients_ready + " ");
+ this.test_start = Date.now();
+
+ this.fill_pipeline();
+};
+
+Test.prototype.fill_pipeline = function () {
+ var pipeline = this.commands_sent - this.commands_completed;
+
+ while (this.commands_sent < num_requests && pipeline < this.max_pipeline) {
+ this.commands_sent++;
+ pipeline++;
+ this.send_next();
+ }
+
+ if (this.commands_completed === num_requests) {
+ this.print_stats();
+ this.stop_clients();
+ }
+};
+
+Test.prototype.stop_clients = function () {
+ var self = this;
+
+ this.clients.forEach(function (client, pos) {
+ if (pos === self.clients.length - 1) {
+ client.quit(function (err, res) {
+ self.callback();
+ });
+ } else {
+ client.quit();
+ }
+ });
+};
+
+Test.prototype.send_next = function () {
+ var self = this,
+ cur_client = this.commands_sent % this.clients.length,
+ command_num = this.commands_sent,
+ start = Date.now();
+
+ this.clients[cur_client][this.args.command](this.args.args, function (err, res) {
+ if (err) {
+ throw err;
+ }
+ self.commands_completed++;
+ self.command_latency.update(Date.now() - start);
+ self.fill_pipeline();
+ });
+};
+
+Test.prototype.print_stats = function () {
+ var duration = Date.now() - this.test_start;
+
+ console.log("min/max/avg/p95: " + this.command_latency.print_line() + " " + lpad(duration, 6) + "ms total, " +
+ lpad((num_requests / (duration / 1000)).toFixed(2), 8) + " ops/sec");
+};
+
+small_str = "1234";
+small_buf = new Buffer(small_str);
+large_str = (new Array(4097).join("-"));
+large_buf = new Buffer(large_str);
+
+tests.push(new Test({descr: "PING", command: "ping", args: [], pipeline: 1}));
+tests.push(new Test({descr: "PING", command: "ping", args: [], pipeline: 50}));
+tests.push(new Test({descr: "PING", command: "ping", args: [], pipeline: 200}));
+tests.push(new Test({descr: "PING", command: "ping", args: [], pipeline: 20000}));
+
+tests.push(new Test({descr: "SET small str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 1}));
+tests.push(new Test({descr: "SET small str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 50}));
+tests.push(new Test({descr: "SET small str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 200}));
+tests.push(new Test({descr: "SET small str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 20000}));
+
+tests.push(new Test({descr: "SET small buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 1}));
+tests.push(new Test({descr: "SET small buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 50}));
+tests.push(new Test({descr: "SET small buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 200}));
+tests.push(new Test({descr: "SET small buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 20000}));
+
+tests.push(new Test({descr: "GET small str", command: "get", args: ["foo_rand000000000000"], pipeline: 1}));
+tests.push(new Test({descr: "GET small str", command: "get", args: ["foo_rand000000000000"], pipeline: 50}));
+tests.push(new Test({descr: "GET small str", command: "get", args: ["foo_rand000000000000"], pipeline: 200}));
+tests.push(new Test({descr: "GET small str", command: "get", args: ["foo_rand000000000000"], pipeline: 20000}));
+
+tests.push(new Test({descr: "GET small buf", command: "get", args: ["foo_rand000000000000"], pipeline: 1, client_opts: { return_buffers: true} }));
+tests.push(new Test({descr: "GET small buf", command: "get", args: ["foo_rand000000000000"], pipeline: 50, client_opts: { return_buffers: true} }));
+tests.push(new Test({descr: "GET small buf", command: "get", args: ["foo_rand000000000000"], pipeline: 200, client_opts: { return_buffers: true} }));
+tests.push(new Test({descr: "GET small buf", command: "get", args: ["foo_rand000000000000"], pipeline: 20000, client_opts: { return_buffers: true} }));
+
+tests.push(new Test({descr: "SET large str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 1}));
+tests.push(new Test({descr: "SET large str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 50}));
+tests.push(new Test({descr: "SET large str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 200}));
+tests.push(new Test({descr: "SET large str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 20000}));
+
+tests.push(new Test({descr: "SET large buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 1}));
+tests.push(new Test({descr: "SET large buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 50}));
+tests.push(new Test({descr: "SET large buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 200}));
+tests.push(new Test({descr: "SET large buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 20000}));
+
+tests.push(new Test({descr: "GET large str", command: "get", args: ["foo_rand000000000001"], pipeline: 1}));
+tests.push(new Test({descr: "GET large str", command: "get", args: ["foo_rand000000000001"], pipeline: 50}));
+tests.push(new Test({descr: "GET large str", command: "get", args: ["foo_rand000000000001"], pipeline: 200}));
+tests.push(new Test({descr: "GET large str", command: "get", args: ["foo_rand000000000001"], pipeline: 20000}));
+
+tests.push(new Test({descr: "GET large buf", command: "get", args: ["foo_rand000000000001"], pipeline: 1, client_opts: { return_buffers: true} }));
+tests.push(new Test({descr: "GET large buf", command: "get", args: ["foo_rand000000000001"], pipeline: 50, client_opts: { return_buffers: true} }));
+tests.push(new Test({descr: "GET large buf", command: "get", args: ["foo_rand000000000001"], pipeline: 200, client_opts: { return_buffers: true} }));
+tests.push(new Test({descr: "GET large buf", command: "get", args: ["foo_rand000000000001"], pipeline: 20000, client_opts: { return_buffers: true} }));
+
+tests.push(new Test({descr: "INCR", command: "incr", args: ["counter_rand000000000000"], pipeline: 1}));
+tests.push(new Test({descr: "INCR", command: "incr", args: ["counter_rand000000000000"], pipeline: 50}));
+tests.push(new Test({descr: "INCR", command: "incr", args: ["counter_rand000000000000"], pipeline: 200}));
+tests.push(new Test({descr: "INCR", command: "incr", args: ["counter_rand000000000000"], pipeline: 20000}));
+
+tests.push(new Test({descr: "LPUSH", command: "lpush", args: ["mylist", small_str], pipeline: 1}));
+tests.push(new Test({descr: "LPUSH", command: "lpush", args: ["mylist", small_str], pipeline: 50}));
+tests.push(new Test({descr: "LPUSH", command: "lpush", args: ["mylist", small_str], pipeline: 200}));
+tests.push(new Test({descr: "LPUSH", command: "lpush", args: ["mylist", small_str], pipeline: 20000}));
+
+tests.push(new Test({descr: "LRANGE 10", command: "lrange", args: ["mylist", "0", "9"], pipeline: 1}));
+tests.push(new Test({descr: "LRANGE 10", command: "lrange", args: ["mylist", "0", "9"], pipeline: 50}));
+tests.push(new Test({descr: "LRANGE 10", command: "lrange", args: ["mylist", "0", "9"], pipeline: 200}));
+tests.push(new Test({descr: "LRANGE 10", command: "lrange", args: ["mylist", "0", "9"], pipeline: 20000}));
+
+tests.push(new Test({descr: "LRANGE 100", command: "lrange", args: ["mylist", "0", "99"], pipeline: 1}));
+tests.push(new Test({descr: "LRANGE 100", command: "lrange", args: ["mylist", "0", "99"], pipeline: 50}));
+tests.push(new Test({descr: "LRANGE 100", command: "lrange", args: ["mylist", "0", "99"], pipeline: 200}));
+tests.push(new Test({descr: "LRANGE 100", command: "lrange", args: ["mylist", "0", "99"], pipeline: 20000}));
+
+function next() {
+ var test = tests.shift();
+ if (test) {
+ test.run(function () {
+ next();
+ });
+ } else {
+ console.log("End of tests.");
+ process.exit(0);
+ }
+}
+
+next();
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/package.json b/signaling-server/node_modules/socket.io/node_modules/redis/package.json
new file mode 100644
index 0000000..ac6a398
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/package.json
@@ -0,0 +1,48 @@
+{
+ "name": "redis",
+ "version": "0.7.3",
+ "description": "Redis client library",
+ "author": {
+ "name": "Matt Ranney",
+ "email": "mjr@ranney.com"
+ },
+ "maintainers": [
+ {
+ "name": "mjr",
+ "email": "mjr@ranney.com"
+ }
+ ],
+ "main": "./index.js",
+ "scripts": {
+ "test": "node ./test.js"
+ },
+ "devDependencies": {
+ "metrics": ">=0.1.5"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/mranney/node_redis.git"
+ },
+ "_npmUser": {
+ "name": "mjr",
+ "email": "mjr@ranney.com"
+ },
+ "_id": "redis@0.7.3",
+ "dependencies": {},
+ "optionalDependencies": {},
+ "engines": {
+ "node": "*"
+ },
+ "_engineSupported": true,
+ "_npmVersion": "1.1.21",
+ "_nodeVersion": "v0.8.1",
+ "_defaultsLoaded": true,
+ "dist": {
+ "shasum": "ee57b7a44d25ec1594e44365d8165fa7d1d4811a",
+ "tarball": "http://registry.npmjs.org/redis/-/redis-0.7.3.tgz"
+ },
+ "directories": {},
+ "_shasum": "ee57b7a44d25ec1594e44365d8165fa7d1d4811a",
+ "_from": "redis@0.7.3",
+ "_resolved": "https://registry.npmjs.org/redis/-/redis-0.7.3.tgz"
+}
diff --git a/signaling-server/node_modules/socket.io/node_modules/redis/test.js b/signaling-server/node_modules/socket.io/node_modules/redis/test.js
new file mode 100644
index 0000000..0a03375
--- /dev/null
+++ b/signaling-server/node_modules/socket.io/node_modules/redis/test.js
@@ -0,0 +1,1618 @@
+/*global require console setTimeout process Buffer */
+var redis = require("./index"),
+ client = redis.createClient(),
+ client2 = redis.createClient(),
+ client3 = redis.createClient(),
+ assert = require("assert"),
+ crypto = require("crypto"),
+ util = require("./lib/util"),
+ test_db_num = 15, // this DB will be flushed and used for testing
+ tests = {},
+ connected = false,
+ ended = false,
+ next, cur_start, run_next_test, all_tests, all_start, test_count;
+
+// Set this to truthy to see the wire protocol and other debugging info
+redis.debug_mode = process.argv[2];
+
+function buffers_to_strings(arr) {
+ return arr.map(function (val) {
+ return val.toString();
+ });
+}
+
+function require_number(expected, label) {
+ return function (err, results) {
+ assert.strictEqual(null, err, label + " expected " + expected + ", got error: " + err);
+ assert.strictEqual(expected, results, label + " " + expected + " !== " + results);
+ assert.strictEqual(typeof results, "number", label);
+ return true;
+ };
+}
+
+function require_number_any(label) {
+ return function (err, results) {
+ assert.strictEqual(null, err, label + " expected any number, got error: " + err);
+ assert.strictEqual(typeof results, "number", label + " " + results + " is not a number");
+ return true;
+ };
+}
+
+function require_number_pos(label) {
+ return function (err, results) {
+ assert.strictEqual(null, err, label + " expected positive number, got error: " + err);
+ assert.strictEqual(true, (results > 0), label + " " + results + " is not a positive number");
+ return true;
+ };
+}
+
+function require_string(str, label) {
+ return function (err, results) {
+ assert.strictEqual(null, err, label + " expected string '" + str + "', got error: " + err);
+ assert.equal(str, results, label + " " + str + " does not match " + results);
+ return true;
+ };
+}
+
+function require_null(label) {
+ return function (err, results) {
+ assert.strictEqual(null, err, label + " expected null, got error: " + err);
+ assert.strictEqual(null, results, label + ": " + results + " is not null");
+ return true;
+ };
+}
+
+function require_error(label) {
+ return function (err, results) {
+ assert.notEqual(err, null, label + " err is null, but an error is expected here.");
+ return true;
+ };
+}
+
+function is_empty_array(obj) {
+ return Array.isArray(obj) && obj.length === 0;
+}
+
+function last(name, fn) {
+ return function (err, results) {
+ fn(err, results);
+ next(name);
+ };
+}
+
+next = function next(name) {
+ console.log(" \x1b[33m" + (Date.now() - cur_start) + "\x1b[0m ms");
+ run_next_test();
+};
+
+// Tests are run in the order they are defined. So FLUSHDB should be stay first.
+
+tests.FLUSHDB = function () {
+ var name = "FLUSHDB";
+ client.select(test_db_num, require_string("OK", name));
+ client2.select(test_db_num, require_string("OK", name));
+ client3.select(test_db_num, require_string("OK", name));
+ client.mset("flush keys 1", "flush val 1", "flush keys 2", "flush val 2", require_string("OK", name));
+ client.FLUSHDB(require_string("OK", name));
+ client.dbsize(last(name, require_number(0, name)));
+};
+
+tests.MULTI_1 = function () {
+ var name = "MULTI_1", multi1, multi2;
+
+ // Provoke an error at queue time
+ multi1 = client.multi();
+ multi1.mset("multifoo", "10", "multibar", "20", require_string("OK", name));
+ multi1.set("foo2", require_error(name));
+ multi1.incr("multifoo", require_number(11, name));
+ multi1.incr("multibar", require_number(21, name));
+ multi1.exec();
+
+ // Confirm that the previous command, while containing an error, still worked.
+ multi2 = client.multi();
+ multi2.incr("multibar", require_number(22, name));
+ multi2.incr("multifoo", require_number(12, name));
+ multi2.exec(function (err, replies) {
+ assert.strictEqual(22, replies[0]);
+ assert.strictEqual(12, replies[1]);
+ next(name);
+ });
+};
+
+tests.MULTI_2 = function () {
+ var name = "MULTI_2";
+
+ // test nested multi-bulk replies
+ client.multi([
+ ["mget", "multifoo", "multibar", function (err, res) {
+ assert.strictEqual(2, res.length, name);
+ assert.strictEqual("12", res[0].toString(), name);
+ assert.strictEqual("22", res[1].toString(), name);
+ }],
+ ["set", "foo2", require_error(name)],
+ ["incr", "multifoo", require_number(13, name)],
+ ["incr", "multibar", require_number(23, name)]
+ ]).exec(function (err, replies) {
+ assert.strictEqual(2, replies[0].length, name);
+ assert.strictEqual("12", replies[0][0].toString(), name);
+ assert.strictEqual("22", replies[0][1].toString(), name);
+
+ assert.strictEqual("13", replies[1].toString());
+ assert.strictEqual("23", replies[2].toString());
+ next(name);
+ });
+};
+
+tests.MULTI_3 = function () {
+ var name = "MULTI_3";
+
+ client.sadd("some set", "mem 1");
+ client.sadd("some set", "mem 2");
+ client.sadd("some set", "mem 3");
+ client.sadd("some set", "mem 4");
+
+ // make sure empty mb reply works
+ client.del("some missing set");
+ client.smembers("some missing set", function (err, reply) {
+ // make sure empty mb reply works
+ assert.strictEqual(true, is_empty_array(reply), name);
+ });
+
+ // test nested multi-bulk replies with empty mb elements.
+ client.multi([
+ ["smembers", "some set"],
+ ["del", "some set"],
+ ["smembers", "some set"]
+ ])
+ .scard("some set")
+ .exec(function (err, replies) {
+ assert.strictEqual(true, is_empty_array(replies[2]), name);
+ next(name);
+ });
+};
+
+tests.MULTI_4 = function () {
+ var name = "MULTI_4";
+
+ client.multi()
+ .mset('some', '10', 'keys', '20')
+ .incr('some')
+ .incr('keys')
+ .mget('some', 'keys')
+ .exec(function (err, replies) {
+ assert.strictEqual(null, err);
+ assert.equal('OK', replies[0]);
+ assert.equal(11, replies[1]);
+ assert.equal(21, replies[2]);
+ assert.equal(11, replies[3][0].toString());
+ assert.equal(21, replies[3][1].toString());
+ next(name);
+ });
+};
+
+tests.MULTI_5 = function () {
+ var name = "MULTI_5";
+
+ // test nested multi-bulk replies with nulls.
+ client.multi([
+ ["mget", ["multifoo", "some", "random value", "keys"]],
+ ["incr", "multifoo"]
+ ])
+ .exec(function (err, replies) {
+ assert.strictEqual(replies.length, 2, name);
+ assert.strictEqual(replies[0].length, 4, name);
+ next(name);
+ });
+};
+
+tests.MULTI_6 = function () {
+ var name = "MULTI_6";
+
+ client.multi()
+ .hmset("multihash", "a", "foo", "b", 1)
+ .hmset("multihash", {
+ extra: "fancy",
+ things: "here"
+ })
+ .hgetall("multihash")
+ .exec(function (err, replies) {
+ assert.strictEqual(null, err);
+ assert.equal("OK", replies[0]);
+ assert.equal(Object.keys(replies[2]).length, 4);
+ assert.equal("foo", replies[2].a);
+ assert.equal("1", replies[2].b);
+ assert.equal("fancy", replies[2].extra);
+ assert.equal("here", replies[2].things);
+ next(name);
+ });
+};
+
+tests.EVAL_1 = function () {
+ var name = "EVAL_1";
+
+ if (client.server_info.versions[0] >= 2 && client.server_info.versions[1] >= 5) {
+ // test {EVAL - Lua integer -> Redis protocol type conversion}
+ client.eval("return 100.5", 0, require_number(100, name));
+ // test {EVAL - Lua string -> Redis protocol type conversion}
+ client.eval("return 'hello world'", 0, require_string("hello world", name));
+ // test {EVAL - Lua true boolean -> Redis protocol type conversion}
+ client.eval("return true", 0, require_number(1, name));
+ // test {EVAL - Lua false boolean -> Redis protocol type conversion}
+ client.eval("return false", 0, require_null(name));
+ // test {EVAL - Lua status code reply -> Redis protocol type conversion}
+ client.eval("return {ok='fine'}", 0, require_string("fine", name));
+ // test {EVAL - Lua error reply -> Redis protocol type conversion}
+ client.eval("return {err='this is an error'}", 0, require_error(name));
+ // test {EVAL - Lua table -> Redis protocol type conversion}
+ client.eval("return {1,2,3,'ciao',{1,2}}", 0, function (err, res) {
+ assert.strictEqual(5, res.length, name);
+ assert.strictEqual(1, res[0], name);
+ assert.strictEqual(2, res[1], name);
+ assert.strictEqual(3, res[2], name);
+ assert.strictEqual("ciao", res[3], name);
+ assert.strictEqual(2, res[4].length, name);
+ assert.strictEqual(1, res[4][0], name);
+ assert.strictEqual(2, res[4][1], name);
+ });
+ // test {EVAL - Are the KEYS and ARGS arrays populated correctly?}
+ client.eval("return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", 2, "a", "b", "c", "d", function (err, res) {
+ assert.strictEqual(4, res.length, name);
+ assert.strictEqual("a", res[0], name);
+ assert.strictEqual("b", res[1], name);
+ assert.strictEqual("c", res[2], name);
+ assert.strictEqual("d", res[3], name);
+ });
+
+ // prepare sha sum for evalsha cache test
+ var source = "return redis.call('get', 'sha test')",
+ sha = crypto.createHash('sha1').update(source).digest('hex');
+
+ client.set("sha test", "eval get sha test", function (err, res) {
+ if (err) throw err;
+ // test {EVAL - is Lua able to call Redis API?}
+ client.eval(source, 0, function (err, res) {
+ require_string("eval get sha test", name)(err, res);
+ // test {EVALSHA - Can we call a SHA1 if already defined?}
+ client.evalsha(sha, 0, require_string("eval get sha test", name));
+ // test {EVALSHA - Do we get an error on non defined SHA1?}
+ client.evalsha("ffffffffffffffffffffffffffffffffffffffff", 0, require_error(name));
+ });
+ });
+
+ // test {EVAL - Redis integer -> Lua type conversion}
+ client.set("incr key", 0, function (err, reply) {
+ if (err) throw err;
+ client.eval("local foo = redis.call('incr','incr key')\n" + "return {type(foo),foo}", 0, function (err, res) {
+ if (err) throw err;
+ assert.strictEqual(2, res.length, name);
+ assert.strictEqual("number", res[0], name);
+ assert.strictEqual(1, res[1], name);
+ });
+ });
+
+ client.set("bulk reply key", "bulk reply value", function (err, res) {
+ // test {EVAL - Redis bulk -> Lua type conversion}
+ client.eval("local foo = redis.call('get','bulk reply key'); return {type(foo),foo}", 0, function (err, res) {
+ if (err) throw err;
+ assert.strictEqual(2, res.length, name);
+ assert.strictEqual("string", res[0], name);
+ assert.strictEqual("bulk reply value", res[1], name);
+ });
+ });
+
+ // test {EVAL - Redis multi bulk -> Lua type conversion}
+ client.multi()
+ .del("mylist")
+ .rpush("mylist", "a")
+ .rpush("mylist", "b")
+ .rpush("mylist", "c")
+ .exec(function (err, replies) {
+ if (err) throw err;
+ client.eval("local foo = redis.call('lrange','mylist',0,-1); return {type(foo),foo[1],foo[2],foo[3],# foo}", 0, function (err, res) {
+ assert.strictEqual(5, res.length, name);
+ assert.strictEqual("table", res[0], name);
+ assert.strictEqual("a", res[1], name);
+ assert.strictEqual("b", res[2], name);
+ assert.strictEqual("c", res[3], name);
+ assert.strictEqual(3, res[4], name);
+ });
+ });
+ // test {EVAL - Redis status reply -> Lua type conversion}
+ client.eval("local foo = redis.call('set','mykey','myval'); return {type(foo),foo['ok']}", 0, function (err, res) {
+ if (err) throw err;
+ assert.strictEqual(2, res.length, name);
+ assert.strictEqual("table", res[0], name);
+ assert.strictEqual("OK", res[1], name);
+ });
+ // test {EVAL - Redis error reply -> Lua type conversion}
+ client.set("error reply key", "error reply value", function (err, res) {
+ if (err) throw err;
+ client.eval("local foo = redis.pcall('incr','error reply key'); return {type(foo),foo['err']}", 0, function (err, res) {
+ if (err) throw err;
+ assert.strictEqual(2, res.length, name);
+ assert.strictEqual("table", res[0], name);
+ assert.strictEqual("ERR value is not an integer or out of range", res[1], name);
+ });
+ });
+ // test {EVAL - Redis nil bulk reply -> Lua type conversion}
+ client.del("nil reply key", function (err, res) {
+ if (err) throw err;
+ client.eval("local foo = redis.call('get','nil reply key'); return {type(foo),foo == false}", 0, function (err, res) {
+ if (err) throw err;
+ assert.strictEqual(2, res.length, name);
+ assert.strictEqual("boolean", res[0], name);
+ assert.strictEqual(1, res[1], name);
+ next(name);
+ });
+ });
+ } else {
+ console.log("Skipping " + name + " because server version isn't new enough.");
+ next(name);
+ }
+};
+
+tests.WATCH_MULTI = function () {
+ var name = 'WATCH_MULTI', multi;
+
+ if (client.server_info.versions[0] >= 2 && client.server_info.versions[1] >= 1) {
+ client.watch(name);
+ client.incr(name);
+ multi = client.multi();
+ multi.incr(name);
+ multi.exec(last(name, require_null(name)));
+ } else {
+ console.log("Skipping " + name + " because server version isn't new enough.");
+ next(name);
+ }
+};
+
+tests.detect_buffers = function () {
+ var name = "detect_buffers", detect_client = redis.createClient(null, null, {detect_buffers: true});
+
+ detect_client.on("ready", function () {
+ // single Buffer or String
+ detect_client.set("string key 1", "string value");
+ detect_client.get("string key 1", require_string("string value", name));
+ detect_client.get(new Buffer("string key 1"), function (err, reply) {
+ assert.strictEqual(null, err, name);
+ assert.strictEqual(true, Buffer.isBuffer(reply), name);
+ assert.strictEqual("<Buffer 73 74 72 69 6e 67 20 76 61 6c 75 65>", reply.inspect(), name);
+ });
+
+ detect_client.hmset("hash key 2", "key 1", "val 1", "key 2", "val 2");
+ // array of Buffers or Strings
+ detect_client.hmget("hash key 2", "key 1", "key 2", function (err, reply) {
+ assert.strictEqual(null, err, name);
+ assert.strictEqual(true, Array.isArray(reply), name);
+ assert.strictEqual(2, reply.length, name);
+ assert.strictEqual("val 1", reply[0], name);
+ assert.strictEqual("val 2", reply[1], name);
+ });
+ detect_client.hmget(new Buffer("hash key 2"), "key 1", "key 2", function (err, reply) {
+ assert.strictEqual(null, err, name);
+ assert.strictEqual(true, Array.isArray(reply));
+ assert.strictEqual(2, reply.length, name);
+ assert.strictEqual(true, Buffer.isBuffer(reply[0]));
+ assert.strictEqual(true, Buffer.isBuffer(reply[1]));
+ assert.strictEqual("<Buffer 76 61 6c 20 31>", reply[0].inspect(), name);
+ assert.strictEqual("<Buffer 76 61 6c 20 32>", reply[1].inspect(), name);
+ });
+
+ // Object of Buffers or Strings
+ detect_client.hgetall("hash key 2", function (err, reply) {
+ assert.strictEqual(null, err, name);
+ assert.strictEqual("object", typeof reply, name);
+ assert.strictEqual(2, Object.keys(reply).length, name);
+ assert.strictEqual("val 1", reply["key 1"], name);
+ assert.strictEqual("val 2", reply["key 2"], name);
+ });
+ detect_client.hgetall(new Buffer("hash key 2"), function (err, reply) {
+ assert.strictEqual(null, err, name);
+ assert.strictEqual("object", typeof reply, name);
+ assert.strictEqual(2, Object.keys(reply).length, name);
+ assert.strictEqual(true, Buffer.isBuffer(reply["key 1"]));
+ assert.strictEqual(true, Buffer.isBuffer(reply["key 2"]));
+ assert.strictEqual("<Buffer 76 61 6c 20 31>", reply["key 1"].inspect(), name);
+ assert.strictEqual("<Buffer 76 61 6c 20 32>", reply["key 2"].inspect(), name);
+ });
+
+ detect_client.quit(function (err, res) {
+ next(name);
+ });
+ });
+};
+
+tests.socket_nodelay = function () {
+ var name = "socket_nodelay", c1, c2, c3, ready_count = 0, quit_count = 0;
+
+ c1 = redis.createClient(null, null, {socket_nodelay: true});
+ c2 = redis.createClient(null, null, {socket_nodelay: false});
+ c3 = redis.createClient(null, null);
+
+ function quit_check() {
+ quit_count++;
+
+ if (quit_count === 3) {
+ next(name);
+ }
+ }
+
+ function run() {
+ assert.strictEqual(true, c1.options.socket_nodelay, name);
+ assert.strictEqual(false, c2.options.socket_nodelay, name);
+ assert.strictEqual(true, c3.options.socket_nodelay, name);
+
+ c1.set(["set key 1", "set val"], require_string("OK", name));
+ c1.set(["set key 2", "set val"], require_string("OK", name));
+ c1.get(["set key 1"], require_string("set val", name));
+ c1.get(["set key 2"], require_string("set val", name));
+
+ c2.set(["set key 3", "set val"], require_string("OK", name));
+ c2.set(["set key 4", "set val"], require_string("OK", name));
+ c2.get(["set key 3"], require_string("set val", name));
+ c2.get(["set key 4"], require_string("set val", name));
+
+ c3.set(["set key 5", "set val"], require_string("OK", name));
+ c3.set(["set key 6", "set val"], require_string("OK", name));
+ c3.get(["set key 5"], require_string("set val", name));
+ c3.get(["set key 6"], require_string("set val", name));
+
+ c1.quit(quit_check);
+ c2.quit(quit_check);
+ c3.quit(quit_check);
+ }
+
+ function ready_check() {
+ ready_count++;
+ if (ready_count === 3) {
+ run();
+ }
+ }
+
+ c1.on("ready", ready_check);
+ c2.on("ready", ready_check);
+ c3.on("ready", ready_check);
+};
+
+tests.reconnect = function () {
+ var name = "reconnect";
+
+ client.set("recon 1", "one");
+ client.set("recon 2", "two", function (err, res) {
+ // Do not do this in normal programs. This is to simulate the server closing on us.
+ // For orderly shutdown in normal programs, do client.quit()
+ client.stream.destroy();
+ });
+
+ client.on("reconnecting", function on_recon(params) {
+ client.on("connect", function on_connect() {
+ client.select(test_db_num, require_string("OK", name));
+ client.get("recon 1", require_string("one", name));
+ client.get("recon 1", require_string("one", name));
+ client.get("recon 2", require_string("two", name));
+ client.get("recon 2", require_string("two", name));
+ client.removeListener("connect", on_connect);
+ client.removeListener("reconnecting", on_recon);
+ next(name);
+ });
+ });
+};
+
+tests.idle = function () {
+ var name = "idle";
+
+ client.on("idle", function on_idle() {
+ client.removeListener("idle", on_idle);
+ next(name);
+ });
+
+ client.set("idle", "test");
+};
+
+tests.HSET = function () {
+ var key = "test hash",
+ field1 = new Buffer("0123456789"),
+ value1 = new Buffer("abcdefghij"),
+ field2 = new Buffer(0),
+ value2 = new Buffer(0),
+ name = "HSET";
+
+ client.HSET(key, field1, value1, require_number(1, name));
+ client.HGET(key, field1, require_string(value1.toString(), name));
+
+ // Empty value
+ client.HSET(key, field1, value2, require_number(0, name));
+ client.HGET([key, field1], require_string("", name));
+
+ // Empty key, empty value
+ client.HSET([key, field2, value1], require_number(1, name));
+ client.HSET(key, field2, value2, last(name, require_number(0, name)));
+};
+
+tests.HLEN = function () {
+ var key = "test hash",
+ field1 = new Buffer("0123456789"),
+ value1 = new Buffer("abcdefghij"),
+ field2 = new Buffer(0),
+ value2 = new Buffer(0),
+ name = "HSET",
+ timeout = 1000;
+
+ client.HSET(key, field1, value1, function (err, results) {
+ client.HLEN(key, function (err, len) {
+ assert.ok(2 === +len);
+ next(name);
+ });
+ });
+}
+
+tests.HMSET_BUFFER_AND_ARRAY = function () {
+ // Saving a buffer and an array to the same key should not error
+ var key = "test hash",
+ field1 = "buffer",
+ value1 = new Buffer("abcdefghij"),
+ field2 = "array",
+ value2 = ["array contents"],
+ name = "HSET";
+
+ client.HMSET(key, field1, value1, field2, value2, last(name, require_string("OK", name)));
+};
+
+// TODO - add test for HMSET with optional callbacks
+
+tests.HMGET = function () {
+ var key1 = "test hash 1", key2 = "test hash 2", name = "HMGET";
+
+ // redis-like hmset syntax
+ client.HMSET(key1, "0123456789", "abcdefghij", "some manner of key", "a type of value", require_string("OK", name));
+
+ // fancy hmset syntax
+ client.HMSET(key2, {
+ "0123456789": "abcdefghij",
+ "some manner of key": "a type of value"
+ }, require_string("OK", name));
+
+ client.HMGET(key1, "0123456789", "some manner of key", function (err, reply) {
+ assert.strictEqual("abcdefghij", reply[0].toString(), name);
+ assert.strictEqual("a type of value", reply[1].toString(), name);
+ });
+
+ client.HMGET(key2, "0123456789", "some manner of key", function (err, reply) {
+ assert.strictEqual("abcdefghij", reply[0].toString(), name);
+ assert.strictEqual("a type of value", reply[1].toString(), name);
+ });
+
+ client.HMGET(key1, ["0123456789"], function (err, reply) {
+ assert.strictEqual("abcdefghij", reply[0], name);
+ });
+
+ client.HMGET(key1, ["0123456789", "some manner of key"], function (err, reply) {
+ assert.strictEqual("abcdefghij", reply[0], name);
+ assert.strictEqual("a type of value", reply[1], name);
+ });
+
+ client.HMGET(key1, "missing thing", "another missing thing", function (err, reply) {
+ assert.strictEqual(null, reply[0], name);
+ assert.strictEqual(null, reply[1], name);
+ next(name);
+ });
+};
+
+tests.HINCRBY = function () {
+ var name = "HINCRBY";
+ client.hset("hash incr", "value", 10, require_number(1, name));
+ client.HINCRBY("hash incr", "value", 1, require_number(11, name));
+ client.HINCRBY("hash incr", "value 2", 1, last(name, require_number(1, name)));
+};
+
+tests.SUBSCRIBE = function () {
+ var client1 = client, msg_count = 0, name = "SUBSCRIBE";
+
+ client1.on("subscribe", function (channel, count) {
+ if (channel === "chan1") {
+ client2.publish("chan1", "message 1", require_number(1, name));
+ client2.publish("chan2", "message 2", require_number(1, name));
+ client2.publish("chan1", "message 3", require_number(1, name));
+ }
+ });
+
+ client1.on("unsubscribe", function (channel, count) {
+ if (count === 0) {
+ // make sure this connection can go into and out of pub/sub mode
+ client1.incr("did a thing", last(name, require_number(2, name)));
+ }
+ });
+
+ client1.on("message", function (channel, message) {
+ msg_count += 1;
+ assert.strictEqual("message " + msg_count, message.toString());
+ if (msg_count === 3) {
+ client1.unsubscribe("chan1", "chan2");
+ }
+ });
+
+ client1.set("did a thing", 1, require_string("OK", name));
+ client1.subscribe("chan1", "chan2", function (err, results) {
+ assert.strictEqual(null, err, "result sent back unexpected error: " + err);
+ assert.strictEqual("chan1", results.toString(), name);
+ });
+};
+
+tests.SUB_UNSUB_SUB = function () {
+ var name = "SUB_UNSUB_SUB";
+ client3.subscribe('chan3');
+ client3.unsubscribe('chan3');
+ client3.subscribe('chan3', function (err, results) {
+ assert.strictEqual(null, err, "unexpected error: " + err);
+ client2.publish('chan3', 'foo');
+ });
+ client3.on('message', function (channel, message) {
+ assert.strictEqual(channel, 'chan3');
+ assert.strictEqual(message, 'foo');
+ next(name);
+ });
+};
+
+tests.SUBSCRIBE_QUIT = function () {
+ var name = "SUBSCRIBE_QUIT";
+ client3.on("end", function () {
+ next(name);
+ });
+ client3.on("subscribe", function (channel, count) {
+ client3.quit();
+ });
+ client3.subscribe("chan3");
+};
+
+tests.SUBSCRIBE_CLOSE_RESUBSCRIBE = function () {
+ var name = "SUBSCRIBE_CLOSE_RESUBSCRIBE";
+ var c1 = redis.createClient();
+ var c2 = redis.createClient();
+ var count = 0;
+
+ /* Create two clients. c1 subscribes to two channels, c2 will publish to them.
+ c2 publishes the first message.
+ c1 gets the message and drops its connection. It must resubscribe itself.
+ When it resubscribes, c2 publishes the second message, on the same channel
+ c1 gets the message and drops its connection. It must resubscribe itself, again.
+ When it resubscribes, c2 publishes the third message, on the second channel
+ c1 gets the message and drops its connection. When it reconnects, the test ends.
+ */
+
+ c1.on("message", function(channel, message) {
+ if (channel === "chan1") {
+ assert.strictEqual(message, "hi on channel 1");
+ c1.stream.end();
+
+ } else if (channel === "chan2") {
+ assert.strictEqual(message, "hi on channel 2");
+ c1.stream.end();
+
+ } else {
+ c1.quit();
+ c2.quit();
+ assert.fail("test failed");
+ }
+ })
+
+ c1.subscribe("chan1", "chan2");
+
+ c2.once("ready", function() {
+ console.log("c2 is ready");
+ c1.on("ready", function(err, results) {
+ console.log("c1 is ready", count);
+
+ count++;
+ if (count == 1) {
+ c2.publish("chan1", "hi on channel 1");
+ return;
+
+ } else if (count == 2) {
+ c2.publish("chan2", "hi on channel 2");
+
+ } else {
+ c1.quit(function() {
+ c2.quit(function() {
+ next(name);
+ });
+ });
+ }
+ });
+
+ c2.publish("chan1", "hi on channel 1");
+
+ });
+};
+
+tests.EXISTS = function () {
+ var name = "EXISTS";
+ client.del("foo", "foo2", require_number_any(name));
+ client.set("foo", "bar", require_string("OK", name));
+ client.EXISTS("foo", require_number(1, name));
+ client.EXISTS("foo2", last(name, require_number(0, name)));
+};
+
+tests.DEL = function () {
+ var name = "DEL";
+ client.DEL("delkey", require_number_any(name));
+ client.set("delkey", "delvalue", require_string("OK", name));
+ client.DEL("delkey", require_number(1, name));
+ client.exists("delkey", require_number(0, name));
+ client.DEL("delkey", require_number(0, name));
+ client.mset("delkey", "delvalue", "delkey2", "delvalue2", require_string("OK", name));
+ client.DEL("delkey", "delkey2", last(name, require_number(2, name)));
+};
+
+tests.TYPE = function () {
+ var name = "TYPE";
+ client.set(["string key", "should be a string"], require_string("OK", name));
+ client.rpush(["list key", "should be a list"], require_number_pos(name));
+ client.sadd(["set key", "should be a set"], require_number_any(name));
+ client.zadd(["zset key", "10.0", "should be a zset"], require_number_any(name));
+ client.hset(["hash key", "hashtest", "should be a hash"], require_number_any(0, name));
+
+ client.TYPE(["string key"], require_string("string", name));
+ client.TYPE(["list key"], require_string("list", name));
+ client.TYPE(["set key"], require_string("set", name));
+ client.TYPE(["zset key"], require_string("zset", name));
+ client.TYPE("not here yet", require_string("none", name));
+ client.TYPE(["hash key"], last(name, require_string("hash", name)));
+};
+
+tests.KEYS = function () {
+ var name = "KEYS";
+ client.mset(["test keys 1", "test val 1", "test keys 2", "test val 2"], require_string("OK", name));
+ client.KEYS(["test keys*"], function (err, results) {
+ assert.strictEqual(null, err, "result sent back unexpected error: " + err);
+ assert.strictEqual(2, results.length, name);
+ assert.strictEqual("test keys 1", results[0].toString(), name);
+ assert.strictEqual("test keys 2", results[1].toString(), name);
+ next(name);
+ });
+};
+
+tests.MULTIBULK_ZERO_LENGTH = function () {
+ var name = "MULTIBULK_ZERO_LENGTH";
+ client.KEYS(['users:*'], function (err, results) {
+ assert.strictEqual(null, err, 'error on empty multibulk reply');
+ assert.strictEqual(true, is_empty_array(results), "not an empty array");
+ next(name);
+ });
+};
+
+tests.RANDOMKEY = function () {
+ var name = "RANDOMKEY";
+ client.mset(["test keys 1", "test val 1", "test keys 2", "test val 2"], require_string("OK", name));
+ client.RANDOMKEY([], function (err, results) {
+ assert.strictEqual(null, err, name + " result sent back unexpected error: " + err);
+ assert.strictEqual(true, /\w+/.test(results), name);
+ next(name);
+ });
+};
+
+tests.RENAME = function () {
+ var name = "RENAME";
+ client.set(['foo', 'bar'], require_string("OK", name));
+ client.RENAME(["foo", "new foo"], require_string("OK", name));
+ client.exists(["foo"], require_number(0, name));
+ client.exists(["new foo"], last(name, require_number(1, name)));
+};
+
+tests.RENAMENX = function () {
+ var name = "RENAMENX";
+ client.set(['foo', 'bar'], require_string("OK", name));
+ client.set(['foo2', 'bar2'], require_string("OK", name));
+ client.RENAMENX(["foo", "foo2"], require_number(0, name));
+ client.exists(["foo"], require_number(1, name));
+ client.exists(["foo2"], require_number(1, name));
+ client.del(["foo2"], require_number(1, name));
+ client.RENAMENX(["foo", "foo2"], require_number(1, name));
+ client.exists(["foo"], require_number(0, name));
+ client.exists(["foo2"], last(name, require_number(1, name)));
+};
+
+tests.DBSIZE = function () {
+ var name = "DBSIZE";
+ client.set(['foo', 'bar'], require_string("OK", name));
+ client.DBSIZE([], last(name, require_number_pos("DBSIZE")));
+};
+
+tests.GET = function () {
+ var name = "GET";
+ client.set(["get key", "get val"], require_string("OK", name));
+ client.GET(["get key"], last(name, require_string("get val", name)));
+};
+
+tests.SET = function () {
+ var name = "SET";
+ client.SET(["set key", "set val"], require_string("OK", name));
+ client.get(["set key"], last(name, require_string("set val", name)));
+};
+
+tests.GETSET = function () {
+ var name = "GETSET";
+ client.set(["getset key", "getset val"], require_string("OK", name));
+ client.GETSET(["getset key", "new getset val"], require_string("getset val", name));
+ client.get(["getset key"], last(name, require_string("new getset val", name)));
+};
+
+tests.MGET = function () {
+ var name = "MGET";
+ client.mset(["mget keys 1", "mget val 1", "mget keys 2", "mget val 2", "mget keys 3", "mget val 3"], require_string("OK", name));
+ client.MGET("mget keys 1", "mget keys 2", "mget keys 3", function (err, results) {
+ assert.strictEqual(null, err, "result sent back unexpected error: " + err);
+ assert.strictEqual(3, results.length, name);
+ assert.strictEqual("mget val 1", results[0].toString(), name);
+ assert.strictEqual("mget val 2", results[1].toString(), name);
+ assert.strictEqual("mget val 3", results[2].toString(), name);
+ });
+ client.MGET(["mget keys 1", "mget keys 2", "mget keys 3"], function (err, results) {
+ assert.strictEqual(null, err, "result sent back unexpected error: " + err);
+ assert.strictEqual(3, results.length, name);
+ assert.strictEqual("mget val 1", results[0].toString(), name);
+ assert.strictEqual("mget val 2", results[1].toString(), name);
+ assert.strictEqual("mget val 3", results[2].toString(), name);
+ });
+ client.MGET(["mget keys 1", "some random shit", "mget keys 2", "mget keys 3"], function (err, results) {
+ assert.strictEqual(null, err, "result sent back unexpected error: " + err);
+ assert.strictEqual(4, results.length, name);
+ assert.strictEqual("mget val 1", results[0].toString(), name);
+ assert.strictEqual(null, results[1], name);
+ assert.strictEqual("mget val 2", results[2].toString(), name);
+ assert.strictEqual("mget val 3", results[3].toString(), name);
+ next(name);
+ });
+};
+
+tests.SETNX = function () {
+ var name = "SETNX";
+ client.set(["setnx key", "setnx value"], require_string("OK", name));
+ client.SETNX(["setnx key", "new setnx value"], require_number(0, name));
+ client.del(["setnx key"], require_number(1, name));
+ client.exists(["setnx key"], require_number(0, name));
+ client.SETNX(["setnx key", "new setnx value"], require_number(1, name));
+ client.exists(["setnx key"], last(name, require_number(1, name)));
+};
+
+tests.SETEX = function () {
+ var name = "SETEX";
+ client.SETEX(["setex key", "100", "setex val"], require_string("OK", name));
+ client.exists(["setex key"], require_number(1, name));
+ client.ttl(["setex key"], last(name, require_number_pos(name)));
+};
+
+tests.MSETNX = function () {
+ var name = "MSETNX";
+ client.mset(["mset1", "val1", "mset2", "val2", "mset3", "val3"], require_string("OK", name));
+ client.MSETNX(["mset3", "val3", "mset4", "val4"], require_number(0, name));
+ client.del(["mset3"], require_number(1, name));
+ client.MSETNX(["mset3", "val3", "mset4", "val4"], require_number(1, name));
+ client.exists(["mset3"], require_number(1, name));
+ client.exists(["mset4"], last(name, require_number(1, name)));
+};
+
+tests.HGETALL = function () {
+ var name = "HGETALL";
+ client.hmset(["hosts", "mjr", "1", "another", "23", "home", "1234"], require_string("OK", name));
+ client.HGETALL(["hosts"], function (err, obj) {
+ assert.strictEqual(null, err, name + " result sent back unexpected error: " + err);
+ assert.strictEqual(3, Object.keys(obj).length, name);
+ assert.strictEqual("1", obj.mjr.toString(), name);
+ assert.strictEqual("23", obj.another.toString(), name);
+ assert.strictEqual("1234", obj.home.toString(), name);
+ next(name);
+ });
+};
+
+tests.HGETALL_NULL = function () {
+ var name = "HGETALL_NULL";
+
+ client.hgetall("missing", function (err, obj) {
+ assert.strictEqual(null, err);
+ assert.strictEqual(null, obj);
+ next(name);
+ });
+};
+
+tests.UTF8 = function () {
+ var name = "UTF8",
+ utf8_sample = "ಠ_ಠ";
+
+ client.set(["utf8test", utf8_sample], require_string("OK", name));
+ client.get(["utf8test"], function (err, obj) {
+ assert.strictEqual(null, err);
+ assert.strictEqual(utf8_sample, obj);
+ next(name);
+ });
+};
+
+// Set tests were adapted from Brian Hammond's redis-node-client.js, which has a comprehensive test suite
+
+tests.SADD = function () {
+ var name = "SADD";
+
+ client.del('set0');
+ client.SADD('set0', 'member0', require_number(1, name));
+ client.sadd('set0', 'member0', last(name, require_number(0, name)));
+};
+
+tests.SADD2 = function () {
+ var name = "SADD2";
+
+ client.del("set0");
+ client.sadd("set0", ["member0", "member1", "member2"], require_number(3, name));
+ client.smembers("set0", function (err, res) {
+ assert.strictEqual(res.length, 3);
+ assert.strictEqual(res[0], "member0");
+ assert.strictEqual(res[1], "member1");
+ assert.strictEqual(res[2], "member2");
+ });
+ client.SADD("set1", ["member0", "member1", "member2"], require_number(3, name));
+ client.smembers("set1", function (err, res) {
+ assert.strictEqual(res.length, 3);
+ assert.strictEqual(res[0], "member0");
+ assert.strictEqual(res[1], "member1");
+ assert.strictEqual(res[2], "member2");
+ next(name);
+ });
+};
+
+tests.SISMEMBER = function () {
+ var name = "SISMEMBER";
+
+ client.del('set0');
+ client.sadd('set0', 'member0', require_number(1, name));
+ client.sismember('set0', 'member0', require_number(1, name));
+ client.sismember('set0', 'member1', last(name, require_number(0, name)));
+};
+
+tests.SCARD = function () {
+ var name = "SCARD";
+
+ client.del('set0');
+ client.sadd('set0', 'member0', require_number(1, name));
+ client.scard('set0', require_number(1, name));
+ client.sadd('set0', 'member1', require_number(1, name));
+ client.scard('set0', last(name, require_number(2, name)));
+};
+
+tests.SREM = function () {
+ var name = "SREM";
+
+ client.del('set0');
+ client.sadd('set0', 'member0', require_number(1, name));
+ client.srem('set0', 'foobar', require_number(0, name));
+ client.srem('set0', 'member0', require_number(1, name));
+ client.scard('set0', last(name, require_number(0, name)));
+};
+
+tests.SPOP = function () {
+ var name = "SPOP";
+
+ client.del('zzz');
+ client.sadd('zzz', 'member0', require_number(1, name));
+ client.scard('zzz', require_number(1, name));
+
+ client.spop('zzz', function (err, value) {
+ if (err) {
+ assert.fail(err);
+ }
+ assert.equal(value, 'member0', name);
+ });
+
+ client.scard('zzz', last(name, require_number(0, name)));
+};
+
+tests.SDIFF = function () {
+ var name = "SDIFF";
+
+ client.del('foo');
+ client.sadd('foo', 'x', require_number(1, name));
+ client.sadd('foo', 'a', require_number(1, name));
+ client.sadd('foo', 'b', require_number(1, name));
+ client.sadd('foo', 'c', require_number(1, name));
+
+ client.sadd('bar', 'c', require_number(1, name));
+
+ client.sadd('baz', 'a', require_number(1, name));
+ client.sadd('baz', 'd', require_number(1, name));
+
+ client.sdiff('foo', 'bar', 'baz', function (err, values) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ values.sort();
+ assert.equal(values.length, 2, name);
+ assert.equal(values[0], 'b', name);
+ assert.equal(values[1], 'x', name);
+ next(name);
+ });
+};
+
+tests.SDIFFSTORE = function () {
+ var name = "SDIFFSTORE";
+
+ client.del('foo');
+ client.del('bar');
+ client.del('baz');
+ client.del('quux');
+
+ client.sadd('foo', 'x', require_number(1, name));
+ client.sadd('foo', 'a', require_number(1, name));
+ client.sadd('foo', 'b', require_number(1, name));
+ client.sadd('foo', 'c', require_number(1, name));
+
+ client.sadd('bar', 'c', require_number(1, name));
+
+ client.sadd('baz', 'a', require_number(1, name));
+ client.sadd('baz', 'd', require_number(1, name));
+
+ // NB: SDIFFSTORE returns the number of elements in the dstkey
+
+ client.sdiffstore('quux', 'foo', 'bar', 'baz', require_number(2, name));
+
+ client.smembers('quux', function (err, values) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ var members = buffers_to_strings(values).sort();
+
+ assert.deepEqual(members, [ 'b', 'x' ], name);
+ next(name);
+ });
+};
+
+tests.SMEMBERS = function () {
+ var name = "SMEMBERS";
+
+ client.del('foo');
+ client.sadd('foo', 'x', require_number(1, name));
+
+ client.smembers('foo', function (err, members) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.deepEqual(buffers_to_strings(members), [ 'x' ], name);
+ });
+
+ client.sadd('foo', 'y', require_number(1, name));
+
+ client.smembers('foo', function (err, values) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.equal(values.length, 2, name);
+ var members = buffers_to_strings(values).sort();
+
+ assert.deepEqual(members, [ 'x', 'y' ], name);
+ next(name);
+ });
+};
+
+tests.SMOVE = function () {
+ var name = "SMOVE";
+
+ client.del('foo');
+ client.del('bar');
+
+ client.sadd('foo', 'x', require_number(1, name));
+ client.smove('foo', 'bar', 'x', require_number(1, name));
+ client.sismember('foo', 'x', require_number(0, name));
+ client.sismember('bar', 'x', require_number(1, name));
+ client.smove('foo', 'bar', 'x', last(name, require_number(0, name)));
+};
+
+tests.SINTER = function () {
+ var name = "SINTER";
+
+ client.del('sa');
+ client.del('sb');
+ client.del('sc');
+
+ client.sadd('sa', 'a', require_number(1, name));
+ client.sadd('sa', 'b', require_number(1, name));
+ client.sadd('sa', 'c', require_number(1, name));
+
+ client.sadd('sb', 'b', require_number(1, name));
+ client.sadd('sb', 'c', require_number(1, name));
+ client.sadd('sb', 'd', require_number(1, name));
+
+ client.sadd('sc', 'c', require_number(1, name));
+ client.sadd('sc', 'd', require_number(1, name));
+ client.sadd('sc', 'e', require_number(1, name));
+
+ client.sinter('sa', 'sb', function (err, intersection) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.equal(intersection.length, 2, name);
+ assert.deepEqual(buffers_to_strings(intersection).sort(), [ 'b', 'c' ], name);
+ });
+
+ client.sinter('sb', 'sc', function (err, intersection) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.equal(intersection.length, 2, name);
+ assert.deepEqual(buffers_to_strings(intersection).sort(), [ 'c', 'd' ], name);
+ });
+
+ client.sinter('sa', 'sc', function (err, intersection) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.equal(intersection.length, 1, name);
+ assert.equal(intersection[0], 'c', name);
+ });
+
+ // 3-way
+
+ client.sinter('sa', 'sb', 'sc', function (err, intersection) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.equal(intersection.length, 1, name);
+ assert.equal(intersection[0], 'c', name);
+ next(name);
+ });
+};
+
+tests.SINTERSTORE = function () {
+ var name = "SINTERSTORE";
+
+ client.del('sa');
+ client.del('sb');
+ client.del('sc');
+ client.del('foo');
+
+ client.sadd('sa', 'a', require_number(1, name));
+ client.sadd('sa', 'b', require_number(1, name));
+ client.sadd('sa', 'c', require_number(1, name));
+
+ client.sadd('sb', 'b', require_number(1, name));
+ client.sadd('sb', 'c', require_number(1, name));
+ client.sadd('sb', 'd', require_number(1, name));
+
+ client.sadd('sc', 'c', require_number(1, name));
+ client.sadd('sc', 'd', require_number(1, name));
+ client.sadd('sc', 'e', require_number(1, name));
+
+ client.sinterstore('foo', 'sa', 'sb', 'sc', require_number(1, name));
+
+ client.smembers('foo', function (err, members) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.deepEqual(buffers_to_strings(members), [ 'c' ], name);
+ next(name);
+ });
+};
+
+tests.SUNION = function () {
+ var name = "SUNION";
+
+ client.del('sa');
+ client.del('sb');
+ client.del('sc');
+
+ client.sadd('sa', 'a', require_number(1, name));
+ client.sadd('sa', 'b', require_number(1, name));
+ client.sadd('sa', 'c', require_number(1, name));
+
+ client.sadd('sb', 'b', require_number(1, name));
+ client.sadd('sb', 'c', require_number(1, name));
+ client.sadd('sb', 'd', require_number(1, name));
+
+ client.sadd('sc', 'c', require_number(1, name));
+ client.sadd('sc', 'd', require_number(1, name));
+ client.sadd('sc', 'e', require_number(1, name));
+
+ client.sunion('sa', 'sb', 'sc', function (err, union) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.deepEqual(buffers_to_strings(union).sort(), ['a', 'b', 'c', 'd', 'e'], name);
+ next(name);
+ });
+};
+
+tests.SUNIONSTORE = function () {
+ var name = "SUNIONSTORE";
+
+ client.del('sa');
+ client.del('sb');
+ client.del('sc');
+ client.del('foo');
+
+ client.sadd('sa', 'a', require_number(1, name));
+ client.sadd('sa', 'b', require_number(1, name));
+ client.sadd('sa', 'c', require_number(1, name));
+
+ client.sadd('sb', 'b', require_number(1, name));
+ client.sadd('sb', 'c', require_number(1, name));
+ client.sadd('sb', 'd', require_number(1, name));
+
+ client.sadd('sc', 'c', require_number(1, name));
+ client.sadd('sc', 'd', require_number(1, name));
+ client.sadd('sc', 'e', require_number(1, name));
+
+ client.sunionstore('foo', 'sa', 'sb', 'sc', function (err, cardinality) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.equal(cardinality, 5, name);
+ });
+
+ client.smembers('foo', function (err, members) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.equal(members.length, 5, name);
+ assert.deepEqual(buffers_to_strings(members).sort(), ['a', 'b', 'c', 'd', 'e'], name);
+ next(name);
+ });
+};
+
+// SORT test adapted from Brian Hammond's redis-node-client.js, which has a comprehensive test suite
+
+tests.SORT = function () {
+ var name = "SORT";
+
+ client.del('y');
+ client.del('x');
+
+ client.rpush('y', 'd', require_number(1, name));
+ client.rpush('y', 'b', require_number(2, name));
+ client.rpush('y', 'a', require_number(3, name));
+ client.rpush('y', 'c', require_number(4, name));
+
+ client.rpush('x', '3', require_number(1, name));
+ client.rpush('x', '9', require_number(2, name));
+ client.rpush('x', '2', require_number(3, name));
+ client.rpush('x', '4', require_number(4, name));
+
+ client.set('w3', '4', require_string("OK", name));
+ client.set('w9', '5', require_string("OK", name));
+ client.set('w2', '12', require_string("OK", name));
+ client.set('w4', '6', require_string("OK", name));
+
+ client.set('o2', 'buz', require_string("OK", name));
+ client.set('o3', 'foo', require_string("OK", name));
+ client.set('o4', 'baz', require_string("OK", name));
+ client.set('o9', 'bar', require_string("OK", name));
+
+ client.set('p2', 'qux', require_string("OK", name));
+ client.set('p3', 'bux', require_string("OK", name));
+ client.set('p4', 'lux', require_string("OK", name));
+ client.set('p9', 'tux', require_string("OK", name));
+
+ // Now the data has been setup, we can test.
+
+ // But first, test basic sorting.
+
+ // y = [ d b a c ]
+ // sort y ascending = [ a b c d ]
+ // sort y descending = [ d c b a ]
+
+ client.sort('y', 'asc', 'alpha', function (err, sorted) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.deepEqual(buffers_to_strings(sorted), ['a', 'b', 'c', 'd'], name);
+ });
+
+ client.sort('y', 'desc', 'alpha', function (err, sorted) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.deepEqual(buffers_to_strings(sorted), ['d', 'c', 'b', 'a'], name);
+ });
+
+ // Now try sorting numbers in a list.
+ // x = [ 3, 9, 2, 4 ]
+
+ client.sort('x', 'asc', function (err, sorted) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.deepEqual(buffers_to_strings(sorted), [2, 3, 4, 9], name);
+ });
+
+ client.sort('x', 'desc', function (err, sorted) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.deepEqual(buffers_to_strings(sorted), [9, 4, 3, 2], name);
+ });
+
+ // Try sorting with a 'by' pattern.
+
+ client.sort('x', 'by', 'w*', 'asc', function (err, sorted) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.deepEqual(buffers_to_strings(sorted), [3, 9, 4, 2], name);
+ });
+
+ // Try sorting with a 'by' pattern and 1 'get' pattern.
+
+ client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', function (err, sorted) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.deepEqual(buffers_to_strings(sorted), ['foo', 'bar', 'baz', 'buz'], name);
+ });
+
+ // Try sorting with a 'by' pattern and 2 'get' patterns.
+
+ client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*', function (err, sorted) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.deepEqual(buffers_to_strings(sorted), ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux'], name);
+ });
+
+ // Try sorting with a 'by' pattern and 2 'get' patterns.
+ // Instead of getting back the sorted set/list, store the values to a list.
+ // Then check that the values are there in the expected order.
+
+ client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*', 'store', 'bacon', function (err) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ });
+
+ client.lrange('bacon', 0, -1, function (err, values) {
+ if (err) {
+ assert.fail(err, name);
+ }
+ assert.deepEqual(buffers_to_strings(values), ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux'], name);
+ next(name);
+ });
+
+ // TODO - sort by hash value
+};
+
+tests.MONITOR = function () {
+ var name = "MONITOR", responses = [], monitor_client;
+
+ monitor_client = redis.createClient();
+ monitor_client.monitor(function (err, res) {
+ client.mget("some", "keys", "foo", "bar");
+ client.set("json", JSON.stringify({
+ foo: "123",
+ bar: "sdflkdfsjk",
+ another: false
+ }));
+ });
+ monitor_client.on("monitor", function (time, args) {
+ // skip monitor command for Redis <= 2.4.16
+ if (args[0] === "monitor") return;
+
+ responses.push(args);
+ if (responses.length === 2) {
+ assert.strictEqual(5, responses[0].length);
+ assert.strictEqual("mget", responses[0][0]);
+ assert.strictEqual("some", responses[0][1]);
+ assert.strictEqual("keys", responses[0][2]);
+ assert.strictEqual("foo", responses[0][3]);
+ assert.strictEqual("bar", responses[0][4]);
+ assert.strictEqual(3, responses[1].length);
+ assert.strictEqual("set", responses[1][0]);
+ assert.strictEqual("json", responses[1][1]);
+ assert.strictEqual('{"foo":"123","bar":"sdflkdfsjk","another":false}', responses[1][2]);
+ monitor_client.quit(function (err, res) {
+ next(name);
+ });
+ }
+ });
+};
+
+tests.BLPOP = function () {
+ var name = "BLPOP";
+
+ client.rpush("blocking list", "initial value", function (err, res) {
+ client2.BLPOP("blocking list", 0, function (err, res) {
+ assert.strictEqual("blocking list", res[0].toString());
+ assert.strictEqual("initial value", res[1].toString());
+
+ client.rpush("blocking list", "wait for this value");
+ });
+ client2.BLPOP("blocking list", 0, function (err, res) {
+ assert.strictEqual("blocking list", res[0].toString());
+ assert.strictEqual("wait for this value", res[1].toString());
+ next(name);
+ });
+ });
+};
+
+tests.BLPOP_TIMEOUT = function () {
+ var name = "BLPOP_TIMEOUT";
+
+ // try to BLPOP the list again, which should be empty. This should timeout and return null.
+ client2.BLPOP("blocking list", 1, function (err, res) {
+ if (err) {
+ throw err;
+ }
+
+ assert.strictEqual(res, null);
+ next(name);
+ });
+};
+
+tests.EXPIRE = function () {
+ var name = "EXPIRE";
+ client.set(['expiry key', 'bar'], require_string("OK", name));
+ client.EXPIRE(["expiry key", "1"], require_number_pos(name));
+ setTimeout(function () {
+ client.exists(["expiry key"], last(name, require_number(0, name)));
+ }, 2000);
+};
+
+tests.TTL = function () {
+ var name = "TTL";
+ client.set(["ttl key", "ttl val"], require_string("OK", name));
+ client.expire(["ttl key", "100"], require_number_pos(name));
+ setTimeout(function () {
+ client.TTL(["ttl key"], last(name, require_number_pos(0, name)));
+ }, 500);
+};
+
+tests.OPTIONAL_CALLBACK = function () {
+ var name = "OPTIONAL_CALLBACK";
+ client.del("op_cb1");
+ client.set("op_cb1", "x");
+ client.get("op_cb1", last(name, require_string("x", name)));
+};
+
+tests.OPTIONAL_CALLBACK_UNDEFINED = function () {
+ var name = "OPTIONAL_CALLBACK_UNDEFINED";
+ client.del("op_cb2");
+ client.set("op_cb2", "y", undefined);
+ client.get("op_cb2", last(name, require_string("y", name)));
+};
+
+tests.HMSET_THROWS_ON_NON_STRINGS = function () {
+ var name = "HMSET_THROWS_ON_NON_STRINGS";
+ var hash = name;
+ var data = { "a": [ "this is not a string" ] };
+
+ client.hmset(hash, data, cb);
+ function cb(e, r) {
+ assert(e); // should be an error!
+ }
+
+ // alternative way it throws
+ function thrower() {
+ client.hmset(hash, data);
+ }
+ assert.throws(thrower);
+ next(name);
+};
+
+tests.ENABLE_OFFLINE_QUEUE_TRUE = function () {
+ var name = "ENABLE_OFFLINE_QUEUE_TRUE";
+ var cli = redis.createClient(9999, null, {
+ max_attempts: 1
+ // default :)
+ // enable_offline_queue: true
+ });
+ cli.on('error', function(e) {
+ // ignore, b/c expecting a "can't connect" error
+ });
+ return setTimeout(function() {
+ cli.set(name, name, function(err, result) {
+ assert.ifError(err);
+ });
+
+ return setTimeout(function(){
+ assert.strictEqual(cli.offline_queue.length, 1);
+ return next(name);
+ }, 25);
+ }, 50);
+};
+
+tests.ENABLE_OFFLINE_QUEUE_FALSE = function () {
+ var name = "ENABLE_OFFLINE_QUEUE_FALSE";
+ var cli = redis.createClient(9999, null, {
+ max_attempts: 1,
+ enable_offline_queue: false
+ });
+ cli.on('error', function() {
+ // ignore, see above
+ });
+ assert.throws(function () {
+ cli.set(name, name)
+ })
+ assert.doesNotThrow(function () {
+ cli.set(name, name, function (err) {
+ // should callback with an error
+ assert.ok(err);
+ setTimeout(function () {
+ next(name);
+ }, 50);
+ });
+ });
+};
+
+// TODO - need a better way to test auth, maybe auto-config a local Redis server or something.
+// Yes, this is the real password. Please be nice, thanks.
+tests.auth = function () {
+ var name = "AUTH", client4, ready_count = 0;
+
+ client4 = redis.createClient(9006, "filefish.redistogo.com");
+ client4.auth("664b1b6aaf134e1ec281945a8de702a9", function (err, res) {
+ assert.strictEqual(null, err, name);
+ assert.strictEqual("OK", res.toString(), name);
+ });
+
+ // test auth, then kill the connection so it'll auto-reconnect and auto-re-auth
+ client4.on("ready", function () {
+ ready_count++;
+ if (ready_count === 1) {
+ client4.stream.destroy();
+ } else {
+ client4.quit(function (err, res) {
+ next(name);
+ });
+ }
+ });
+};
+
+all_tests = Object.keys(tests);
+all_start = new Date();
+test_count = 0;
+
+run_next_test = function run_next_test() {
+ var test_name = all_tests.shift();
+ if (typeof tests[test_name] === "function") {
+ util.print('- \x1b[1m' + test_name.toLowerCase() + '\x1b[0m:');
+ cur_start = new Date();
+ test_count += 1;
+ tests[test_name]();
+ } else {
+ console.log('\n completed \x1b[32m%d\x1b[0m tests in \x1b[33m%d\x1b[0m ms\n', test_count, new Date() - all_start);
+ client.quit();
+ client2.quit();
+ }
+};
+
+client.once("ready", function start_tests() {
+ console.log("Connected to " + client.host + ":" + client.port + ", Redis server version " + client.server_info.redis_version + "\n");
+ console.log("Using reply parser " + client.reply_parser.name);
+
+ run_next_test();
+
+ connected = true;
+});
+
+client.on('end', function () {
+ ended = true;
+});
+
+// Exit immediately on connection failure, which triggers "exit", below, which fails the test
+client.on("error", function (err) {
+ console.error("client: " + err.stack);
+ process.exit();
+});
+client2.on("error", function (err) {
+ console.error("client2: " + err.stack);
+ process.exit();
+});
+client3.on("error", function (err) {
+ console.error("client3: " + err.stack);
+ process.exit();
+});
+client.on("reconnecting", function (params) {
+ console.log("reconnecting: " + util.inspect(params));
+});
+
+process.on('uncaughtException', function (err) {
+ console.error("Uncaught exception: " + err.stack);
+ process.exit(1);
+});
+
+process.on('exit', function (code) {
+ assert.equal(true, connected);
+ assert.equal(true, ended);
+});