Initial commit

This commit is contained in:
abrendan
2023-11-30 14:15:19 +00:00
commit e4599df811
5457 changed files with 500139 additions and 0 deletions

4
node_modules/redis/.eslintignore generated vendored Normal file
View File

@@ -0,0 +1,4 @@
node_modules/**
coverage/**
**.md
**.log

108
node_modules/redis/.eslintrc generated vendored Normal file
View File

@@ -0,0 +1,108 @@
env:
node: true
es6: false
rules:
# Possible Errors
# http://eslint.org/docs/rules/#possible-errors
comma-dangle: [2, "only-multiline"]
no-constant-condition: 2
no-control-regex: 2
no-debugger: 2
no-dupe-args: 2
no-dupe-keys: 2
no-duplicate-case: 2
no-empty: 2
no-empty-character-class: 2
no-ex-assign: 2
no-extra-boolean-cast : 2
no-extra-parens: [2, "functions"]
no-extra-semi: 2
no-func-assign: 2
no-invalid-regexp: 2
no-irregular-whitespace: 2
no-negated-in-lhs: 2
no-obj-calls: 2
no-regex-spaces: 2
no-sparse-arrays: 2
no-inner-declarations: 2
no-unexpected-multiline: 2
no-unreachable: 2
use-isnan: 2
valid-typeof: 2
# Best Practices
# http://eslint.org/docs/rules/#best-practices
array-callback-return: 2
block-scoped-var: 2
dot-notation: 2
eqeqeq: 2
no-else-return: 2
no-extend-native: 2
no-floating-decimal: 2
no-extra-bind: 2
no-fallthrough: 2
no-labels: 2
no-lone-blocks: 2
no-loop-func: 2
no-multi-spaces: 2
no-multi-str: 2
no-native-reassign: 2
no-new-wrappers: 2
no-octal: 2
no-proto: 2
no-redeclare: 2
no-return-assign: 2
no-self-assign: 2
no-self-compare: 2
no-sequences: 2
no-throw-literal: 2
no-useless-call: 2
no-useless-concat: 2
no-useless-escape: 2
no-void: 2
no-unmodified-loop-condition: 2
yoda: 2
# Strict Mode
# http://eslint.org/docs/rules/#strict-mode
strict: [2, "global"]
# Variables
# http://eslint.org/docs/rules/#variables
no-delete-var: 2
no-shadow-restricted-names: 2
no-undef: 2
no-unused-vars: [2, {"args": "none"}]
# http://eslint.org/docs/rules/#nodejs-and-commonjs
no-mixed-requires: 2
no-new-require: 2
no-path-concat: 2
# Stylistic Issues
# http://eslint.org/docs/rules/#stylistic-issues
comma-spacing: 2
eol-last: 2
indent: [2, 4, {SwitchCase: 2}]
keyword-spacing: 2
max-len: [2, 200, 2]
new-parens: 2
no-mixed-spaces-and-tabs: 2
no-multiple-empty-lines: [2, {max: 2}]
no-trailing-spaces: 2
quotes: [2, "single", "avoid-escape"]
semi: 2
space-before-blocks: [2, "always"]
space-before-function-paren: [2, "always"]
space-in-parens: [2, "never"]
space-infix-ops: 2
space-unary-ops: 2
globals:
it: true
describe: true
before: true
after: true
beforeEach: true
afterEach: true

15
node_modules/redis/.github/ISSUE_TEMPLATE.md generated vendored Normal file
View File

@@ -0,0 +1,15 @@
_Thanks for wanting to report an issue you've found in node_redis. Please delete
this text and fill in the template below. Please note that the issue tracker is only
for bug reports or feature requests. If you have a question, please ask that on [gitter].
If unsure about something, just do as best as you're able._
_Note that it will be much easier to fix the issue if a test case that reproduces
the problem is provided. It is of course not always possible to reduce your code
to a small test case, but it's highly appreciated to have as much data as possible.
Thank you!_
* **Version**: What node_redis and what redis version is the issue happening on?
* **Platform**: What platform / version? (For example Node.js 0.10 or Node.js 5.7.0 on Windows 7 / Ubuntu 15.10 / Azure)
* **Description**: Description of your issue, stack traces from errors and code that reproduces the issue
[gitter]: https://gitter.im/NodeRedis/node_redis?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge

14
node_modules/redis/.github/PULL_REQUEST_TEMPLATE.md generated vendored Normal file
View File

@@ -0,0 +1,14 @@
### Pull Request check-list
_Please make sure to review and check all of these items:_
- [ ] Does `npm test` pass with this change (including linting)?
- [ ] Is the new or changed code fully tested?
- [ ] Is a documentation update included (if this change modifies existing APIs, or introduces new ones)?
_NOTE: these things are not required to open a PR and can be done
afterwards / while the PR is open._
### Description of change
_Please provide a description of the change here._

10
node_modules/redis/.npmignore generated vendored Normal file
View File

@@ -0,0 +1,10 @@
examples/
benchmarks/
test/
.nyc_output/
coverage/
.tern-port
*.log
*.rdb
*.out
*.yml

24
node_modules/redis/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,24 @@
LICENSE - "MIT License"
Copyright (c) 2016 by NodeRedis
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.

965
node_modules/redis/README.md generated vendored Normal file
View File

@@ -0,0 +1,965 @@
redis - a node.js redis client
===========================
[![Build Status](https://travis-ci.org/NodeRedis/node_redis.svg?branch=master)](https://travis-ci.org/NodeRedis/node_redis)
[![Coverage Status](https://coveralls.io/repos/NodeRedis/node_redis/badge.svg?branch=)](https://coveralls.io/r/NodeRedis/node_redis?branch=)
[![Windows Tests](https://img.shields.io/appveyor/ci/BridgeAR/node-redis/master.svg?label=Windows%20Tests)](https://ci.appveyor.com/project/BridgeAR/node-redis/branch/master)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/NodeRedis/node_redis?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
This is a complete and feature rich Redis client for node.js. __It supports all
Redis commands__ and focuses on high performance.
Install with:
npm install redis
## Usage Example
```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)$
Note that the API is entirely asynchronous. To get data back from the server,
you'll need to use a callback. From v.2.6 on the API supports camelCase and
snake_case and all options / variables / events etc. can be used either way. It
is recommended to use camelCase as this is the default for the Node.js
landscape.
### Promises
You can also use node_redis with promises by promisifying node_redis with
[bluebird](https://github.com/petkaantonov/bluebird) as in:
```js
var redis = require('redis');
bluebird.promisifyAll(redis.RedisClient.prototype);
bluebird.promisifyAll(redis.Multi.prototype);
```
It'll add a *Async* to all node_redis functions (e.g. return client.getAsync().then())
```js
// We expect a value 'foo': 'bar' to be present
// So instead of writing client.get('foo', cb); you have to write:
return client.getAsync('foo').then(function(res) {
console.log(res); // => 'bar'
});
// Using multi with promises looks like:
return client.multi().get('foo').execAsync().then(function(res) {
console.log(res); // => 'bar'
});
```
### 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.
Examples:
```js
client.hmset(["key", "test keys 1", "test val 1", "test keys 2", "test val 2"], function (err, res) {});
// Works the same as
client.hmset("key", ["test keys 1", "test val 1", "test keys 2", "test val 2"], function (err, res) {});
// Or
client.hmset("key", "test keys 1", "test val 1", "test keys 2", "test val 2", function (err, res) {});
```
Note that in either form the `callback` is optional:
```js
client.set("some key", "some val");
client.set(["some other key", "some val"]);
```
If the key is missing, reply will be null. Only if the [Redis Command
Reference](http://redis.io/commands) states something else it will not be null.
```js
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)
Minimal parsing is done on the replies. Commands that return a integer return
JavaScript Numbers, arrays return JavaScript Array. `HGETALL` returns an Object
keyed by the hash keys. All strings will either be returned as string or as
buffer depending on your setting. Please be aware that sending null, undefined
and Boolean values will result in the value coerced to a string!
# Redis Commands
This library is a 1 to 1 mapping to [Redis commands](https://redis.io/commands).
It is not a cache library so please refer to Redis commands page for full usage
details.
Example setting key to auto expire using [SET command](https://redis.io/commands/set)
```js
// this key will expire after 10 seconds
client.set('key', 'value!', 'EX', 10);
```
# API
## Connection and other Events
`client` will emit some events about the state of the connection to the Redis server.
### "ready"
`client` will emit `ready` once a connection is established. Commands issued
before the `ready` event are queued, then replayed just before this event is
emitted.
### "connect"
`client` will emit `connect` as soon as the stream is connected to the server.
### "reconnecting"
`client` will emit `reconnecting` when trying to reconnect to the Redis server
after losing the connection. Listeners are passed an object containing `delay`
(in ms) and `attempt` (the attempt #) attributes.
### "error"
`client` will emit `error` when encountering an error connecting to the Redis
server or when any other in node_redis occurs. If you use a command without
callback and encounter a ReplyError it is going to be emitted to the error
listener.
So please attach the error listener to node_redis.
### "end"
`client` will emit `end` when an established Redis server connection has closed.
### "drain" (deprecated)
`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.
If the stream is buffering `client.should_buffer` is set to true. Otherwise the
variable is always set to false. That way you can decide when to reduce your
send rate and resume sending commands when you get `drain`.
You can also check the return value of each command as it will also return the
backpressure indicator (deprecated). If false is returned the stream had to
buffer.
### "warning"
`client` will emit `warning` when password was set but none is needed and if a
deprecated option / function / similar is used.
### "idle" (deprecated)
`client` will emit `idle` when there are no outstanding commands that are
awaiting a response.
## redis.createClient()
If you have `redis-server` running on the same machine as node, then the
defaults for port and host are probably fine and you don't need to supply any
arguments. `createClient()` returns a `RedisClient` object. Otherwise,
`createClient()` accepts these arguments:
* `redis.createClient([options])`
* `redis.createClient(unix_socket[, options])`
* `redis.createClient(redis_url[, options])`
* `redis.createClient(port[, host][, options])`
__Tip:__ If the Redis server runs on the same machine as the client consider
using unix sockets if possible to increase throughput.
#### `options` object properties
| Property | Default | Description |
|-----------|-----------|-------------|
| host | 127.0.0.1 | IP address of the Redis server |
| port | 6379 | Port of the Redis server |
| path | null | The UNIX socket string of the Redis server |
| url | null | The URL of the Redis server. Format: `[redis:]//[[user][:password@]][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]]` (More info avaliable at [IANA](http://www.iana.org/assignments/uri-schemes/prov/redis)). |
| parser | javascript | __Deprecated__ Use either the built-in JS parser [`javascript`]() or the native [`hiredis`]() parser. __Note__ `node_redis` < 2.6 uses hiredis as default if installed. This changed in v.2.6.0. |
| string_numbers | null | Set to `true`, `node_redis` will return Redis number values as Strings instead of javascript Numbers. Useful if you need to handle big numbers (above `Number.MAX_SAFE_INTEGER === 2^53`). Hiredis is incapable of this behavior, so setting this option to `true` will result in the built-in javascript parser being used no matter the value of the `parser` option. |
| return_buffers | false | If set to `true`, then all replies will be sent to callbacks as Buffers instead of Strings. |
| detect_buffers | false | If set to `true`, then replies will be sent to callbacks as Buffers. This option lets you switch between Buffers and Strings on a per-command basis, whereas `return_buffers` applies to every command on a client. __Note__: This doesn't work properly with the pubsub mode. A subscriber has to either always return Strings or Buffers. |
| socket_keepalive | true | If set to `true`, the keep-alive functionality is enabled on the underlying socket. |
| no_ready_check | false | When a connection is established to the Redis server, the server might still be loading the database from disk. While loading, the server will 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 | 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 executed immediately with an error, or an error will be emitted if no callback is specified. |
| retry_max_delay | null | __Deprecated__ _Please use `retry_strategy` instead._ By default, every time the client tries to connect and fails, the reconnection delay almost doubles. This delay normally grows infinitely, but setting `retry_max_delay` limits it to the maximum value provided in milliseconds. |
| connect_timeout | 3600000 | __Deprecated__ _Please use `retry_strategy` instead._ Setting `connect_timeout` limits the total time for the client to connect and reconnect. The value is provided in milliseconds and is counted from the moment a new client is created or from the time the connection is lost. The last retry is going to happen exactly at the timeout time. Default is to try connecting until the default system socket timeout has been exceeded and to try reconnecting until 1h has elapsed. |
| max_attempts | 0 | __Deprecated__ _Please use `retry_strategy` instead._ By default, a client will try reconnecting until connected. Setting `max_attempts` limits total amount of connection attempts. Setting this to 1 will prevent any reconnect attempt. |
| retry_unfulfilled_commands | false | If set to `true`, all commands that were unfulfilled while the connection is lost will be retried after the connection has been reestablished. Use this with caution if you use state altering commands (e.g. `incr`). This is especially useful if you use blocking commands. |
| password | null | If set, client will run Redis auth command on connect. Alias `auth_pass` __Note__ `node_redis` < 2.5 must use `auth_pass` |
| db | null | If set, client will run Redis `select` command on connect. |
| family | IPv4 | You can force using IPv6 if you set the family to 'IPv6'. See Node.js [net](https://nodejs.org/api/net.html) or [dns](https://nodejs.org/api/dns.html) modules on how to use the family type. |
| disable_resubscribing | false | If set to `true`, a client won't resubscribe after disconnecting. |
| rename_commands | null | Passing an object with renamed commands to use instead of the original functions. For example, if you renamed the command KEYS to "DO-NOT-USE" then the rename_commands object would be: `{ KEYS : "DO-NOT-USE" }` . See the [Redis security topics](http://redis.io/topics/security) for more info. |
| tls | null | An object containing options to pass to [tls.connect](http://nodejs.org/api/tls.html#tls_tls_connect_port_host_options_callback) to set up a TLS connection to Redis (if, for example, it is set up to be accessible via a tunnel). |
| prefix | null | A string used to prefix all used keys (e.g. `namespace:test`). Please be aware that the `keys` command will not be prefixed. The `keys` command has a "pattern" as argument and no key and it would be impossible to determine the existing keys in Redis if this would be prefixed. |
| retry_strategy | function | A function that receives an options object as parameter including the retry `attempt`, the `total_retry_time` indicating how much time passed since the last time connected, the `error` why the connection was lost and the number of `times_connected` in total. If you return a number from this function, the retry will happen exactly after that time in milliseconds. If you return a non-number, no further retry will happen and all offline commands are flushed with errors. Return an error to return that specific error to all offline commands. Example below. |
```js
var redis = require("redis");
var client = redis.createClient({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.quit();
```
retry_strategy example
```js
var client = redis.createClient({
retry_strategy: function (options) {
if (options.error && options.error.code === 'ECONNREFUSED') {
// End reconnecting on a specific error and flush all commands with
// a individual error
return new Error('The server refused the connection');
}
if (options.total_retry_time > 1000 * 60 * 60) {
// End reconnecting after a specific timeout and flush all commands
// with a individual error
return new Error('Retry time exhausted');
}
if (options.attempt > 10) {
// End reconnecting with built in error
return undefined;
}
// reconnect after
return Math.min(options.attempt * 100, 3000);
}
});
```
## client.auth(password[, callback])
When connecting to a Redis server that requires 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`.
## backpressure
### stream
The client exposed the used [stream](https://nodejs.org/api/stream.html) in
`client.stream` and if the stream or client had to
[buffer](https://nodejs.org/api/stream.html#stream_writable_write_chunk_encoding_callback)
the command in `client.should_buffer`. In combination this can be used to
implement backpressure by checking the buffer state before sending a command and
listening to the stream
[drain](https://nodejs.org/api/stream.html#stream_event_drain) event.
## client.quit()
This sends the quit command to the redis server and ends cleanly right after all
running commands were properly handled. If this is called while reconnecting
(and therefore no connection to the redis server exists) it is going to end the
connection right away instead of resulting in further reconnections! All offline
commands are going to be flushed with an error in that case.
## client.end(flush)
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()` as mentioned above.
You should set flush to true, if you are not absolutely sure you do not care
about any other commands. If you set flush to false all still running commands
will silently fail.
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", function (err, reply) {
// This will either result in an error (flush parameter is set to true)
// or will silently fail and this callback will not be called at all (flush set to false)
console.log(err);
});
client.end(true); // No further commands will be processed
client.get("foo_rand000000000000", function (err, reply) {
console.log(err); // => 'The connection has already been closed.'
});
```
`client.end()` without the flush parameter set to true should NOT be used in production!
## Error handling (>= v.2.6)
Currently the following error subclasses exist:
* `RedisError`: _All errors_ returned by the client
* `ReplyError` subclass of `RedisError`: All errors returned by __Redis__ itself
* `AbortError` subclass of `RedisError`: All commands that could not finish due
to what ever reason
* `ParserError` subclass of `RedisError`: Returned in case of a parser error
(this should not happen)
* `AggregateError` subclass of `AbortError`: Emitted in case multiple unresolved
commands without callback got rejected in debug_mode instead of lots of
`AbortError`s.
All error classes are exported by the module.
Example:
```js
var redis = require('./');
var assert = require('assert');
var client = redis.createClient();
client.on('error', function (err) {
assert(err instanceof Error);
assert(err instanceof redis.AbortError);
assert(err instanceof redis.AggregateError);
// The set and get get aggregated in here
assert.strictEqual(err.errors.length, 2);
assert.strictEqual(err.code, 'NR_CLOSED');
});
client.set('foo', 123, 'bar', function (err, res) { // Too many arguments
assert(err instanceof redis.ReplyError); // => true
assert.strictEqual(err.command, 'SET');
assert.deepStrictEqual(err.args, ['foo', 123, 'bar']);
redis.debug_mode = true;
client.set('foo', 'bar');
client.get('foo');
process.nextTick(function () {
// Force closing the connection while the command did not yet return
client.end(true);
redis.debug_mode = false;
});
});
```
Every `ReplyError` contains the `command` name in all-caps and the arguments (`args`).
If node_redis emits a library error because of another error, the triggering
error is added to the returned error as `origin` attribute.
___Error codes___
node_redis returns a `NR_CLOSED` error code if the clients connection dropped.
If a command unresolved command got rejected a `UNCERTAIN_STATE` code is
returned. A `CONNECTION_BROKEN` error code is used in case node_redis gives up
to reconnect.
## client.unref()
Call `unref()` on the underlying socket connection to the Redis server, allowing
the program to exit once no more commands are pending.
This is an **experimental** feature, and only supports a subset of the Redis
protocol. Any commands where client state is saved on the Redis server, e.g.
`*SUBSCRIBE` or the blocking `BL*` commands will *NOT* work with `.unref()`.
```js
var redis = require("redis")
var client = redis.createClient()
/*
Calling unref() will allow this program to exit immediately after the get
command finishes. Otherwise the client would hang as long as the
client-server connection is alive.
*/
client.unref()
client.get("foo", function (err, value){
if (err) throw(err)
console.log(value)
})
```
## 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, callback)
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:
```js
client.hmset("hosts", "mjr", "1", "another", "23", "home", "1234");
client.hgetall("hosts", function (err, obj) {
console.dir(obj);
});
```
Output:
```js
{ mjr: '1', another: '23', home: '1234' }
```
### client.hmset(hash, obj[, callback])
Multiple values in a hash can be set by supplying an object:
```js
client.HMSET(key2, {
"0123456789": "abcdefghij", // NOTE: key and value will be coerced to 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:
```js
client.HMSET(key1, "0123456789", "abcdefghij", "some manner of key", "a type of value");
```
## Publish / Subscribe
Example of the publish / subscribe API. 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");
var sub = redis.createClient(), pub = redis.createClient();
var msg_count = 0;
sub.on("subscribe", function (channel, count) {
pub.publish("a nice channel", "I am sending a message.");
pub.publish("a nice channel", "I am sending a second message.");
pub.publish("a nice channel", "I am sending my last message.");
});
sub.on("message", function (channel, message) {
console.log("sub channel " + channel + ": " + message);
msg_count += 1;
if (msg_count === 3) {
sub.unsubscribe();
sub.quit();
pub.quit();
}
});
sub.subscribe("a nice channel");
```
When a client issues a `SUBSCRIBE` or `PSUBSCRIBE`, that connection is put into
a "subscriber" mode. At that point, only commands that modify the subscription
set are valid and quit (and depending on the redis version ping as well). 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 subscriber mode, just
open another connection with a new client (hint: use `client.duplicate()`).
## Subscriber 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 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 as `message`.
### "message_buffer" (channel, message)
This is the same as the `message` event with the exception, that it is always
going to emit a buffer. If you listen to the `message` event at the same time as
the `message_buffer`, it is always going to emit a string.
### "pmessage_buffer" (pattern, channel, message)
This is the same as the `pmessage` event with the exception, that it is always
going to emit a buffer. If you listen to the `pmessage` event at the same time
as the `pmessage_buffer`, it is always going to emit a string.
### "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 subscriber mode
and no more subscriber 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 subscriber mode and no more subscriber 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()`. If any command fails to
queue, all commands are rolled back and none is going to be executed (For
further information look at
[transactions](http://redis.io/topics/transactions)).
```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());
});
});
```
### Multi.exec([callback])
`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.
If your code contains an syntax error an EXECABORT error is going to be thrown
and all commands are going to be aborted. That error contains a `.errors`
property that contains the concrete errors.
If all commands were queued successfully and an error is thrown by redis while
processing the commands that error is going to be returned in the result array!
No other command is going to be aborted though than the onces failing.
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
});
```
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);
});
```
### Multi.exec_atomic([callback])
Identical to Multi.exec but with the difference that executing a single command
will not use transactions.
## client.batch([commands])
Identical to .multi without transactions. This is recommended if you want to
execute many commands at once but don't have to rely on transactions.
`BATCH` 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 `Batch` object by calling `client.batch()`. The only difference
between .batch and .multi is that no transaction is going to be used.
Be aware that the errors are - just like in multi statements - in the result.
Otherwise both, errors and results could be returned at the same time.
If you fire many commands at once this is going to boost the execution speed
significantly compared to firing the same commands in a loop without waiting for
the result! See the benchmarks for further comparison. Please remember that all
commands are kept in memory until they are fired.
## 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.
A `monitor` event is going to be emitted for every command fired from any client
connected to the server including the monitoring client itself. The callback for
the `monitor` event takes a timestamp from the Redis server, an array of command
arguments and the raw monitoring string.
Example:
```js
var client = require("redis").createClient();
client.monitor(function (err, res) {
console.log("Entering monitoring mode.");
});
client.set('foo', 'bar');
client.on("monitor", function (time, args, raw_reply) {
console.log(time + ": " + args); // 1458910076.446514:['set', 'foo', 'bar']
});
```
# 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.
## Multi-word commands
To execute redis multi-word commands like `SCRIPT LOAD` or `CLIENT LIST` pass
the second word as first parameter:
client.script('load', 'return 1');
client.multi().script('load', 'return 1').exec(...);
client.multi([['script', 'load', 'return 1']]).exec(...);
## client.duplicate([options][, callback])
Duplicate all current options and return a new redisClient instance. All options
passed to the duplicate function are going to replace the original option. If
you pass a callback, duplicate is going to wait until the client is ready and
returns it in the callback. If an error occurs in the meanwhile, that is going
to return an error instead in the callback.
One example of when to use duplicate() would be to accommodate the connection-
blocking redis commands BRPOP, BLPOP, and BRPOPLPUSH. If these commands
are used on the same redisClient instance as non-blocking commands, the
non-blocking ones may be queued up until after the blocking ones finish.
var Redis=require('redis');
var client = Redis.createClient();
var clientBlocking = client.duplicate();
var get = function() {
console.log("get called");
client.get("any_key",function() { console.log("get returned"); });
setTimeout( get, 1000 );
};
var brpop = function() {
console.log("brpop called");
clientBlocking.brpop("nonexistent", 5, function() {
console.log("brpop return");
setTimeout( brpop, 1000 );
});
};
get();
brpop();
Another reason to use duplicate() is when multiple DBs on the same server are
accessed via the redis SELECT command. Each DB could use its own connection.
## client.send_command(command_name[, [args][, callback]])
All Redis commands have been added to the `client` object. However, if new
commands are introduced before this library is updated or if you want to add
individual commands 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 / set to undefined.
## client.add_command(command_name)
Calling add_command will add a new command to the prototype. The exact command
name will be used when calling using this new command. Using arbitrary arguments
is possible as with any other command.
## 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.
## 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.
### 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
});
});
```
## Performance
Much effort has been spent to make `node_redis` as fast as possible for common
operations.
```
Lenovo T450s, i7-5600U and 12gb memory
clients: 1, NodeJS: 6.2.0, Redis: 3.2.0, parser: javascript, connected by: tcp
PING, 1/1 avg/max: 0.02/ 5.26 2501ms total, 46916 ops/sec
PING, batch 50/1 avg/max: 0.06/ 4.35 2501ms total, 755178 ops/sec
SET 4B str, 1/1 avg/max: 0.02/ 4.75 2501ms total, 40856 ops/sec
SET 4B str, batch 50/1 avg/max: 0.11/ 1.51 2501ms total, 432727 ops/sec
SET 4B buf, 1/1 avg/max: 0.05/ 2.76 2501ms total, 20659 ops/sec
SET 4B buf, batch 50/1 avg/max: 0.25/ 1.76 2501ms total, 194962 ops/sec
GET 4B str, 1/1 avg/max: 0.02/ 1.55 2501ms total, 45156 ops/sec
GET 4B str, batch 50/1 avg/max: 0.09/ 3.15 2501ms total, 524110 ops/sec
GET 4B buf, 1/1 avg/max: 0.02/ 3.07 2501ms total, 44563 ops/sec
GET 4B buf, batch 50/1 avg/max: 0.10/ 3.18 2501ms total, 473171 ops/sec
SET 4KiB str, 1/1 avg/max: 0.03/ 1.54 2501ms total, 32627 ops/sec
SET 4KiB str, batch 50/1 avg/max: 0.34/ 1.89 2501ms total, 146861 ops/sec
SET 4KiB buf, 1/1 avg/max: 0.05/ 2.85 2501ms total, 20688 ops/sec
SET 4KiB buf, batch 50/1 avg/max: 0.36/ 1.83 2501ms total, 138165 ops/sec
GET 4KiB str, 1/1 avg/max: 0.02/ 1.37 2501ms total, 39389 ops/sec
GET 4KiB str, batch 50/1 avg/max: 0.24/ 1.81 2501ms total, 208157 ops/sec
GET 4KiB buf, 1/1 avg/max: 0.02/ 2.63 2501ms total, 39918 ops/sec
GET 4KiB buf, batch 50/1 avg/max: 0.31/ 8.56 2501ms total, 161575 ops/sec
INCR, 1/1 avg/max: 0.02/ 4.69 2501ms total, 45685 ops/sec
INCR, batch 50/1 avg/max: 0.09/ 3.06 2501ms total, 539964 ops/sec
LPUSH, 1/1 avg/max: 0.02/ 3.04 2501ms total, 41253 ops/sec
LPUSH, batch 50/1 avg/max: 0.12/ 1.94 2501ms total, 425090 ops/sec
LRANGE 10, 1/1 avg/max: 0.02/ 2.28 2501ms total, 39850 ops/sec
LRANGE 10, batch 50/1 avg/max: 0.25/ 1.85 2501ms total, 194302 ops/sec
LRANGE 100, 1/1 avg/max: 0.05/ 2.93 2501ms total, 21026 ops/sec
LRANGE 100, batch 50/1 avg/max: 1.52/ 2.89 2501ms total, 32767 ops/sec
SET 4MiB str, 1/1 avg/max: 5.16/ 15.55 2502ms total, 193 ops/sec
SET 4MiB str, batch 20/1 avg/max: 89.73/ 99.96 2513ms total, 223 ops/sec
SET 4MiB buf, 1/1 avg/max: 2.23/ 8.35 2501ms total, 446 ops/sec
SET 4MiB buf, batch 20/1 avg/max: 41.47/ 50.91 2530ms total, 482 ops/sec
GET 4MiB str, 1/1 avg/max: 2.79/ 10.91 2502ms total, 358 ops/sec
GET 4MiB str, batch 20/1 avg/max: 101.61/118.11 2541ms total, 197 ops/sec
GET 4MiB buf, 1/1 avg/max: 2.32/ 14.93 2502ms total, 430 ops/sec
GET 4MiB buf, batch 20/1 avg/max: 65.01/ 84.72 2536ms total, 308 ops/sec
```
## Debugging
To get debug output run your `node_redis` application with `NODE_DEBUG=redis`.
This is also going to result in good stack traces opposed to useless ones
otherwise for any async operation.
If you only want to have good stack traces but not the debug output run your
application in development mode instead (`NODE_ENV=development`).
Good stack traces are only activated in development and debug mode as this
results in a significant performance penalty.
___Comparison___:
Useless stack trace:
```
ReplyError: ERR wrong number of arguments for 'set' command
at parseError (/home/ruben/repos/redis/node_modules/redis-parser/lib/parser.js:158:12)
at parseType (/home/ruben/repos/redis/node_modules/redis-parser/lib/parser.js:219:14)
```
Good stack trace:
```
ReplyError: ERR wrong number of arguments for 'set' command
at new Command (/home/ruben/repos/redis/lib/command.js:9:902)
at RedisClient.set (/home/ruben/repos/redis/lib/commands.js:9:3238)
at Context.<anonymous> (/home/ruben/repos/redis/test/good_stacks.spec.js:20:20)
at callFnAsync (/home/ruben/repos/redis/node_modules/mocha/lib/runnable.js:349:8)
at Test.Runnable.run (/home/ruben/repos/redis/node_modules/mocha/lib/runnable.js:301:7)
at Runner.runTest (/home/ruben/repos/redis/node_modules/mocha/lib/runner.js:422:10)
at /home/ruben/repos/redis/node_modules/mocha/lib/runner.js:528:12
at next (/home/ruben/repos/redis/node_modules/mocha/lib/runner.js:342:14)
at /home/ruben/repos/redis/node_modules/mocha/lib/runner.js:352:7
at next (/home/ruben/repos/redis/node_modules/mocha/lib/runner.js:284:14)
at Immediate._onImmediate (/home/ruben/repos/redis/node_modules/mocha/lib/runner.js:320:5)
at processImmediate [as _immediateCallback] (timers.js:383:17)
```
## How to Contribute
- Open a pull request or an issue about what you want to implement / change. We're glad for any help!
- Please be aware that we'll only accept fully tested code.
## Contributors
The original author of node_redis is [Matthew Ranney](https://github.com/mranney)
The current lead maintainer is [Ruben Bridgewater](https://github.com/BridgeAR)
Many [others](https://github.com/NodeRedis/node_redis/graphs/contributors)
contributed to `node_redis` too. Thanks to all of them!
## License
[MIT](LICENSE)
### Consolidation: It's time for celebration
Right now there are two great redis clients around and both have some advantages
above each other. We speak about ioredis and node_redis. So after talking to
each other about how we could improve in working together we (that is @luin and
@BridgeAR) decided to work towards a single library on the long run. But step by
step.
First of all, we want to split small parts of our libraries into others so that
we're both able to use the same code. Those libraries are going to be maintained
under the NodeRedis organization. This is going to reduce the maintenance
overhead, allows others to use the very same code, if they need it and it's way
easyer for others to contribute to both libraries.
We're very happy about this step towards working together as we both want to
give you the best redis experience possible.
If you want to join our cause by help maintaining something, please don't
hesitate to contact either one of us.

845
node_modules/redis/changelog.md generated vendored Normal file
View File

@@ -0,0 +1,845 @@
# Changelog
## v.2.8.0 - 31 Jul, 2017
Features
- Accept UPPER_CASE commands in send_command
- Add arbitrary commands to the prototype by using `Redis.addCommand(name)`
Bugfixes
- Fixed not always copying subscribe unsubscribe arguments
- Fixed emitting internal errors while reconnecting with auth
- Fixed crashing with invalid url option
## v.2.7.1 - 14 Mar, 2017
Bugfixes
- Fixed monitor mode not working in combination with IPv6 (2.6.0 regression)
## v.2.7.0 - 11 Mar, 2017
Features
- All returned errors are from now a subclass of `RedisError`.
Bugfixes
- Fixed rename_commands not accepting `null` as value
- Fixed `AbortError`s and `AggregateError`s not showing the error message in the stack trace
## v.2.6.5 - 15 Jan, 2017
Bugfixes
- Fixed parser not being reset in case the redis connection closed ASAP for overcoming of output buffer limits
- Fixed parser reset if (p)message_buffer listener is attached
## v.2.6.4 - 12 Jan, 2017
Bugfixes
- Fixed monitor mode not working in combination with IPv6, sockets or lua scripts (2.6.0 regression)
## v.2.6.3 - 31 Oct, 2016
Bugfixes
- Do not change the tls setting to camel_case
- Fix domain handling in combination with the offline queue (2.5.3 regression)
## v.2.6.2 - 16 Jun, 2016
Bugfixes
- Fixed individual callbacks of a transaction not being called (2.6.0 regression)
## v.2.6.1 - 02 Jun, 2016
Bugfixes
- Fixed invalid function name being exported
## v.2.6.0 - 01 Jun, 2016
In addition to the pre-releases the following changes exist in v.2.6.0:
Features
- Updated [redis-parser](https://github.com/NodeRedis/node-redis-parser) dependency ([changelog](https://github.com/NodeRedis/node-redis-parser/releases/tag/v.2.0.0))
- The JS parser is from now on the new default as it is a lot faster than the hiredis parser
- This is no BC as there is no changed behavior for the user at all but just a performance improvement. Explicitly requireing the Hiredis parser is still possible.
- Added name property to all Redis functions (Node.js >= 4.0)
- Improved stack traces in development and debug mode
Bugfixes
- Reverted support for `__proto__` (v.2.6.0-2) to prevent and breaking change
Deprecations
- The `parser` option is deprecated and should be removed. The built-in Javascript parser is a lot faster than the hiredis parser and has more features
## v.2.6.0-2 - 29 Apr, 2016
Features
- Added support for the new [CLIENT REPLY ON|OFF|SKIP](http://redis.io/commands/client-reply) command (Redis v.3.2)
- Added support for camelCase
- The Node.js landscape default is to use camelCase. node_redis is a bit out of the box here
but from now on it is possible to use both, just as you prefer!
- If there's any documented variable missing as camelCased, please open a issue for it
- Improve error handling significantly
- Only emit an error if the error has not already been handled in a callback
- Improved unspecific error messages e.g. "Connection gone from end / close event"
- Added `args` to command errors to improve identification of the error
- Added origin to errors if there's e.g. a connection error
- Added ReplyError class. All Redis errors are from now on going to be of that class
- Added AbortError class. A subclass of AbortError. All unresolved and by node_redis rejected commands are from now on of that class
- Added AggregateError class. If a unresolved and by node_redis rejected command has no callback and
this applies to more than a single command, the errors for the commands without callback are aggregated
to a single error that is emitted in debug_mode in that case.
- Added `message_buffer` / `pmessage_buffer` events. That event is always going to emit a buffer
- Listening to the `message` event at the same time is always going to return the same message as string
- Added callback option to the duplicate function
- Added support for `__proto__` and other reserved keywords as hgetall field
- Updated [redis-commands](https://github.com/NodeRedis/redis-commands) dependency ([changelog](https://github.com/NodeRedis/redis-commands/releases/tag/v.1.2.0))
Bugfixes
- Fixed v.2.5.0 auth command regression (under special circumstances a reconnect would not authenticate properly)
- Fixed v.2.6.0-0 pub sub mode and quit command regressions:
- Entering pub sub mode not working if a earlier called and still running command returned an error
- Unsubscribe callback not called if unsubscribing from all channels and resubscribing right away
- Quit command resulting in an error in some cases
- Fixed special handled functions in batch and multi context not working the same as without (e.g. select and info)
- Be aware that not all commands work in combination with transactions but they all work with batch
- Fixed address always set to 127.0.0.1:6379 in case host / port is set in the `tls` options instead of the general options
## v.2.6.0-1 - 01 Apr, 2016
A second pre-release with further fixes. This is likely going to be released as 2.6.0 stable without further changes.
Features
- Added type validations for client.send_command arguments
Bugfixes
- Fixed client.send_command not working properly with every command and every option
- Fixed pub sub mode unsubscribing from all channels in combination with the new `string_numbers` option crashing
- Fixed pub sub mode unsubscribing from all channels not respected while reconnecting
- Fixed pub sub mode events in combination with the `string_numbers` option emitting the number of channels not as number
## v.2.6.0-0 - 27 Mar, 2016
This is mainly a very important bug fix release with some smaller features.
Features
- Monitor and pub sub mode now work together with the offline queue
- All commands that were send after a connection loss are now going to be send after reconnecting
- Activating monitor mode does now work together with arbitrary commands including pub sub mode
- Pub sub mode is completely rewritten and all known issues fixed
- Added `string_numbers` option to get back strings instead of numbers
- Quit command is from now on always going to end the connection properly
Bugfixes
- Fixed calling monitor command while other commands are still running
- Fixed monitor and pub sub mode not working together
- Fixed monitor mode not working in combination with the offline queue
- Fixed pub sub mode not working in combination with the offline queue
- Fixed pub sub mode resubscribing not working with non utf8 buffer channels
- Fixed pub sub mode crashing if calling unsubscribe / subscribe in various combinations
- Fixed pub sub mode emitting unsubscribe even if no channels were unsubscribed
- Fixed pub sub mode emitting a message without a message published
- Fixed quit command not ending the connection and resulting in further reconnection if called while reconnecting
The quit command did not end connections earlier if the connection was down at that time and this could have
lead to strange situations, therefor this was fixed to end the connection right away in those cases.
## v.2.5.3 - 21 Mar, 2016
Bugfixes
- Revert throwing on invalid data types and print a warning instead
## v.2.5.2 - 16 Mar, 2016
Bugfixes
- Fixed breaking changes against Redis 2.4 introduced in 2.5.0 / 2.5.1
## v.2.5.1 - 15 Mar, 2016
Bugfixes
- Fixed info command not working anymore with optional section argument
## v.2.5.0 - 15 Mar, 2016
Same changelog as the pre-release
## v.2.5.0-1 - 07 Mar, 2016
This is a big release with some substantial underlining changes. Therefor this is released as a pre-release and I encourage anyone who's able to, to test this out.
It took way to long to release this one and the next release cycles will be shorter again.
This release is also going to deprecate a couple things to prepare for a future v.3 (it'll still take a while to v.3).
Features
- The parsers moved into the [redis-parser](https://github.com/NodeRedis/node-redis-parser) module and will be maintained in there from now on
- Improve js parser speed significantly for big SUNION/SINTER/LRANGE/ZRANGE
- Improve redis-url parsing to also accept the database-number and options as query parameters as suggested in [IANA](http://www.iana.org/assignments/uri-schemes/prov/redis)
- Added a `retry_unfulfilled_commands` option
- Setting this to 'true' results in retrying all commands that were not fulfilled on a connection loss after the reconnect. Use with caution
- Added a `db` option to select the database while connecting (this is [not recommended](https://groups.google.com/forum/#!topic/redis-db/vS5wX8X4Cjg))
- Added a `password` option as alias for auth_pass
- The client.server_info is from now on updated while using the info command
- Gracefuly handle redis protocol errors from now on
- Added a `warning` emitter that receives node_redis warnings like auth not required and deprecation messages
- Added a `retry_strategy` option that replaces all reconnect options
- The reconnecting event from now on also receives:
- The error message why the reconnect happened (params.error)
- The amount of times the client was connected (params.times_connected)
- The total reconnecting time since the last time connected (params.total_retry_time)
- Always respect the command execution order no matter if the reply could be returned sync or not (former exceptions: [#937](https://github.com/NodeRedis/node_redis/issues/937#issuecomment-167525939))
- redis.createClient is now checking input values stricter and detects more faulty input
- Started refactoring internals into individual modules
- Pipelining speed improvements
Bugfixes
- Fixed explicit undefined as a command callback in a multi context
- Fixed hmset failing to detect the first key as buffer or date if the key is of that type
- Fixed do not run toString on an array argument and throw a "invalid data" error instead
- This is not considered as breaking change, as this is likely a error in your code and if you want to have such a behavior you should handle this beforehand
- The same applies to Map / Set and individual Object types
- Fixed redis url not accepting the protocol being omitted or protocols other than the redis protocol for convenience
- Fixed parsing the db keyspace even if the first database does not begin with a zero
- Fixed handling of errors occurring while receiving pub sub messages
- Fixed huge string pipelines crashing NodeJS (Pipeline size above 256mb)
- Fixed rename_commands and prefix option not working together
- Fixed ready being emitted to early in case a slave is still syncing / master down
Deprecations
- Using any command with a argument being set to null or undefined is deprecated
- From v.3.0.0 on using a command with such an argument will return an error instead
- If you want to keep the old behavior please use a precheck in your code that converts the arguments to a string.
- Using SET or SETEX with a undefined or null value will from now on also result in converting the value to "null" / "undefined" to have a consistent behavior. This is not considered as breaking change, as it returned an error earlier.
- Using .end(flush) without the flush parameter is deprecated and the flush parameter should explicitly be used
- From v.3.0.0 on using .end without flush will result in an error
- Using .end without flush means that any command that did not yet return is going to silently fail. Therefor this is considered harmful and you should explicitly silence such errors if you are sure you want this
- Depending on the return value of a command to detect the backpressure is deprecated
- From version 3.0.0 on node_redis might not return true / false as a return value anymore. Please rely on client.should_buffer instead
- The `socket_nodelay` option is deprecated and will be removed in v.3.0.0
- If you want to buffer commands you should use [.batch or .multi](./README.md) instead. This is necessary to reduce the amount of different options and this is very likely reducing your throughput if set to false.
- If you are sure you want to activate the NAGLE algorithm you can still activate it by using client.stream.setNoDelay(false)
- The `max_attempts` option is deprecated and will be removed in v.3.0.0. Please use the `retry_strategy` instead
- The `retry_max_delay` option is deprecated and will be removed in v.3.0.0. Please use the `retry_strategy` instead
- The drain event is deprecated and will be removed in v.3.0.0. Please listen to the stream drain event instead
- The idle event is deprecated and will likely be removed in v.3.0.0. If you rely on this feature please open a new ticket in node_redis with your use case
- Redis < v. 2.6 is not officially supported anymore and might not work in all cases. Please update to a newer redis version as it is not possible to test for these old versions
- Removed non documented command syntax (adding the callback to an arguments array instead of passing it as individual argument)
## v.2.4.2 - 27 Nov, 2015
Bugfixes
- Fixed not emitting ready after reconnect with disable_resubscribing ([@maxgalbu](https://github.com/maxgalbu))
## v.2.4.1 - 25 Nov, 2015
Bugfixes
- Fixed a js parser regression introduced in 2.4.0 ([@BridgeAR](https://github.com/BridgeAR))
## v.2.4.0 - 25 Nov, 2015
Features
- Added `tls` option to initiate a connection to a redis server behind a TLS proxy. Thanks ([@paddybyers](https://github.com/paddybyers))
- Added `prefix` option to auto key prefix any command with the provided prefix ([@luin](https://github.com/luin) & [@BridgeAR](https://github.com/BridgeAR))
- Added `url` option to pass the connection url with the options object ([@BridgeAR](https://github.com/BridgeAR))
- Added `client.duplicate([options])` to duplicate the current client and return a new one with the same options ([@BridgeAR](https://github.com/BridgeAR))
- Improve performance by up to 20% on almost all use cases ([@BridgeAR](https://github.com/BridgeAR))
Bugfixes
- Fixed js parser handling big values slow ([@BridgeAR](https://github.com/BridgeAR))
- The speed is now on par with the hiredis parser.
## v.2.3.1 - 18 Nov, 2015
Bugfixes
- Fixed saving buffers with charsets other than utf-8 while using multi ([@BridgeAR](https://github.com/BridgeAR))
- Fixed js parser handling big values very slow ([@BridgeAR](https://github.com/BridgeAR))
- The speed is up to ~500% faster than before but still up to ~50% slower than the hiredis parser.
## v.2.3.0 - 30 Oct, 2015
Features
- Improve speed further for: ([@BridgeAR](https://github.com/BridgeAR))
- saving big strings (up to +300%)
- using .multi / .batch (up to +50% / on Node.js 0.10.x +300%)
- saving small buffers
- Increased coverage to 99% ([@BridgeAR](https://github.com/BridgeAR))
- Refactored manual backpressure control ([@BridgeAR](https://github.com/BridgeAR))
- Removed the high water mark and low water mark. Such a mechanism should be implemented by a user instead
- The `drain` event is from now on only emitted if the stream really had to buffer
- Reduced the default connect_timeout to be one hour instead of 24h ([@BridgeAR](https://github.com/BridgeAR))
- Added .path to redis.createClient(options); ([@BridgeAR](https://github.com/BridgeAR))
- Ignore info command, if not available on server ([@ivanB1975](https://github.com/ivanB1975))
Bugfixes
- Fixed a js parser error that could result in a timeout ([@BridgeAR](https://github.com/BridgeAR))
- Fixed .multi / .batch used with Node.js 0.10.x not working properly after a reconnect ([@BridgeAR](https://github.com/BridgeAR))
- Fixed fired but not yet returned commands not being rejected after a connection loss ([@BridgeAR](https://github.com/BridgeAR))
- Fixed connect_timeout not respected if no connection has ever been established ([@gagle](https://github.com/gagle) & [@benjie](https://github.com/benjie))
- Fixed return_buffers in pub sub mode ([@komachi](https://github.com/komachi))
## v.2.2.5 - 18 Oct, 2015
Bugfixes
- Fixed undefined options passed to a new instance not accepted (possible with individual .createClient functions) ([@BridgeAR](https://github.com/BridgeAR))
## v.2.2.4 - 17 Oct, 2015
Bugfixes
- Fixed unspecific error message for unresolvable commands ([@BridgeAR](https://github.com/BridgeAR))
- Fixed not allowed command error in pubsub mode not being returned in a provided callback ([@BridgeAR](https://github.com/BridgeAR))
- Fixed to many commands forbidden in pub sub mode ([@BridgeAR](https://github.com/BridgeAR))
- Fixed mutation of the arguments array passed to .multi / .batch constructor ([@BridgeAR](https://github.com/BridgeAR))
- Fixed mutation of the options object passed to createClient ([@BridgeAR](https://github.com/BridgeAR))
- Fixed error callback in .multi not called if connection in broken mode ([@BridgeAR](https://github.com/BridgeAR))
## v.2.2.3 - 14 Oct, 2015
Bugfixes
- Fixed multi not being executed on Node 0.10.x if node_redis not yet ready ([@BridgeAR](https://github.com/BridgeAR))
## v.2.2.2 - 14 Oct, 2015
Bugfixes
- Fixed regular commands not being executed after a .multi until .exec was called ([@BridgeAR](https://github.com/BridgeAR))
## v.2.2.1 - 12 Oct, 2015
No code change
## v.2.2.0 - 12 Oct, 2015 - The peregrino falcon
The peregrino falcon is the fasted bird on earth and this is what this release is all about: Increased performance for heavy usage by up to **400%** [sic!] and increased overall performance for any command as well. Please check the benchmarks in the [README.md](README.md) for further details.
Features
- Added rename_commands options to handle renamed commands from the redis config ([@digmxl](https://github.com/digmxl) & [@BridgeAR](https://github.com/BridgeAR))
- Added disable_resubscribing option to prevent a client from resubscribing after reconnecting ([@BridgeAR](https://github.com/BridgeAR))
- Increased performance ([@BridgeAR](https://github.com/BridgeAR))
- exchanging built in queue with [@petkaantonov](https://github.com/petkaantonov)'s [double-ended queue](https://github.com/petkaantonov/deque)
- prevent polymorphism
- optimize statements
- Added *.batch* command, similar to .multi but without transaction ([@BridgeAR](https://github.com/BridgeAR))
- Improved pipelining to minimize the [RTT](http://redis.io/topics/pipelining) further ([@BridgeAR](https://github.com/BridgeAR))
Bugfixes
- Fixed a javascript parser regression introduced in 2.0 that could result in timeouts on high load. ([@BridgeAR](https://github.com/BridgeAR))
- I was not able to write a regression test for this, since the error seems to only occur under heavy load with special conditions. So please have a look for timeouts with the js parser, if you use it and report all issues and switch to the hiredis parser in the meanwhile. If you're able to come up with a reproducable test case, this would be even better :)
- Fixed should_buffer boolean for .exec, .select and .auth commands not being returned and fix a couple special conditions ([@BridgeAR](https://github.com/BridgeAR))
If you do not rely on transactions but want to reduce the RTT you can use .batch from now on. It'll behave just the same as .multi but it does not have any transaction and therefor won't roll back any failed commands.<br>
Both .multi and .batch are from now on going to cache the commands and release them while calling .exec.
Please consider using .batch instead of looping through a lot of commands one by one. This will significantly improve your performance.
Here are some stats compared to ioredis 1.9.1 (Lenovo T450s i7-5600U):
simple set
82,496 op/s » ioredis
112,617 op/s » node_redis
simple get
82,015 op/s » ioredis
105,701 op/s » node_redis
simple get with pipeline
10,233 op/s » ioredis
26,541 op/s » node_redis (using .batch)
lrange 100
7,321 op/s » ioredis
26,155 op/s » node_redis
publish
90,524 op/s » ioredis
112,823 op/s » node_redis
subscribe
43,783 op/s » ioredis
61,889 op/s » node_redis
To conclude: we can proudly say that node_redis is very likely outperforming any other node redis client.
Known issues
- The pub sub system has some flaws and those will be addressed in the next minor release
## v2.1.0 - Oct 02, 2015
Features:
- Addded optional flush parameter to `.end`. If set to true, commands fired after using .end are going to be rejected instead of being ignored. (@crispy1989)
- Addded: host and port can now be provided in a single options object. E.g. redis.createClient({ host: 'localhost', port: 1337, max_attempts: 5 }); (@BridgeAR)
- Speedup common cases (@BridgeAR)
Bugfixes:
- Fix argument mutation while using the array notation with the multi constructor (@BridgeAR)
- Fix multi.hmset key not being type converted if used with an object and key not being a string (@BridgeAR)
- Fix parser errors not being catched properly (@BridgeAR)
- Fix a crash that could occur if a redis server does not return the info command as usual #541 (@BridgeAR)
- Explicitly passing undefined as a callback statement will work again. E.g. client.publish('channel', 'message', undefined); (@BridgeAR)
## v2.0.1 - Sep 24, 2015
Bugfixes:
- Fix argument mutation while using the array notation in combination with keys / callbacks ([#866](.)). (@BridgeAR)
## v2.0.0 - Sep 21, 2015
This is the biggest release that node_redis had since it was released in 2010. A long list of outstanding bugs has been fixed, so we are very happy to present you redis 2.0 and we highly recommend updating as soon as possible.
# What's new in 2.0
- Implemented a "connection is broken" mode if no connection could be established
- node_redis no longer throws under any circumstances, preventing it from terminating applications.
- Multi error handling is now working properly
- Consistent command behavior including multi
- Windows support
- Improved performance
- A lot of code cleanup
- Many bug fixes
- Better user support!
## Features:
- Added a "redis connection is broken" mode after reaching max connection attempts / exceeding connection timeout. (@BridgeAR)
- Added NODE_DEBUG=redis env to activate the debug_mode (@BridgeAR)
- Added a default connection timeout of 24h instead of never timing out as a default (@BridgeAR)
- Added: Network errors and other stream errors will from now on include the error code as `err.code` property (@BridgeAR)
- Added: Errors thrown by redis will now include the redis error code as `err.code` property. (@skeggse & @BridgeAR)
- Added: Errors thrown by node_redis will now include a `err.command` property for the command used (@BridgeAR)
- Added new commands and drop support for deprecated *substr* (@BridgeAR)
- Added new possibilities how to provide the command arguments (@BridgeAR)
- The entries in the keyspace of the server_info is now an object instead of a string. (@SinisterLight & @BridgeAR)
- Small speedup here and there (e.g. by not using .toLowerCase() anymore) (@BridgeAR)
- Full windows support (@bcoe)
- Increased coverage by 10% and add a lot of tests to make sure everything works as it should. We now reached 97% :-) (@BridgeAR)
- Remove dead code, clean up and refactor very old chunks (@BridgeAR)
- Don't flush the offline queue if reconnecting (@BridgeAR)
- Emit all errors insteaf of throwing sometimes and sometimes emitting them (@BridgeAR)
- *auth_pass* passwords are now checked to be a valid password (@jcppman & @BridgeAR)
## Bug fixes:
- Don't kill the app anymore by randomly throwing errors sync instead of emitting them (@BridgeAR)
- Don't catch user errors anymore occuring in callbacks (no try callback anymore & more fixes for the parser) (@BridgeAR)
- Early garbage collection of queued items (@dohse)
- Fix js parser returning errors as strings (@BridgeAR)
- Do not wrap errors into other errors (@BridgeAR)
- Authentication failures are now returned in the callback instead of being emitted (@BridgeAR)
- Fix a memory leak on reconnect (@rahar)
- Using `send_command` directly may now also be called without the args as stated in the [README.md](./README.md) (@BridgeAR)
- Fix the multi.exec error handling (@BridgeAR)
- Fix commands being inconsistent and behaving wrong (@BridgeAR)
- Channel names with spaces are now properly resubscribed after a reconnection (@pbihler)
- Do not try to reconnect after the connection timeout has been exceeded (@BridgeAR)
- Ensure the execution order is observed if using .eval (@BridgeAR)
- Fix commands not being rejected after calling .quit (@BridgeAR)
- Fix .auth calling the callback twice if already connected (@BridgeAR)
- Fix detect_buffers not working in pub sub mode and while monitoring (@BridgeAR)
- Fix channel names always being strings instead of buffers while return_buffers is true (@BridgeAR)
- Don't print any debug statements if not asked for (@BridgeAR)
- Fix a couple small other bugs
## Breaking changes:
1. redis.send_command commands have to be lower case from now on. This does only apply if you use `.send_command` directly instead of the convenient methods like `redis.command`.
2. Error messages have changed quite a bit. If you depend on a specific wording please check your application carfully.
3. Errors are from now on always either returned if a callback is present or emitted. They won't be thrown (neither sync, nor async).
4. The Multi error handling has changed a lot!
- All errors are from now on errors instead of strings (this only applied to the js parser).
- If an error occurs while queueing the commands an EXECABORT error will be returned including the failed commands as `.errors` property instead of an array with errors.
- If an error occurs while executing the commands and that command has a callback it'll return the error as first parameter (`err, undefined` instead of `null, undefined`).
- All the errors occuring while executing the commands will stay in the result value as error instance (if you used the js parser before they would have been strings). Be aware that the transaction won't be aborted if those error occurr!
- If `multi.exec` does not have a callback and an EXECABORT error occurrs, it'll emit that error instead.
5. If redis can't connect to your redis server it'll give up after a certain point of failures (either max connection attempts or connection timeout exceeded). If that is the case it'll emit an CONNECTION_BROKEN error. You'll have to initiate a new client to try again afterwards.
6. The offline queue is not flushed anymore on a reconnect. It'll stay until node_redis gives up trying to reach the server or until you close the connection.
7. Before this release node_redis catched user errors and threw them async back. This is not the case anymore! No user behavior of what so ever will be tracked or catched.
8. The keyspace of `redis.server_info` (db0...) is from now on an object instead of an string.
NodeRedis also thanks @qdb, @tobek, @cvibhagool, @frewsxcv, @davidbanham, @serv, @vitaliylag, @chrishamant, @GamingCoder and all other contributors that I may have missed for their contributions!
From now on we'll push new releases more frequently out and fix further long outstanding things and implement new features.
<hr>
## v1.0.0 - Aug 30, 2015
* Huge issue and pull-request cleanup. Thanks Blain! (@blainsmith)
* [#658](https://github.com/NodeRedis/node_redis/pull/658) Client now parses URL-format connection strings (e.g., redis://foo:pass@127.0.0.1:8080) (@kuwabarahiroshi)
* [#749](https://github.com/NodeRedis/node_redis/pull/749) Fix reconnection bug when client is in monitoring mode (@danielbprice)
* [#786](https://github.com/NodeRedis/node_redis/pull/786) Refactor createClient. Fixes #651 (@BridgeAR)
* [#793](https://github.com/NodeRedis/node_redis/pull/793) Refactor tests and improve test coverage (@erinspice, @bcoe)
* [#733](https://github.com/NodeRedis/node_redis/pull/733) Fixes detect_buffers functionality in the context of exec. Fixes #732, #263 (@raydog)
* [#785](https://github.com/NodeRedis/node_redis/pull/785) Tiny speedup by using 'use strict' (@BridgeAR)
* Fix extraneous error output due to pubsub tests (Mikael Kohlmyr)
## v0.12.1 - Aug 10, 2014
* Fix IPv6/IPv4 family selection in node 0.11+ (Various)
## v0.12.0 - Aug 9, 2014
* Fix unix socket support (Jack Tang)
* Improve createClient argument handling (Jack Tang)
## v0.11.0 - Jul 10, 2014
* IPv6 Support. (Yann Stephan)
* Revert error emitting and go back to throwing errors. (Bryce Baril)
* Set socket_keepalive to prevent long-lived client timeouts. (mohit)
* Correctly reset retry timer. (ouotuo)
* Domains protection from bad user exit. (Jake Verbaten)
* Fix reconnection socket logic to prevent misqueued entries. (Iain Proctor)
## v0.10.3 - May 22, 2014
* Update command list to match Redis 2.8.9 (Charles Feng)
## v0.10.2 - May 18, 2014
* Better binary key handling for HGETALL. (Nick Apperson)
* Fix test not resetting `error` handler. (CrypticSwarm)
* Fix SELECT error semantics. (Bryan English)
## v0.10.1 - February 17, 2014
* Skip plucking redis version from the INFO stream if INFO results weren't provided. (Robert Sköld)
## v0.10.0 - December 21, 2013
* Instead of throwing errors asynchronously, emit errors on client. (Bryce Baril)
## v0.9.2 - December 15, 2013
* Regenerate commands for new 2.8.x Redis commands. (Marek Ventur)
* Correctly time reconnect counts when using 'auth'. (William Hockey)
## v0.9.1 - November 23, 2013
* Allow hmset to accept numeric keys. (Alex Stokes)
* Fix TypeError for multiple MULTI/EXEC errors. (Kwangsu Kim)
## v0.9.0 - October 17, 2013
* Domains support. (Forrest L Norvell)
## v0.8.6 - October 2, 2013
* If error is already an Error, don't wrap it in another Error. (Mathieu M-Gosselin)
* Fix retry delay logic (Ian Babrou)
* Return Errors instead of strings where Errors are expected (Ian Babrou)
* Add experimental `.unref()` method to RedisClient (Bryce Baril / Olivier Lalonde)
* Strengthen checking of reply to prevent conflating "message" or "pmessage" fields with pub_sub replies. (Bryce Baril)
## v0.8.5 - September 26, 2013
* Add `auth_pass` option to connect and immediately authenticate (Henrik Peinar)
## v0.8.4 - June 24, 2013
Many contributed features and fixes, including:
* Ignore password set if not needed. (jbergknoff)
* Improved compatibility with 0.10.X for tests and client.end() (Bryce Baril)
* Protect connection retries from application exceptions. (Amos Barreto)
* Better exception handling for Multi/Exec (Thanasis Polychronakis)
* Renamed pubsub mode to subscriber mode (Luke Plaster)
* Treat SREM like SADD when passed an array (Martin Ciparelli)
* Fix empty unsub/punsub TypeError (Jeff Barczewski)
* Only attempt to run a callback if it one was provided (jifeng)
## v0.8.3 - April 09, 2013
Many contributed features and fixes, including:
* Fix some tests for Node.js version 0.9.x+ changes (Roman Ivanilov)
* Fix error when commands submitted after idle event handler (roamm)
* Bypass Redis for no-op SET/SETEX commands (jifeng)
* Fix HMGET + detect_buffers (Joffrey F)
* Fix CLIENT LOAD functionality (Jonas Dohse)
* Add percentage outputs to diff_multi_bench_output.js (Bryce Baril)
* Add retry_max_delay option (Tomasz Durka)
* Fix parser off-by-one errors with nested multi-bulk replies (Bryce Baril)
* Prevent parser from sinking application-side exceptions (Bryce Baril)
* Fix parser incorrect buffer skip when parsing multi-bulk errors (Bryce Baril)
* Reverted previous change with throwing on non-string values with HMSET (David Trejo)
* Fix command queue sync issue when using pubsub (Tom Leach)
* Fix compatibility with two-word Redis commands (Jonas Dohse)
* Add EVAL with array syntax (dmoena)
* Fix tests due to Redis reply order changes in 2.6.5+ (Bryce Baril)
* Added a test for the SLOWLOG command (Nitesh Sinha)
* Fix SMEMBERS order dependency in test broken by Redis changes (Garrett Johnson)
* Update commands for new Redis commands (David Trejo)
* Prevent exception from SELECT on subscriber reconnection (roamm)
## v0.8.2 - November 11, 2012
Another version bump because 0.8.1 didn't get applied properly for some mysterious reason.
Sorry about that.
Changed name of "faster" parser to "javascript".
## v0.8.1 - September 11, 2012
Important bug fix for null responses (Jerry Sievert)
## v0.8.0 - September 10, 2012
Many contributed features and fixes, including:
* Pure JavaScript reply parser that is usually faster than hiredis (Jerry Sievert)
* Remove hiredis as optionalDependency from package.json. It still works if you want it.
* Restore client state on reconnect, including select, subscribe, and monitor. (Ignacio Burgueño)
* Fix idle event (Trae Robrock)
* Many documentation improvements and bug fixes (David Trejo)
## 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.

1105
node_modules/redis/index.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

16
node_modules/redis/lib/command.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
'use strict';
var betterStackTraces = /development/i.test(process.env.NODE_ENV) || /\bredis\b/i.test(process.env.NODE_DEBUG);
function Command (command, args, callback, call_on_write) {
this.command = command;
this.args = args;
this.buffer_args = false;
this.callback = callback;
this.call_on_write = call_on_write;
if (betterStackTraces) {
this.error = new Error();
}
}
module.exports = Command;

121
node_modules/redis/lib/commands.js generated vendored Normal file
View File

@@ -0,0 +1,121 @@
'use strict';
var commands = require('redis-commands');
var Multi = require('./multi');
var RedisClient = require('../').RedisClient;
var Command = require('./command');
// Feature detect if a function may change it's name
var changeFunctionName = (function () {
var fn = function abc () {};
try {
Object.defineProperty(fn, 'name', {
value: 'foobar'
});
return true;
} catch (e) {
return false;
}
}());
var addCommand = function (command) {
// Some rare Redis commands use special characters in their command name
// Convert those to a underscore to prevent using invalid function names
var commandName = command.replace(/(?:^([0-9])|[^a-zA-Z0-9_$])/g, '_$1');
// Do not override existing functions
if (!RedisClient.prototype[command]) {
RedisClient.prototype[command.toUpperCase()] = RedisClient.prototype[command] = function () {
var arr;
var len = arguments.length;
var callback;
var i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0];
if (len === 2) {
callback = arguments[1];
}
} else if (len > 1 && Array.isArray(arguments[1])) {
if (len === 3) {
callback = arguments[2];
}
len = arguments[1].length;
arr = new Array(len + 1);
arr[0] = arguments[0];
for (; i < len; i += 1) {
arr[i + 1] = arguments[1][i];
}
} else {
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
return this.internal_send_command(new Command(command, arr, callback));
};
// Alias special function names (e.g. NR.RUN becomes NR_RUN and nr_run)
if (commandName !== command) {
RedisClient.prototype[commandName.toUpperCase()] = RedisClient.prototype[commandName] = RedisClient.prototype[command];
}
if (changeFunctionName) {
Object.defineProperty(RedisClient.prototype[command], 'name', {
value: commandName
});
}
}
// Do not override existing functions
if (!Multi.prototype[command]) {
Multi.prototype[command.toUpperCase()] = Multi.prototype[command] = function () {
var arr;
var len = arguments.length;
var callback;
var i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0];
if (len === 2) {
callback = arguments[1];
}
} else if (len > 1 && Array.isArray(arguments[1])) {
if (len === 3) {
callback = arguments[2];
}
len = arguments[1].length;
arr = new Array(len + 1);
arr[0] = arguments[0];
for (; i < len; i += 1) {
arr[i + 1] = arguments[1][i];
}
} else {
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
this.queue.push(new Command(command, arr, callback));
return this;
};
// Alias special function names (e.g. NR.RUN becomes NR_RUN and nr_run)
if (commandName !== command) {
Multi.prototype[commandName.toUpperCase()] = Multi.prototype[commandName] = Multi.prototype[command];
}
if (changeFunctionName) {
Object.defineProperty(Multi.prototype[command], 'name', {
value: commandName
});
}
}
};
commands.list.forEach(addCommand);
module.exports = addCommand;

80
node_modules/redis/lib/createClient.js generated vendored Normal file
View File

@@ -0,0 +1,80 @@
'use strict';
var utils = require('./utils');
var URL = require('url');
module.exports = function createClient (port_arg, host_arg, options) {
if (typeof port_arg === 'number' || typeof port_arg === 'string' && /^\d+$/.test(port_arg)) {
var host;
if (typeof host_arg === 'string') {
host = host_arg;
} else {
if (options && host_arg) {
throw new TypeError('Unknown type of connection in createClient()');
}
options = options || host_arg;
}
options = utils.clone(options);
options.host = host || options.host;
options.port = port_arg;
} else if (typeof port_arg === 'string' || port_arg && port_arg.url) {
options = utils.clone(port_arg.url ? port_arg : host_arg || options);
var url = port_arg.url || port_arg;
var parsed = URL.parse(url, true, true);
// [redis:]//[[user][:password]@][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]]
if (parsed.slashes) { // We require slashes
if (parsed.auth) {
options.password = parsed.auth.split(':')[1];
}
if (parsed.protocol && parsed.protocol !== 'redis:') {
console.warn('node_redis: WARNING: You passed "' + parsed.protocol.substring(0, parsed.protocol.length - 1) + '" as protocol instead of the "redis" protocol!');
}
if (parsed.pathname && parsed.pathname !== '/') {
options.db = parsed.pathname.substr(1);
}
if (parsed.hostname) {
options.host = parsed.hostname;
}
if (parsed.port) {
options.port = parsed.port;
}
if (parsed.search !== '') {
var elem;
for (elem in parsed.query) {
// If options are passed twice, only the parsed options will be used
if (elem in options) {
if (options[elem] === parsed.query[elem]) {
console.warn('node_redis: WARNING: You passed the ' + elem + ' option twice!');
} else {
throw new RangeError('The ' + elem + ' option is added twice and does not match');
}
}
options[elem] = parsed.query[elem];
}
}
} else if (parsed.hostname) {
throw new RangeError('The redis url must begin with slashes "//" or contain slashes after the redis protocol');
} else {
options.path = url;
}
} else if (typeof port_arg === 'object' || port_arg === undefined) {
options = utils.clone(port_arg || options);
options.host = options.host || host_arg;
if (port_arg && arguments.length !== 1) {
throw new TypeError('To many arguments passed to createClient. Please only pass the options object');
}
}
if (!options) {
throw new TypeError('Unknown type of connection in createClient()');
}
return options;
};

59
node_modules/redis/lib/customErrors.js generated vendored Normal file
View File

@@ -0,0 +1,59 @@
'use strict';
var util = require('util');
var assert = require('assert');
var RedisError = require('redis-parser').RedisError;
var ADD_STACKTRACE = false;
function AbortError (obj, stack) {
assert(obj, 'The options argument is required');
assert.strictEqual(typeof obj, 'object', 'The options argument has to be of type object');
RedisError.call(this, obj.message, ADD_STACKTRACE);
Object.defineProperty(this, 'message', {
value: obj.message || '',
configurable: true,
writable: true
});
if (stack || stack === undefined) {
Error.captureStackTrace(this, AbortError);
}
for (var keys = Object.keys(obj), key = keys.pop(); key; key = keys.pop()) {
this[key] = obj[key];
}
}
function AggregateError (obj) {
assert(obj, 'The options argument is required');
assert.strictEqual(typeof obj, 'object', 'The options argument has to be of type object');
AbortError.call(this, obj, ADD_STACKTRACE);
Object.defineProperty(this, 'message', {
value: obj.message || '',
configurable: true,
writable: true
});
Error.captureStackTrace(this, AggregateError);
for (var keys = Object.keys(obj), key = keys.pop(); key; key = keys.pop()) {
this[key] = obj[key];
}
}
util.inherits(AbortError, RedisError);
util.inherits(AggregateError, AbortError);
Object.defineProperty(AbortError.prototype, 'name', {
value: 'AbortError',
configurable: true,
writable: true
});
Object.defineProperty(AggregateError.prototype, 'name', {
value: 'AggregateError',
configurable: true,
writable: true
});
module.exports = {
AbortError: AbortError,
AggregateError: AggregateError
};

11
node_modules/redis/lib/debug.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
'use strict';
var index = require('../');
function debug () {
if (index.debug_mode) {
console.error.apply(null, arguments);
}
}
module.exports = debug;

113
node_modules/redis/lib/extendedApi.js generated vendored Normal file
View File

@@ -0,0 +1,113 @@
'use strict';
var utils = require('./utils');
var debug = require('./debug');
var RedisClient = require('../').RedisClient;
var Command = require('./command');
var noop = function () {};
/**********************************************
All documented and exposed API belongs in here
**********************************************/
// Redirect calls to the appropriate function and use to send arbitrary / not supported commands
RedisClient.prototype.send_command = RedisClient.prototype.sendCommand = function (command, args, callback) {
// Throw to fail early instead of relying in order in this case
if (typeof command !== 'string') {
throw new TypeError('Wrong input type "' + (command !== null && command !== undefined ? command.constructor.name : command) + '" for command name');
}
command = command.toLowerCase();
if (!Array.isArray(args)) {
if (args === undefined || args === null) {
args = [];
} else if (typeof args === 'function' && callback === undefined) {
callback = args;
args = [];
} else {
throw new TypeError('Wrong input type "' + args.constructor.name + '" for args');
}
}
if (typeof callback !== 'function' && callback !== undefined) {
throw new TypeError('Wrong input type "' + (callback !== null ? callback.constructor.name : 'null') + '" for callback function');
}
// Using the raw multi command is only possible with this function
// If the command is not yet added to the client, the internal function should be called right away
// Otherwise we need to redirect the calls to make sure the internal functions don't get skipped
// The internal functions could actually be used for any non hooked function
// but this might change from time to time and at the moment there's no good way to distinguish them
// from each other, so let's just do it do it this way for the time being
if (command === 'multi' || typeof this[command] !== 'function') {
return this.internal_send_command(new Command(command, args, callback));
}
if (typeof callback === 'function') {
args = args.concat([callback]); // Prevent manipulating the input array
}
return this[command].apply(this, args);
};
RedisClient.prototype.end = function (flush) {
// Flush queue if wanted
if (flush) {
this.flush_and_error({
message: 'Connection forcefully ended and command aborted.',
code: 'NR_CLOSED'
});
} else if (arguments.length === 0) {
this.warn(
'Using .end() without the flush parameter is deprecated and throws from v.3.0.0 on.\n' +
'Please check the doku (https://github.com/NodeRedis/node_redis) and explictly use flush.'
);
}
// Clear retry_timer
if (this.retry_timer) {
clearTimeout(this.retry_timer);
this.retry_timer = null;
}
this.stream.removeAllListeners();
this.stream.on('error', noop);
this.connected = false;
this.ready = false;
this.closing = true;
return this.stream.destroySoon();
};
RedisClient.prototype.unref = function () {
if (this.connected) {
debug("Unref'ing the socket connection");
this.stream.unref();
} else {
debug('Not connected yet, will unref later');
this.once('connect', function () {
this.unref();
});
}
};
RedisClient.prototype.duplicate = function (options, callback) {
if (typeof options === 'function') {
callback = options;
options = null;
}
var existing_options = utils.clone(this.options);
options = utils.clone(options);
for (var elem in options) {
existing_options[elem] = options[elem];
}
var client = new RedisClient(existing_options);
client.selected_db = this.selected_db;
if (typeof callback === 'function') {
var ready_listener = function () {
callback(null, client);
client.removeAllListeners(error_listener);
};
var error_listener = function (err) {
callback(err);
client.end(true);
};
client.once('ready', ready_listener);
client.once('error', error_listener);
return;
}
return client;
};

617
node_modules/redis/lib/individualCommands.js generated vendored Normal file
View File

@@ -0,0 +1,617 @@
'use strict';
var utils = require('./utils');
var debug = require('./debug');
var Multi = require('./multi');
var Command = require('./command');
var no_password_is_set = /no password is set/;
var loading = /LOADING/;
var RedisClient = require('../').RedisClient;
/********************************************************************************************
Replace built-in redis functions
The callback may be hooked as needed. The same does not apply to the rest of the function.
State should not be set outside of the callback if not absolutly necessary.
This is important to make sure it works the same as single command or in a multi context.
To make sure everything works with the offline queue use the "call_on_write" function.
This is going to be executed while writing to the stream.
TODO: Implement individal command generation as soon as possible to prevent divergent code
on single and multi calls!
********************************************************************************************/
RedisClient.prototype.multi = RedisClient.prototype.MULTI = function multi (args) {
var multi = new Multi(this, args);
multi.exec = multi.EXEC = multi.exec_transaction;
return multi;
};
// ATTENTION: This is not a native function but is still handled as a individual command as it behaves just the same as multi
RedisClient.prototype.batch = RedisClient.prototype.BATCH = function batch (args) {
return new Multi(this, args);
};
function select_callback (self, db, callback) {
return function (err, res) {
if (err === null) {
// Store db in this.select_db to restore it on reconnect
self.selected_db = db;
}
utils.callback_or_emit(self, callback, err, res);
};
}
RedisClient.prototype.select = RedisClient.prototype.SELECT = function select (db, callback) {
return this.internal_send_command(new Command('select', [db], select_callback(this, db, callback)));
};
Multi.prototype.select = Multi.prototype.SELECT = function select (db, callback) {
this.queue.push(new Command('select', [db], select_callback(this._client, db, callback)));
return this;
};
RedisClient.prototype.monitor = RedisClient.prototype.MONITOR = function monitor (callback) {
// Use a individual command, as this is a special case that does not has to be checked for any other command
var self = this;
var call_on_write = function () {
// Activating monitor mode has to happen before Redis returned the callback. The monitor result is returned first.
// Therefore we expect the command to be properly processed. If this is not the case, it's not an issue either.
self.monitoring = true;
};
return this.internal_send_command(new Command('monitor', [], callback, call_on_write));
};
// Only works with batch, not in a transaction
Multi.prototype.monitor = Multi.prototype.MONITOR = function monitor (callback) {
// Use a individual command, as this is a special case that does not has to be checked for any other command
if (this.exec !== this.exec_transaction) {
var self = this;
var call_on_write = function () {
self._client.monitoring = true;
};
this.queue.push(new Command('monitor', [], callback, call_on_write));
return this;
}
// Set multi monitoring to indicate the exec that it should abort
// Remove this "hack" as soon as Redis might fix this
this.monitoring = true;
return this;
};
function quit_callback (self, callback) {
return function (err, res) {
if (err && err.code === 'NR_CLOSED') {
// Pretent the quit command worked properly in this case.
// Either the quit landed in the offline queue and was flushed at the reconnect
// or the offline queue is deactivated and the command was rejected right away
// or the stream is not writable
// or while sending the quit, the connection ended / closed
err = null;
res = 'OK';
}
utils.callback_or_emit(self, callback, err, res);
if (self.stream.writable) {
// If the socket is still alive, kill it. This could happen if quit got a NR_CLOSED error code
self.stream.destroy();
}
};
}
RedisClient.prototype.QUIT = RedisClient.prototype.quit = function quit (callback) {
// TODO: Consider this for v.3
// Allow the quit command to be fired as soon as possible to prevent it landing in the offline queue.
// this.ready = this.offline_queue.length === 0;
var backpressure_indicator = this.internal_send_command(new Command('quit', [], quit_callback(this, callback)));
// Calling quit should always end the connection, no matter if there's a connection or not
this.closing = true;
this.ready = false;
return backpressure_indicator;
};
// Only works with batch, not in a transaction
Multi.prototype.QUIT = Multi.prototype.quit = function quit (callback) {
var self = this._client;
var call_on_write = function () {
// If called in a multi context, we expect redis is available
self.closing = true;
self.ready = false;
};
this.queue.push(new Command('quit', [], quit_callback(self, callback), call_on_write));
return this;
};
function info_callback (self, callback) {
return function (err, res) {
if (res) {
var obj = {};
var lines = res.toString().split('\r\n');
var line, parts, sub_parts;
for (var i = 0; i < lines.length; i++) {
parts = lines[i].split(':');
if (parts[1]) {
if (parts[0].indexOf('db') === 0) {
sub_parts = parts[1].split(',');
obj[parts[0]] = {};
while (line = sub_parts.pop()) {
line = line.split('=');
obj[parts[0]][line[0]] = +line[1];
}
} else {
obj[parts[0]] = parts[1];
}
}
}
obj.versions = [];
if (obj.redis_version) {
obj.redis_version.split('.').forEach(function (num) {
obj.versions.push(+num);
});
}
// Expose info key/vals to users
self.server_info = obj;
} else {
self.server_info = {};
}
utils.callback_or_emit(self, callback, err, res);
};
}
// Store info in this.server_info after each call
RedisClient.prototype.info = RedisClient.prototype.INFO = function info (section, callback) {
var args = [];
if (typeof section === 'function') {
callback = section;
} else if (section !== undefined) {
args = Array.isArray(section) ? section : [section];
}
return this.internal_send_command(new Command('info', args, info_callback(this, callback)));
};
Multi.prototype.info = Multi.prototype.INFO = function info (section, callback) {
var args = [];
if (typeof section === 'function') {
callback = section;
} else if (section !== undefined) {
args = Array.isArray(section) ? section : [section];
}
this.queue.push(new Command('info', args, info_callback(this._client, callback)));
return this;
};
function auth_callback (self, pass, callback) {
return function (err, res) {
if (err) {
if (no_password_is_set.test(err.message)) {
self.warn('Warning: Redis server does not require a password, but a password was supplied.');
err = null;
res = 'OK';
} else if (loading.test(err.message)) {
// If redis is still loading the db, it will not authenticate and everything else will fail
debug('Redis still loading, trying to authenticate later');
setTimeout(function () {
self.auth(pass, callback);
}, 100);
return;
}
}
utils.callback_or_emit(self, callback, err, res);
};
}
RedisClient.prototype.auth = RedisClient.prototype.AUTH = function auth (pass, callback) {
debug('Sending auth to ' + this.address + ' id ' + this.connection_id);
// Stash auth for connect and reconnect.
this.auth_pass = pass;
var ready = this.ready;
this.ready = ready || this.offline_queue.length === 0;
var tmp = this.internal_send_command(new Command('auth', [pass], auth_callback(this, pass, callback)));
this.ready = ready;
return tmp;
};
// Only works with batch, not in a transaction
Multi.prototype.auth = Multi.prototype.AUTH = function auth (pass, callback) {
debug('Sending auth to ' + this.address + ' id ' + this.connection_id);
// Stash auth for connect and reconnect.
this.auth_pass = pass;
this.queue.push(new Command('auth', [pass], auth_callback(this._client, callback)));
return this;
};
RedisClient.prototype.client = RedisClient.prototype.CLIENT = function client () {
var arr,
len = arguments.length,
callback,
i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0];
callback = arguments[1];
} else if (Array.isArray(arguments[1])) {
if (len === 3) {
callback = arguments[2];
}
len = arguments[1].length;
arr = new Array(len + 1);
arr[0] = arguments[0];
for (; i < len; i += 1) {
arr[i + 1] = arguments[1][i];
}
} else {
len = arguments.length;
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
var self = this;
var call_on_write = undefined;
// CLIENT REPLY ON|OFF|SKIP
/* istanbul ignore next: TODO: Remove this as soon as Travis runs Redis 3.2 */
if (arr.length === 2 && arr[0].toString().toUpperCase() === 'REPLY') {
var reply_on_off = arr[1].toString().toUpperCase();
if (reply_on_off === 'ON' || reply_on_off === 'OFF' || reply_on_off === 'SKIP') {
call_on_write = function () {
self.reply = reply_on_off;
};
}
}
return this.internal_send_command(new Command('client', arr, callback, call_on_write));
};
Multi.prototype.client = Multi.prototype.CLIENT = function client () {
var arr,
len = arguments.length,
callback,
i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0];
callback = arguments[1];
} else if (Array.isArray(arguments[1])) {
if (len === 3) {
callback = arguments[2];
}
len = arguments[1].length;
arr = new Array(len + 1);
arr[0] = arguments[0];
for (; i < len; i += 1) {
arr[i + 1] = arguments[1][i];
}
} else {
len = arguments.length;
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
var self = this._client;
var call_on_write = undefined;
// CLIENT REPLY ON|OFF|SKIP
/* istanbul ignore next: TODO: Remove this as soon as Travis runs Redis 3.2 */
if (arr.length === 2 && arr[0].toString().toUpperCase() === 'REPLY') {
var reply_on_off = arr[1].toString().toUpperCase();
if (reply_on_off === 'ON' || reply_on_off === 'OFF' || reply_on_off === 'SKIP') {
call_on_write = function () {
self.reply = reply_on_off;
};
}
}
this.queue.push(new Command('client', arr, callback, call_on_write));
return this;
};
RedisClient.prototype.hmset = RedisClient.prototype.HMSET = function hmset () {
var arr,
len = arguments.length,
callback,
i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0];
callback = arguments[1];
} else if (Array.isArray(arguments[1])) {
if (len === 3) {
callback = arguments[2];
}
len = arguments[1].length;
arr = new Array(len + 1);
arr[0] = arguments[0];
for (; i < len; i += 1) {
arr[i + 1] = arguments[1][i];
}
} else if (typeof arguments[1] === 'object' && (arguments.length === 2 || arguments.length === 3 && (typeof arguments[2] === 'function' || typeof arguments[2] === 'undefined'))) {
arr = [arguments[0]];
for (var field in arguments[1]) {
arr.push(field, arguments[1][field]);
}
callback = arguments[2];
} else {
len = arguments.length;
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
return this.internal_send_command(new Command('hmset', arr, callback));
};
Multi.prototype.hmset = Multi.prototype.HMSET = function hmset () {
var arr,
len = arguments.length,
callback,
i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0];
callback = arguments[1];
} else if (Array.isArray(arguments[1])) {
if (len === 3) {
callback = arguments[2];
}
len = arguments[1].length;
arr = new Array(len + 1);
arr[0] = arguments[0];
for (; i < len; i += 1) {
arr[i + 1] = arguments[1][i];
}
} else if (typeof arguments[1] === 'object' && (arguments.length === 2 || arguments.length === 3 && (typeof arguments[2] === 'function' || typeof arguments[2] === 'undefined'))) {
arr = [arguments[0]];
for (var field in arguments[1]) {
arr.push(field, arguments[1][field]);
}
callback = arguments[2];
} else {
len = arguments.length;
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
this.queue.push(new Command('hmset', arr, callback));
return this;
};
RedisClient.prototype.subscribe = RedisClient.prototype.SUBSCRIBE = function subscribe () {
var arr,
len = arguments.length,
callback,
i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0].slice(0);
callback = arguments[1];
} else {
len = arguments.length;
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
var self = this;
var call_on_write = function () {
self.pub_sub_mode = self.pub_sub_mode || self.command_queue.length + 1;
};
return this.internal_send_command(new Command('subscribe', arr, callback, call_on_write));
};
Multi.prototype.subscribe = Multi.prototype.SUBSCRIBE = function subscribe () {
var arr,
len = arguments.length,
callback,
i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0].slice(0);
callback = arguments[1];
} else {
len = arguments.length;
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
var self = this._client;
var call_on_write = function () {
self.pub_sub_mode = self.pub_sub_mode || self.command_queue.length + 1;
};
this.queue.push(new Command('subscribe', arr, callback, call_on_write));
return this;
};
RedisClient.prototype.unsubscribe = RedisClient.prototype.UNSUBSCRIBE = function unsubscribe () {
var arr,
len = arguments.length,
callback,
i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0].slice(0);
callback = arguments[1];
} else {
len = arguments.length;
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
var self = this;
var call_on_write = function () {
// Pub sub has to be activated even if not in pub sub mode, as the return value is manipulated in the callback
self.pub_sub_mode = self.pub_sub_mode || self.command_queue.length + 1;
};
return this.internal_send_command(new Command('unsubscribe', arr, callback, call_on_write));
};
Multi.prototype.unsubscribe = Multi.prototype.UNSUBSCRIBE = function unsubscribe () {
var arr,
len = arguments.length,
callback,
i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0].slice(0);
callback = arguments[1];
} else {
len = arguments.length;
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
var self = this._client;
var call_on_write = function () {
// Pub sub has to be activated even if not in pub sub mode, as the return value is manipulated in the callback
self.pub_sub_mode = self.pub_sub_mode || self.command_queue.length + 1;
};
this.queue.push(new Command('unsubscribe', arr, callback, call_on_write));
return this;
};
RedisClient.prototype.psubscribe = RedisClient.prototype.PSUBSCRIBE = function psubscribe () {
var arr,
len = arguments.length,
callback,
i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0].slice(0);
callback = arguments[1];
} else {
len = arguments.length;
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
var self = this;
var call_on_write = function () {
self.pub_sub_mode = self.pub_sub_mode || self.command_queue.length + 1;
};
return this.internal_send_command(new Command('psubscribe', arr, callback, call_on_write));
};
Multi.prototype.psubscribe = Multi.prototype.PSUBSCRIBE = function psubscribe () {
var arr,
len = arguments.length,
callback,
i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0].slice(0);
callback = arguments[1];
} else {
len = arguments.length;
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
var self = this._client;
var call_on_write = function () {
self.pub_sub_mode = self.pub_sub_mode || self.command_queue.length + 1;
};
this.queue.push(new Command('psubscribe', arr, callback, call_on_write));
return this;
};
RedisClient.prototype.punsubscribe = RedisClient.prototype.PUNSUBSCRIBE = function punsubscribe () {
var arr,
len = arguments.length,
callback,
i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0].slice(0);
callback = arguments[1];
} else {
len = arguments.length;
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
var self = this;
var call_on_write = function () {
// Pub sub has to be activated even if not in pub sub mode, as the return value is manipulated in the callback
self.pub_sub_mode = self.pub_sub_mode || self.command_queue.length + 1;
};
return this.internal_send_command(new Command('punsubscribe', arr, callback, call_on_write));
};
Multi.prototype.punsubscribe = Multi.prototype.PUNSUBSCRIBE = function punsubscribe () {
var arr,
len = arguments.length,
callback,
i = 0;
if (Array.isArray(arguments[0])) {
arr = arguments[0].slice(0);
callback = arguments[1];
} else {
len = arguments.length;
// The later should not be the average use case
if (len !== 0 && (typeof arguments[len - 1] === 'function' || typeof arguments[len - 1] === 'undefined')) {
len--;
callback = arguments[len];
}
arr = new Array(len);
for (; i < len; i += 1) {
arr[i] = arguments[i];
}
}
var self = this._client;
var call_on_write = function () {
// Pub sub has to be activated even if not in pub sub mode, as the return value is manipulated in the callback
self.pub_sub_mode = self.pub_sub_mode || self.command_queue.length + 1;
};
this.queue.push(new Command('punsubscribe', arr, callback, call_on_write));
return this;
};

187
node_modules/redis/lib/multi.js generated vendored Normal file
View File

@@ -0,0 +1,187 @@
'use strict';
var Queue = require('double-ended-queue');
var utils = require('./utils');
var Command = require('./command');
function Multi (client, args) {
this._client = client;
this.queue = new Queue();
var command, tmp_args;
if (args) { // Either undefined or an array. Fail hard if it's not an array
for (var i = 0; i < args.length; i++) {
command = args[i][0];
tmp_args = args[i].slice(1);
if (Array.isArray(command)) {
this[command[0]].apply(this, command.slice(1).concat(tmp_args));
} else {
this[command].apply(this, tmp_args);
}
}
}
}
function pipeline_transaction_command (self, command_obj, index) {
// Queueing is done first, then the commands are executed
var tmp = command_obj.callback;
command_obj.callback = function (err, reply) {
// Ignore the multi command. This is applied by node_redis and the user does not benefit by it
if (err && index !== -1) {
if (tmp) {
tmp(err);
}
err.position = index;
self.errors.push(err);
}
// Keep track of who wants buffer responses:
// By the time the callback is called the command_obj got the buffer_args attribute attached
self.wants_buffers[index] = command_obj.buffer_args;
command_obj.callback = tmp;
};
self._client.internal_send_command(command_obj);
}
Multi.prototype.exec_atomic = Multi.prototype.EXEC_ATOMIC = Multi.prototype.execAtomic = function exec_atomic (callback) {
if (this.queue.length < 2) {
return this.exec_batch(callback);
}
return this.exec(callback);
};
function multi_callback (self, err, replies) {
var i = 0, command_obj;
if (err) {
err.errors = self.errors;
if (self.callback) {
self.callback(err);
// Exclude connection errors so that those errors won't be emitted twice
} else if (err.code !== 'CONNECTION_BROKEN') {
self._client.emit('error', err);
}
return;
}
if (replies) {
while (command_obj = self.queue.shift()) {
if (replies[i] instanceof Error) {
var match = replies[i].message.match(utils.err_code);
// LUA script could return user errors that don't behave like all other errors!
if (match) {
replies[i].code = match[1];
}
replies[i].command = command_obj.command.toUpperCase();
if (typeof command_obj.callback === 'function') {
command_obj.callback(replies[i]);
}
} else {
// If we asked for strings, even in detect_buffers mode, then return strings:
replies[i] = self._client.handle_reply(replies[i], command_obj.command, self.wants_buffers[i]);
if (typeof command_obj.callback === 'function') {
command_obj.callback(null, replies[i]);
}
}
i++;
}
}
if (self.callback) {
self.callback(null, replies);
}
}
Multi.prototype.exec_transaction = function exec_transaction (callback) {
if (this.monitoring || this._client.monitoring) {
var err = new RangeError(
'Using transaction with a client that is in monitor mode does not work due to faulty return values of Redis.'
);
err.command = 'EXEC';
err.code = 'EXECABORT';
return utils.reply_in_order(this._client, callback, err);
}
var self = this;
var len = self.queue.length;
self.errors = [];
self.callback = callback;
self._client.cork();
self.wants_buffers = new Array(len);
pipeline_transaction_command(self, new Command('multi', []), -1);
// Drain queue, callback will catch 'QUEUED' or error
for (var index = 0; index < len; index++) {
// The commands may not be shifted off, since they are needed in the result handler
pipeline_transaction_command(self, self.queue.get(index), index);
}
self._client.internal_send_command(new Command('exec', [], function (err, replies) {
multi_callback(self, err, replies);
}));
self._client.uncork();
return !self._client.should_buffer;
};
function batch_callback (self, cb, i) {
return function batch_callback (err, res) {
if (err) {
self.results[i] = err;
// Add the position to the error
self.results[i].position = i;
} else {
self.results[i] = res;
}
cb(err, res);
};
}
Multi.prototype.exec = Multi.prototype.EXEC = Multi.prototype.exec_batch = function exec_batch (callback) {
var self = this;
var len = self.queue.length;
var index = 0;
var command_obj;
if (len === 0) {
utils.reply_in_order(self._client, callback, null, []);
return !self._client.should_buffer;
}
self._client.cork();
if (!callback) {
while (command_obj = self.queue.shift()) {
self._client.internal_send_command(command_obj);
}
self._client.uncork();
return !self._client.should_buffer;
}
var callback_without_own_cb = function (err, res) {
if (err) {
self.results.push(err);
// Add the position to the error
var i = self.results.length - 1;
self.results[i].position = i;
} else {
self.results.push(res);
}
// Do not emit an error here. Otherwise each error would result in one emit.
// The errors will be returned in the result anyway
};
var last_callback = function (cb) {
return function (err, res) {
cb(err, res);
callback(null, self.results);
};
};
self.results = [];
while (command_obj = self.queue.shift()) {
if (typeof command_obj.callback === 'function') {
command_obj.callback = batch_callback(self, command_obj.callback, index);
} else {
command_obj.callback = callback_without_own_cb;
}
if (typeof callback === 'function' && index === len - 1) {
command_obj.callback = last_callback(command_obj.callback);
}
this._client.internal_send_command(command_obj);
index++;
}
self._client.uncork();
return !self._client.should_buffer;
};
module.exports = Multi;

134
node_modules/redis/lib/utils.js generated vendored Normal file
View File

@@ -0,0 +1,134 @@
'use strict';
// hgetall converts its replies to an Object. If the reply is empty, null is returned.
// These function are only called with internal data and have therefore always the same instanceof X
function replyToObject (reply) {
// The reply might be a string or a buffer if this is called in a transaction (multi)
if (reply.length === 0 || !(reply instanceof Array)) {
return null;
}
var obj = {};
for (var i = 0; i < reply.length; i += 2) {
obj[reply[i].toString('binary')] = reply[i + 1];
}
return obj;
}
function replyToStrings (reply) {
if (reply instanceof Buffer) {
return reply.toString();
}
if (reply instanceof Array) {
var res = new Array(reply.length);
for (var i = 0; i < reply.length; i++) {
// Recusivly call the function as slowlog returns deep nested replies
res[i] = replyToStrings(reply[i]);
}
return res;
}
return reply;
}
function print (err, reply) {
if (err) {
// A error always begins with Error:
console.log(err.toString());
} else {
console.log('Reply: ' + reply);
}
}
var camelCase;
// Deep clone arbitrary objects with arrays. Can't handle cyclic structures (results in a range error)
// Any attribute with a non primitive value besides object and array will be passed by reference (e.g. Buffers, Maps, Functions)
// All capital letters are going to be replaced with a lower case letter and a underscore infront of it
function clone (obj) {
var copy;
if (Array.isArray(obj)) {
copy = new Array(obj.length);
for (var i = 0; i < obj.length; i++) {
copy[i] = clone(obj[i]);
}
return copy;
}
if (Object.prototype.toString.call(obj) === '[object Object]') {
copy = {};
var elems = Object.keys(obj);
var elem;
while (elem = elems.pop()) {
if (elem === 'tls') { // special handle tls
copy[elem] = obj[elem];
continue;
}
// Accept camelCase options and convert them to snake_case
var snake_case = elem.replace(/[A-Z][^A-Z]/g, '_$&').toLowerCase();
// If camelCase is detected, pass it to the client, so all variables are going to be camelCased
// There are no deep nested options objects yet, but let's handle this future proof
if (snake_case !== elem.toLowerCase()) {
camelCase = true;
}
copy[snake_case] = clone(obj[elem]);
}
return copy;
}
return obj;
}
function convenienceClone (obj) {
camelCase = false;
obj = clone(obj) || {};
if (camelCase) {
obj.camel_case = true;
}
return obj;
}
function callbackOrEmit (self, callback, err, res) {
if (callback) {
callback(err, res);
} else if (err) {
self.emit('error', err);
}
}
function replyInOrder (self, callback, err, res, queue) {
// If the queue is explicitly passed, use that, otherwise fall back to the offline queue first,
// as there might be commands in both queues at the same time
var command_obj;
/* istanbul ignore if: TODO: Remove this as soon as we test Redis 3.2 on travis */
if (queue) {
command_obj = queue.peekBack();
} else {
command_obj = self.offline_queue.peekBack() || self.command_queue.peekBack();
}
if (!command_obj) {
process.nextTick(function () {
callbackOrEmit(self, callback, err, res);
});
} else {
var tmp = command_obj.callback;
command_obj.callback = tmp ?
function (e, r) {
tmp(e, r);
callbackOrEmit(self, callback, err, res);
} :
function (e, r) {
if (e) {
self.emit('error', e);
}
callbackOrEmit(self, callback, err, res);
};
}
}
module.exports = {
reply_to_strings: replyToStrings,
reply_to_object: replyToObject,
print: print,
err_code: /^([A-Z]+)\s+(.+)$/,
monitor_regex: /^[0-9]{10,11}\.[0-9]+ \[[0-9]+ .+\]( ".+?")+$/,
clone: convenienceClone,
callback_or_emit: callbackOrEmit,
reply_in_order: replyInOrder
};

87
node_modules/redis/package.json generated vendored Normal file
View File

@@ -0,0 +1,87 @@
{
"_from": "redis@^2.8.0",
"_id": "redis@2.8.0",
"_inBundle": false,
"_integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==",
"_location": "/redis",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "redis@^2.8.0",
"name": "redis",
"escapedName": "redis",
"rawSpec": "^2.8.0",
"saveSpec": null,
"fetchSpec": "^2.8.0"
},
"_requiredBy": [
"/connect-redis"
],
"_resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz",
"_shasum": "202288e3f58c49f6079d97af7a10e1303ae14b02",
"_spec": "redis@^2.8.0",
"_where": "/home/runner/Socketio-Chat-Template/node_modules/connect-redis",
"author": {
"name": "Matt Ranney",
"email": "mjr@ranney.com"
},
"bugs": {
"url": "https://github.com/NodeRedis/node_redis/issues"
},
"bundleDependencies": false,
"dependencies": {
"double-ended-queue": "^2.1.0-0",
"redis-commands": "^1.2.0",
"redis-parser": "^2.6.0"
},
"deprecated": false,
"description": "Redis client library",
"devDependencies": {
"bluebird": "^3.0.2",
"coveralls": "^2.11.2",
"eslint": "^4.2.0",
"intercept-stdout": "~0.1.2",
"metrics": "^0.1.9",
"mocha": "^3.1.2",
"nyc": "^10.0.0",
"tcp-port-used": "^0.1.2",
"uuid": "^2.0.1",
"win-spawn": "^2.0.0"
},
"directories": {
"example": "examples",
"test": "test"
},
"engines": {
"node": ">=0.10.0"
},
"homepage": "https://github.com/NodeRedis/node_redis",
"keywords": [
"database",
"redis",
"transaction",
"pipelining",
"performance",
"queue",
"nodejs",
"pubsub",
"backpressure"
],
"license": "MIT",
"main": "./index.js",
"name": "redis",
"repository": {
"type": "git",
"url": "git://github.com/NodeRedis/node_redis.git"
},
"scripts": {
"benchmark": "node benchmarks/multi_bench.js",
"compare": "node benchmarks/diff_multi_bench_output.js beforeBench.txt afterBench.txt",
"coverage": "nyc report --reporter=html",
"coveralls": "nyc report --reporter=text-lcov | coveralls",
"lint": "eslint . --fix && npm run coverage",
"test": "nyc --cache mocha ./test/*.js ./test/commands/*.js --timeout=8000"
},
"version": "2.8.0"
}