Upgrading node modules.

This commit is contained in:
Samuel Clay 2013-03-15 17:18:36 -07:00
parent 6114aaefe4
commit 7111ff1dbe
209 changed files with 5733 additions and 3945 deletions

4
node/node_modules/express/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,4 @@
language: node_js
node_js:
- 0.6
- 0.8

25
node/node_modules/express/client.js generated vendored Normal file
View file

@ -0,0 +1,25 @@
var http = require('http');
var times = 50;
while (times--) {
var req = http.request({
port: 3000
, method: 'POST'
, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
req.on('response', function(res){
console.log(res.statusCode);
});
var n = 500000;
while (n--) {
req.write('foo=bar&bar=baz&');
}
req.write('foo=bar&bar=baz');
req.end();
}

534
node/node_modules/express/lib/application.js generated vendored Normal file
View file

@ -0,0 +1,534 @@
/**
* Module dependencies.
*/
var connect = require('connect')
, Router = require('./router')
, methods = require('methods')
, middleware = require('./middleware')
, debug = require('debug')('express:application')
, locals = require('./utils').locals
, View = require('./view')
, utils = connect.utils
, path = require('path')
, http = require('http')
, join = path.join;
/**
* Application prototype.
*/
var app = exports = module.exports = {};
/**
* Initialize the server.
*
* - setup default configuration
* - setup default middleware
* - setup route reflection methods
*
* @api private
*/
app.init = function(){
this.cache = {};
this.settings = {};
this.engines = {};
this.viewCallbacks = [];
this.defaultConfiguration();
};
/**
* Initialize application configuration.
*
* @api private
*/
app.defaultConfiguration = function(){
// default settings
this.enable('x-powered-by');
this.set('env', process.env.NODE_ENV || 'development');
this.set('subdomain offset', 2);
debug('booting in %s mode', this.get('env'));
// implicit middleware
this.use(connect.query());
this.use(middleware.init(this));
// inherit protos
this.on('mount', function(parent){
this.request.__proto__ = parent.request;
this.response.__proto__ = parent.response;
this.engines.__proto__ = parent.engines;
});
// router
this._router = new Router(this);
this.routes = this._router.map;
this.__defineGetter__('router', function(){
this._usedRouter = true;
this._router.caseSensitive = this.enabled('case sensitive routing');
this._router.strict = this.enabled('strict routing');
return this._router.middleware;
});
// setup locals
this.locals = locals(this);
// default locals
this.locals.settings = this.settings;
// default configuration
this.set('views', process.cwd() + '/views');
this.set('jsonp callback name', 'callback');
this.configure('development', function(){
this.set('json spaces', 2);
});
this.configure('production', function(){
this.enable('view cache');
});
};
/**
* Proxy `connect#use()` to apply settings to
* mounted applications.
*
* @param {String|Function|Server} route
* @param {Function|Server} fn
* @return {app} for chaining
* @api public
*/
app.use = function(route, fn){
var app;
// default route to '/'
if ('string' != typeof route) fn = route, route = '/';
// express app
if (fn.handle && fn.set) app = fn;
// restore .app property on req and res
if (app) {
app.route = route;
fn = function(req, res, next) {
var orig = req.app;
app.handle(req, res, function(err){
req.app = res.app = orig;
req.__proto__ = orig.request;
res.__proto__ = orig.response;
next(err);
});
};
}
connect.proto.use.call(this, route, fn);
// mounted an app
if (app) {
app.parent = this;
app.emit('mount', this);
}
return this;
};
/**
* Register the given template engine callback `fn`
* as `ext`.
*
* By default will `require()` the engine based on the
* file extension. For example if you try to render
* a "foo.jade" file Express will invoke the following internally:
*
* app.engine('jade', require('jade').__express);
*
* For engines that do not provide `.__express` out of the box,
* or if you wish to "map" a different extension to the template engine
* you may use this method. For example mapping the EJS template engine to
* ".html" files:
*
* app.engine('html', require('ejs').renderFile);
*
* In this case EJS provides a `.renderFile()` method with
* the same signature that Express expects: `(path, options, callback)`,
* though note that it aliases this method as `ejs.__express` internally
* so if you're using ".ejs" extensions you dont need to do anything.
*
* Some template engines do not follow this convention, the
* [Consolidate.js](https://github.com/visionmedia/consolidate.js)
* library was created to map all of node's popular template
* engines to follow this convention, thus allowing them to
* work seeessly within Express.
*
* @param {String} ext
* @param {Function} fn
* @return {app} for chaining
* @api public
*/
app.engine = function(ext, fn){
if ('function' != typeof fn) throw new Error('callback function required');
if ('.' != ext[0]) ext = '.' + ext;
this.engines[ext] = fn;
return this;
};
/**
* Map the given param placeholder `name`(s) to the given callback(s).
*
* Parameter mapping is used to provide pre-conditions to routes
* which use normalized placeholders. For example a _:user_id_ parameter
* could automatically load a user's information from the database without
* any additional code,
*
* The callback uses the samesignature as middleware, the only differencing
* being that the value of the placeholder is passed, in this case the _id_
* of the user. Once the `next()` function is invoked, just like middleware
* it will continue on to execute the route, or subsequent parameter functions.
*
* app.param('user_id', function(req, res, next, id){
* User.find(id, function(err, user){
* if (err) {
* next(err);
* } else if (user) {
* req.user = user;
* next();
* } else {
* next(new Error('failed to load user'));
* }
* });
* });
*
* @param {String|Array} name
* @param {Function} fn
* @return {app} for chaining
* @api public
*/
app.param = function(name, fn){
var self = this
, fns = [].slice.call(arguments, 1);
// array
if (Array.isArray(name)) {
name.forEach(function(name){
fns.forEach(function(fn){
self.param(name, fn);
});
});
// param logic
} else if ('function' == typeof name) {
this._router.param(name);
// single
} else {
if (':' == name[0]) name = name.substr(1);
fns.forEach(function(fn){
self._router.param(name, fn);
});
}
return this;
};
/**
* Assign `setting` to `val`, or return `setting`'s value.
*
* app.set('foo', 'bar');
* app.get('foo');
* // => "bar"
*
* Mounted servers inherit their parent server's settings.
*
* @param {String} setting
* @param {String} val
* @return {Server} for chaining
* @api public
*/
app.set = function(setting, val){
if (1 == arguments.length) {
if (this.settings.hasOwnProperty(setting)) {
return this.settings[setting];
} else if (this.parent) {
return this.parent.set(setting);
}
} else {
this.settings[setting] = val;
return this;
}
};
/**
* Return the app's absolute pathname
* based on the parent(s) that have
* mounted it.
*
* For example if the application was
* mounted as "/admin", which itself
* was mounted as "/blog" then the
* return value would be "/blog/admin".
*
* @return {String}
* @api private
*/
app.path = function(){
return this.parent
? this.parent.path() + this.route
: '';
};
/**
* Check if `setting` is enabled (truthy).
*
* app.enabled('foo')
* // => false
*
* app.enable('foo')
* app.enabled('foo')
* // => true
*
* @param {String} setting
* @return {Boolean}
* @api public
*/
app.enabled = function(setting){
return !!this.set(setting);
};
/**
* Check if `setting` is disabled.
*
* app.disabled('foo')
* // => true
*
* app.enable('foo')
* app.disabled('foo')
* // => false
*
* @param {String} setting
* @return {Boolean}
* @api public
*/
app.disabled = function(setting){
return !this.set(setting);
};
/**
* Enable `setting`.
*
* @param {String} setting
* @return {app} for chaining
* @api public
*/
app.enable = function(setting){
return this.set(setting, true);
};
/**
* Disable `setting`.
*
* @param {String} setting
* @return {app} for chaining
* @api public
*/
app.disable = function(setting){
return this.set(setting, false);
};
/**
* Configure callback for zero or more envs,
* when no `env` is specified that callback will
* be invoked for all environments. Any combination
* can be used multiple times, in any order desired.
*
* Examples:
*
* app.configure(function(){
* // executed for all envs
* });
*
* app.configure('stage', function(){
* // executed staging env
* });
*
* app.configure('stage', 'production', function(){
* // executed for stage and production
* });
*
* Note:
*
* These callbacks are invoked immediately, and
* are effectively sugar for the following:
*
* var env = process.env.NODE_ENV || 'development';
*
* switch (env) {
* case 'development':
* ...
* break;
* case 'stage':
* ...
* break;
* case 'production':
* ...
* break;
* }
*
* @param {String} env...
* @param {Function} fn
* @return {app} for chaining
* @api public
*/
app.configure = function(env, fn){
var envs = 'all'
, args = [].slice.call(arguments);
fn = args.pop();
if (args.length) envs = args;
if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
return this;
};
/**
* Delegate `.VERB(...)` calls to `router.VERB(...)`.
*/
methods.forEach(function(method){
app[method] = function(path){
if ('get' == method && 1 == arguments.length) return this.set(path);
// if no router attacked yet, attach the router
if (!this._usedRouter) this.use(this.router);
// setup route
this._router[method].apply(this._router, arguments);
return this;
};
});
/**
* Special-cased "all" method, applying the given route `path`,
* middleware, and callback to _every_ HTTP method.
*
* @param {String} path
* @param {Function} ...
* @return {app} for chaining
* @api public
*/
app.all = function(path){
var args = arguments;
methods.forEach(function(method){
app[method].apply(this, args);
}, this);
return this;
};
// del -> delete alias
app.del = app.delete;
/**
* Render the given view `name` name with `options`
* and a callback accepting an error and the
* rendered template string.
*
* Example:
*
* app.render('email', { name: 'Tobi' }, function(err, html){
* // ...
* })
*
* @param {String} name
* @param {String|Function} options or fn
* @param {Function} fn
* @api public
*/
app.render = function(name, options, fn){
var opts = {}
, cache = this.cache
, engines = this.engines
, view;
// support callback function as second arg
if ('function' == typeof options) {
fn = options, options = {};
}
// merge app.locals
utils.merge(opts, this.locals);
// merge options._locals
if (options._locals) utils.merge(opts, options._locals);
// merge options
utils.merge(opts, options);
// set .cache unless explicitly provided
opts.cache = null == opts.cache
? this.enabled('view cache')
: opts.cache;
// primed cache
if (opts.cache) view = cache[name];
// view
if (!view) {
view = new View(name, {
defaultEngine: this.get('view engine'),
root: this.get('views'),
engines: engines
});
if (!view.path) {
var err = new Error('Failed to lookup view "' + name + '"');
err.view = view;
return fn(err);
}
// prime the cache
if (opts.cache) cache[name] = view;
}
// render
try {
view.render(opts, fn);
} catch (err) {
fn(err);
}
};
/**
* Listen for connections.
*
* A node `http.Server` is returned, with this
* application (which is a `Function`) as its
* callback. If you wish to create both an HTTP
* and HTTPS server you may do so with the "http"
* and "https" modules as shown here:
*
* var http = require('http')
* , https = require('https')
* , express = require('express')
* , app = express();
*
* http.createServer(app).listen(80);
* https.createServer({ ... }, app).listen(443);
*
* @return {http.Server}
* @api public
*/
app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};

33
node/node_modules/express/lib/middleware.js generated vendored Normal file
View file

@ -0,0 +1,33 @@
/**
* Module dependencies.
*/
var utils = require('./utils');
/**
* Initialization middleware, exposing the
* request and response to eachother, as well
* as defaulting the X-Powered-By header field.
*
* @param {Function} app
* @return {Function}
* @api private
*/
exports.init = function(app){
return function expressInit(req, res, next){
req.app = res.app = app;
if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
req.res = res;
res.req = req;
req.next = next;
req.__proto__ = app.request;
res.__proto__ = app.response;
res.locals = res.locals || utils.locals(res);
next();
}
};

14
node/node_modules/express/test.js generated vendored Normal file
View file

@ -0,0 +1,14 @@
/**
* Module dependencies.
*/
var express = require('./')
, app = express()
app.get('/', function(req, res){
console.log(req.query);
});
app.listen(3000);
console.log('listening on 3000');

1
node/node_modules/redis/.npmignore generated vendored Normal file
View file

@ -0,0 +1 @@
node_modules

38
node/node_modules/redis/benches/hiredis_parser.js generated vendored Normal file
View file

@ -0,0 +1,38 @@
var Parser = require('../lib/parser/hiredis').Parser;
var assert = require('assert');
/*
This test makes sure that exceptions thrown inside of "reply" event handlers
are not trapped and mistakenly emitted as parse errors.
*/
(function testExecuteDoesNotCatchReplyCallbackExceptions() {
var parser = new Parser();
var replies = [{}];
parser.reader = {
feed: function() {},
get: function() {
return replies.shift();
}
};
var emittedError = false;
var caughtException = false;
parser
.on('error', function() {
emittedError = true;
})
.on('reply', function() {
throw new Error('bad');
});
try {
parser.execute();
} catch (err) {
caughtException = true;
}
assert.equal(caughtException, true);
assert.equal(emittedError, false);
})();

14
node/node_modules/redis/benches/re_sub_test.js generated vendored Normal file
View file

@ -0,0 +1,14 @@
var client = require('../index').createClient()
, client2 = require('../index').createClient()
, assert = require('assert');
client.once('subscribe', function (channel, count) {
client.unsubscribe('x');
client.subscribe('x', function () {
client.quit();
client2.quit();
});
client2.publish('x', 'hi');
});
client.subscribe('x');

View file

@ -1,4 +1,6 @@
var redis = require("redis").createClient();
var redis = require("../index").createClient(null, null, {
// max_attempts: 4
});
redis.on("error", function (err) {
console.log("Redis says: " + err);
@ -24,4 +26,4 @@ setInterval(function () {
console.log(now + " Redis reply: " + res);
}
});
}, 200);
}, 100);

View file

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

87
node/node_modules/redis/diff_multi_bench_output.js generated vendored Executable file
View file

@ -0,0 +1,87 @@
#!/usr/bin/env node
var colors = require('colors'),
fs = require('fs'),
_ = require('underscore'),
metrics = require('metrics'),
// `node diff_multi_bench_output.js before.txt after.txt`
before = process.argv[2],
after = process.argv[3];
if (!before || !after) {
console.log('Please supply two file arguments:');
var n = __filename;
n = n.substring(n.lastIndexOf('/', n.length));
console.log(' ./' + n + ' multiBenchBefore.txt multiBenchAfter.txt');
console.log('To generate multiBenchBefore.txt, run');
console.log(' node multi_bench.js > multiBenchBefore.txt');
console.log('Thank you for benchmarking responsibly.');
return;
}
var before_lines = fs.readFileSync(before, 'utf8').split('\n'),
after_lines = fs.readFileSync(after, 'utf8').split('\n');
console.log('Comparing before,', before.green, '(', before_lines.length,
'lines)', 'to after,', after.green, '(', after_lines.length, 'lines)');
var total_ops = new metrics.Histogram.createUniformHistogram();
before_lines.forEach(function(b, i) {
var a = after_lines[i];
if (!a || !b || !b.trim() || !a.trim()) {
// console.log('#ignored#', '>'+a+'<', '>'+b+'<');
return;
}
b_words = b.split(' ').filter(is_whitespace);
a_words = a.split(' ').filter(is_whitespace);
var ops =
[b_words, a_words]
.map(function(words) {
// console.log(words);
return parseInt10(words.slice(-2, -1));
}).filter(function(num) {
var isNaN = !num && num !== 0;
return !isNaN;
});
if (ops.length != 2) return
var delta = ops[1] - ops[0];
total_ops.update(delta);
delta = humanize_diff(delta);
console.log(
// name of test
command_name(a_words) == command_name(b_words)
? command_name(a_words) + ':'
: '404:',
// results of test
ops.join(' -> '), 'ops/sec (∆', delta, ')');
});
console.log('Mean difference in ops/sec:', humanize_diff(total_ops.mean()));
function is_whitespace(s) {
return !!s.trim();
}
function parseInt10(s) {
return parseInt(s, 10);
}
// green if greater than 0, red otherwise
function humanize_diff(num) {
if (num > 0) {
return ('+' + num).green;
}
return ('' + num).red;
}
function command_name(words) {
var line = words.join(' ');
return line.substr(0, line.indexOf(','));
}

18
node/node_modules/redis/test3.js generated vendored Normal file
View file

@ -0,0 +1,18 @@
var redis = require('redis');
rc = redis.createClient();
rc.on('error', function (err) {
console.log('Redis error ' + err);
});
var jsonStr = '{\"glossary\":{\"title\":\"example glossary\",\"GlossDiv\":{\"title\":\"S\",\"GlossList\":{\"GlossEntry\":{\"ID\":\"SGML\",\"SortAs\":\"SGML\",\"GlossTerm\":\"Standard Generalized Markup Language\",\"Acronym\":\"SGML\",\"Abbrev\":\"ISO 8879:1986\",\"GlossDef\":{\"para\":\"A meta-markup language, used to create markup languages such as DocBook.\",\"GlossSeeAlso\":[\"GML\",\"XML\"]},\"GlossSee\":\"markup\"}}}}}';
for (var i = 0, len = 100; i < len; i++) {
rc.rpush('test:case', jsonStr);
}
rc.lrange('test:case', 0, -1, function (err, data) {
console.log(data); // it will return 100 elements, but the last ones will be null's instead of the actual value
rc.end();
});

View file

@ -1,4 +1,68 @@
0.9.13 / 2012-12-13
===================
* package: fixed `base64id` requirement
0.9.12 / 2012-12-13
===================
* manager: fix for latest node which is returning a clone with `listeners` [viirya]
0.9.11 / 2012-11-02
===================
* package: move redis to optionalDependenices [3rd-Eden]
* bumped client
0.9.10 / 2012-08-10
===================
* Don't lowercase log messages
* Always set the HTTP response in case an error should be returned to the client
* Create or destroy the flash policy server on configuration change
* Honour configuration to disable flash policy server
* Add express 3.0 instructions on Readme.md
* Bump client
0.9.9 / 2012-08-01
==================
* Fixed sync disconnect xhrs handling
* Put license text in its own file (#965)
* Add warning to .listen() to ease the migration to Express 3.x
* Restored compatibility with node 0.4.x
0.9.8 / 2012-07-24
==================
* Bumped client.
0.9.7 / 2012-07-24
==================
* Prevent crash when socket leaves a room twice.
* Corrects unsafe usage of for..in
* Fix for node 0.8 with `gzip compression` [vadimi]
* Update redis to support Node 0.8.x
* Made ID generation securely random
* Fix Redis Store race condition in manager onOpen unsubscribe callback
* Fix for EventEmitters always reusing the same Array instance for listeners
0.9.6 / 2012-04-17
==================
* Fixed XSS in jsonp-polling.
0.9.5 / 2012-04-05
==================
* Added test for polling and socket close.
* Ensure close upon request close.
* Fix disconnection reason being lost for polling transports.
* Ensure that polling transports work with Connection: close.
* Log disconnection reason.
0.9.4 / 2012-04-01
==================

22
node/node_modules/socket.io/LICENSE generated vendored Normal file
View file

@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2011 Guillermo Rauch <guillermo@learnboost.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -21,6 +21,25 @@ var io = require('socket.io');
Next, attach it to a HTTP/HTTPS server. If you're using the fantastic `express`
web framework:
#### Express 3.x
```js
var app = express()
, server = require('http').createServer(app)
, io = io.listen(server);
server.listen(80);
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
```
#### Express 2.x
```js
var app = express.createServer()
, io = io.listen(app);
@ -104,10 +123,10 @@ io.sockets.on('connection', function (socket) {
var socket = io.connect('http://localhost');
socket.on('connect', function () {
socket.emit('set nickname', confirm('What is your nickname?'));
socket.emit('set nickname', prompt('What is your nickname?'));
socket.on('ready', function () {
console.log('Connected !');
socket.emit('msg', confirm('What is your message?'));
socket.emit('msg', prompt('What is your message?'));
});
});
</script>

View file

@ -1,80 +0,0 @@
/**
* Module dependencies.
*/
var express = require('express')
, stylus = require('stylus')
, nib = require('nib')
, sio = require('../../lib/socket.io');
/**
* App.
*/
var app = express.createServer();
/**
* App configuration.
*/
app.configure(function () {
app.use(stylus.middleware({ src: __dirname + '/public', compile: compile }));
app.use(express.static(__dirname + '/public'));
app.set('views', __dirname);
app.set('view engine', 'jade');
function compile (str, path) {
return stylus(str)
.set('filename', path)
.use(nib());
};
});
/**
* App routes.
*/
app.get('/', function (req, res) {
res.render('index', { layout: false });
});
/**
* App listen.
*/
app.listen(3000, function () {
var addr = app.address();
console.log(' app listening on http://' + addr.address + ':' + addr.port);
});
/**
* Socket.IO server (single process only)
*/
var io = sio.listen(app)
, nicknames = {};
io.sockets.on('connection', function (socket) {
socket.on('user message', function (msg) {
socket.broadcast.emit('user message', socket.nickname, msg);
});
socket.on('nickname', function (nick, fn) {
if (nicknames[nick]) {
fn(true);
} else {
fn(false);
nicknames[nick] = socket.nickname = nick;
socket.broadcast.emit('announcement', nick + ' connected');
io.sockets.emit('nicknames', nicknames);
}
});
socket.on('disconnect', function () {
if (!socket.nickname) return;
delete nicknames[socket.nickname];
socket.broadcast.emit('announcement', socket.nickname + ' disconnected');
socket.broadcast.emit('nicknames', nicknames);
});
});

View file

@ -1,83 +0,0 @@
doctype 5
html
head
link(href='/stylesheets/style.css', rel='stylesheet')
script(src='http://code.jquery.com/jquery-1.6.1.min.js')
script(src='/socket.io/socket.io.js')
script
// socket.io specific code
var socket = io.connect();
socket.on('connect', function () {
$('#chat').addClass('connected');
});
socket.on('announcement', function (msg) {
$('#lines').append($('<p>').append($('<em>').text(msg)));
});
socket.on('nicknames', function (nicknames) {
$('#nicknames').empty().append($('<span>Online: </span>'));
for (var i in nicknames) {
$('#nicknames').append($('<b>').text(nicknames[i]));
}
});
socket.on('user message', message);
socket.on('reconnect', function () {
$('#lines').remove();
message('System', 'Reconnected to the server');
});
socket.on('reconnecting', function () {
message('System', 'Attempting to re-connect to the server');
});
socket.on('error', function (e) {
message('System', e ? e : 'A unknown error occurred');
});
function message (from, msg) {
$('#lines').append($('<p>').append($('<b>').text(from), msg));
}
// dom manipulation
$(function () {
$('#set-nickname').submit(function (ev) {
socket.emit('nickname', $('#nick').val(), function (set) {
if (!set) {
clear();
return $('#chat').addClass('nickname-set');
}
$('#nickname-err').css('visibility', 'visible');
});
return false;
});
$('#send-message').submit(function () {
message('me', $('#message').val());
socket.emit('user message', $('#message').val());
clear();
$('#lines').get(0).scrollTop = 10000000;
return false;
});
function clear () {
$('#message').val('').focus();
};
});
body
#chat
#nickname
form.wrap#set-nickname
p Please type in your nickname and press enter.
input#nick
p#nickname-err Nickname already in use
#connecting
.wrap Connecting to socket.io server
#messages
#nicknames
#lines
form#send-message
input#message
button Send

View file

@ -1,11 +0,0 @@
{
"name": "chat.io"
, "description": "example chat application with socket.io"
, "version": "0.0.1"
, "dependencies": {
"express": "2.5.5"
, "jade": "0.16.4"
, "stylus": "0.19.0"
, "nib": "0.2.0"
}
}

View file

@ -1,96 +0,0 @@
border-radius(n)
-webkit-border-radius n
-moz-border-radius n
border-radius n
// replace str with val
replace(expr, str, val)
expr = clone(expr)
for e, i in expr
if str == e
expr[i] = val
expr
// normalize gradient point (webkit)
grad-point(pos)
if length(pos) == 1
return left pos if pos in (top bottom)
return pos top if pos in (left right)
else if pos[0] in (top bottom)
pos[1] pos[0]
else
pos
// implicit color stop position
pos-in-stops(i, stops)
len = length(stops)
if len - 1 == i
100%
else if i
unit(i / len * 100, '%')
else
0%
// normalize color stops
// - (color pos) -> (pos color)
// - (color) -> (implied-pos color)
normalize-stops(stops)
stops = clone(stops)
for stop, i in stops
if length(stop) == 1
color = stop[0]
stop[0] = pos-in-stops(i, stops)
stop[1] = color
else if typeof(stop[1]) == 'unit'
pos = stop[1]
stop[1] = stop[0]
stop[0] = pos
stops
// join color stops with the given translation function
join-stops(stops, translate)
str = ''
len = length(stops)
for stop, i in stops
str += ', ' if i
pos = stop[0]
color = stop[1]
str += translate(color, pos)
unquote(str)
// webkit translation function
webkit-stop(color, pos)
s('color-stop(%d, %s)', pos / 100, color)
// mozilla translation function
moz-stop(color, pos)
s('%s %s', color, pos)
// create a linear gradient with the given start
// position, followed by color stops
linear-gradient(start, stops...)
error('color stops required') unless length(stops)
prop = current-property[0]
val = current-property[1]
stops = normalize-stops(stops)
// webkit
end = grad-point(opposite-position(start))
webkit = s('-webkit-gradient(linear, %s, %s, %s)', grad-point(start), end, join-stops(stops, webkit-stop))
add-property(prop, replace(val, '__CALL__', webkit))
// moz
stops = join-stops(stops, moz-stop)
moz = s('-moz-linear-gradient(%s, %s)', start, stops)
add-property(prop, replace(val, '__CALL__', moz))
// literal
s('linear-gradient(%s, %s)', start, stops)

View file

@ -1,188 +0,0 @@
#chat,
#nickname,
#messages {
width: 600px;
}
#chat {
position: relative;
border: 1px solid #ccc;
}
#nickname,
#connecting {
position: absolute;
height: 410px;
z-index: 100;
left: 0;
top: 0;
background: #fff;
text-align: center;
width: 600px;
font: 15px Georgia;
color: #666;
display: block;
}
#nickname .wrap,
#connecting .wrap {
padding-top: 150px;
}
#nickname input {
border: 1px solid #ccc;
padding: 10px;
}
#nickname input:focus {
border-color: #999;
outline: 0;
}
#nickname #nickname-err {
color: #8b0000;
font-size: 12px;
visibility: hidden;
}
.connected #connecting {
display: none;
}
.nickname-set #nickname {
display: none;
}
#messages {
height: 380px;
background: #eee;
}
#messages em {
text-shadow: 0 1px 0 #fff;
color: #999;
}
#messages p {
padding: 0;
margin: 0;
font: 12px Helvetica, Arial;
padding: 5px 10px;
}
#messages p b {
display: inline-block;
padding-right: 10px;
}
#messages p:nth-child(even) {
background: #fafafa;
}
#messages #nicknames {
background: #ccc;
padding: 2px 4px 4px;
font: 11px Helvetica;
}
#messages #nicknames span {
color: #000;
}
#messages #nicknames b {
display: inline-block;
color: #fff;
background: #999;
padding: 3px 6px;
margin-right: 5px;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
text-shadow: 0 1px 0 #666;
}
#messages #lines {
height: 355px;
overflow: auto;
overflow-x: hidden;
overflow-y: auto;
}
#messages #lines::-webkit-scrollbar {
width: 6px;
height: 6px;
}
#messages #lines::-webkit-scrollbar-button:start:decrement,
#messages #lines ::-webkit-scrollbar-button:end:increment {
display: block;
height: 10px;
}
#messages #lines::-webkit-scrollbar-button:vertical:increment {
background-color: #fff;
}
#messages #lines::-webkit-scrollbar-track-piece {
background-color: #fff;
-webkit-border-radius: 3px;
}
#messages #lines::-webkit-scrollbar-thumb:vertical {
height: 50px;
background-color: #ccc;
-webkit-border-radius: 3px;
}
#messages #lines::-webkit-scrollbar-thumb:horizontal {
width: 50px;
background-color: #fff;
-webkit-border-radius: 3px;
}
#send-message {
background: #fff;
position: relative;
}
#send-message input {
border: none;
height: 30px;
padding: 0 10px;
line-height: 30px;
vertical-align: middle;
width: 580px;
}
#send-message input:focus {
outline: 0;
}
#send-message button {
position: absolute;
top: 5px;
right: 5px;
}
button {
margin: 0;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
display: inline-block;
text-decoration: none;
background: #43a1f7;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #43a1f7), color-stop(1, #377ad0));
background: -webkit-linear-gradient(top, #43a1f7 0%, #377ad0 100%);
background: -moz-linear-gradient(top, #43a1f7 0%, #377ad0 100%);
background: linear-gradient(top, #43a1f7 0%, #377ad0 100%);
border: 1px solid #2e70c4;
-webkit-border-radius: 16px;
-moz-border-radius: 16px;
border-radius: 16px;
color: #fff;
font-family: "lucida grande", sans-serif;
font-size: 11px;
font-weight: normal;
line-height: 1;
padding: 3px 10px 5px 10px;
text-align: center;
text-shadow: 0 -1px 1px #2d6dc0;
}
button:hover,
button.hover {
background: darker;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #43a1f7), color-stop(1, #2e70c4));
background: -webkit-linear-gradient(top, #43a1f7 0%, #2e70c4 100%);
background: -moz-linear-gradient(top, #43a1f7 0%, #2e70c4 100%);
background: linear-gradient(top, #43a1f7 0%, #2e70c4 100%);
border: 1px solid #2e70c4;
cursor: pointer;
text-shadow: 0 -1px 1px #2c6bbb;
}
button:active,
button.active {
background: #2e70c4;
border: 1px solid #2e70c4;
border-bottom: 1px solid #2861aa;
text-shadow: 0 -1px 1px #2b67b5;
}
button:focus,
button.focus {
outline: none;
-webkit-box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0;
-moz-box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0;
box-shadow: 0 1px 0 0 rgba(255,255,255,0.4), 0 0 4px 0 #377ad0;
}

View file

@ -1,118 +0,0 @@
@import 'nib'
#chat, #nickname, #messages
width 600px
#chat
position relative
border 1px solid #ccc
#nickname, #connecting
position absolute
height 410px
z-index 100
left 0
top 0
background #fff
text-align center
width 600px
font 15px Georgia
color #666
display block
.wrap
padding-top 150px
#nickname
input
border 1px solid #ccc
padding 10px
&:focus
border-color #999
outline 0
#nickname-err
color darkred
font-size 12px
visibility hidden
.connected
#connecting
display none
.nickname-set
#nickname
display none
#messages
height 380px
background #eee
em
text-shadow 0 1px 0 #fff
color #999
p
padding 0
margin 0
font 12px Helvetica, Arial
padding 5px 10px
b
display inline-block
padding-right 10px
p:nth-child(even)
background #fafafa
#nicknames
background #ccc
padding 2px 4px 4px
font 11px Helvetica
span
color black
b
display inline-block
color #fff
background #999
padding 3px 6px
margin-right 5px
border-radius 10px
text-shadow 0 1px 0 #666
#lines
height 355px
overflow auto
overflow-x hidden
overflow-y auto
&::-webkit-scrollbar
width 6px
height 6px
&::-webkit-scrollbar-button:start:decrement, ::-webkit-scrollbar-button:end:increment
display block
height 10px
&::-webkit-scrollbar-button:vertical:increment
background-color #fff
&::-webkit-scrollbar-track-piece
background-color #fff
-webkit-border-radius 3px
&::-webkit-scrollbar-thumb:vertical
height 50px
background-color #ccc
-webkit-border-radius 3px
&::-webkit-scrollbar-thumb:horizontal
width 50px
background-color #fff
-webkit-border-radius 3px
#send-message
background #fff
position relative
input
border none
height 30px
padding 0 10px
line-height 30px
vertical-align middle
width 580px
&:focus
outline 0
button
position absolute
top 5px
right 5px
button
download-button()

View file

@ -1,74 +0,0 @@
/**
* Module dependencies.
*/
var express = require('express')
, stylus = require('stylus')
, nib = require('nib')
, sio = require('../../lib/socket.io')
, irc = require('./irc');
/**
* App.
*/
var app = express.createServer();
/**
* App configuration.
*/
app.configure(function () {
app.use(stylus.middleware({ src: __dirname + '/public', compile: compile }))
app.use(express.static(__dirname + '/public'));
app.set('views', __dirname);
app.set('view engine', 'jade');
function compile (str, path) {
return stylus(str)
.set('filename', path)
.use(nib());
};
});
/**
* App routes.
*/
app.get('/', function (req, res) {
res.render('index', { layout: false });
});
/**
* App listen.
*/
app.listen(3000, function () {
var addr = app.address();
console.log(' app listening on http://' + addr.address + ':' + addr.port);
});
/**
* Socket.IO server
*/
var io = sio.listen(app)
/**
* Connect to IRC.
*/
var client = new irc.Client('irc.freenode.net', 6667);
client.connect('socketio\\test\\' + String(Math.random()).substr(-3));
client.on('001', function () {
this.send('JOIN', '#node.js');
});
client.on('PART', function (prefix) {
io.sockets.emit('announcement', irc.user(prefix) + ' left the channel');
});
client.on('JOIN', function (prefix) {
io.sockets.emit('announcement', irc.user(prefix) + ' joined the channel');
});
client.on('PRIVMSG', function (prefix, channel, text) {
io.sockets.emit('irc message', irc.user(prefix), text);
});

View file

@ -1,28 +0,0 @@
doctype 5
html
head
link(href='/stylesheets/style.css', rel='stylesheet')
script(src='http://code.jquery.com/jquery-1.6.1.min.js')
script(src='/socket.io/socket.io.js')
script
var socket = io.connect();
socket.on('connect', function () {
$('#irc').addClass('connected');
});
socket.on('announcement', function (msg) {
$('#messages').append($('<p>').append($('<em>').text(msg)));
$('#messages').get(0).scrollTop = 10000000;
});
socket.on('irc message', function (user, msg) {
$('#messages').append($('<p>').append($('<b>').text(user), msg));
$('#messages').get(0).scrollTop = 10000000;
});
body
h2 Node.JS IRC
#irc
#connecting
.wrap Connecting to socket.io server
#messages

View file

@ -1,164 +0,0 @@
/**
* From https://github.com/felixge/nodelog/
*/
var sys = require('util');
var tcp = require('net');
var irc = exports;
function bind(fn, scope) {
var bindArgs = Array.prototype.slice.call(arguments);
bindArgs.shift();
bindArgs.shift();
return function() {
var args = Array.prototype.slice.call(arguments);
fn.apply(scope, bindArgs.concat(args));
};
}
function each(set, iterator) {
for (var i = 0; i < set.length; i++) {
var r = iterator(set[i], i);
if (r === false) {
return;
}
}
}
var Client = irc.Client = function(host, port) {
this.host = host || 'localhost';
this.port = port || 6667;
this.connection = null;
this.buffer = '';
this.encoding = 'utf8';
this.timeout = 10 * 60 * 60 * 1000;
this.nick = null;
this.user = null;
this.real = null;
}
sys.inherits(Client, process.EventEmitter);
Client.prototype.connect = function(nick, user, real) {
var connection = tcp.createConnection(this.port, this.host);
connection.setEncoding(this.encoding);
connection.setTimeout(this.timeout);
connection.addListener('connect', bind(this.onConnect, this));
connection.addListener('data', bind(this.onReceive, this));
connection.addListener('end', bind(this.onEof, this));
connection.addListener('timeout', bind(this.onTimeout, this));
connection.addListener('close', bind(this.onClose, this));
this.nick = nick;
this.user = user || 'guest';
this.real = real || 'Guest';
this.connection = connection;
};
Client.prototype.disconnect = function(why) {
if (this.connection.readyState !== 'closed') {
this.connection.close();
sys.puts('disconnected (reason: '+why+')');
this.emit('DISCONNECT', why);
}
};
Client.prototype.send = function(arg1) {
if (this.connection.readyState !== 'open') {
return this.disconnect('cannot send with readyState: '+this.connection.readyState);
}
var message = [];
for (var i = 0; i< arguments.length; i++) {
if (arguments[i]) {
message.push(arguments[i]);
}
}
message = message.join(' ');
sys.puts('> '+message);
message = message + "\r\n";
this.connection.write(message, this.encoding);
};
Client.prototype.parse = function(message) {
var match = message.match(/(?:(:[^\s]+) )?([^\s]+) (.+)/);
var parsed = {
prefix: match[1],
command: match[2]
};
var params = match[3].match(/(.*?) ?:(.*)/);
if (params) {
// Params before :
params[1] = (params[1])
? params[1].split(' ')
: [];
// Rest after :
params[2] = params[2]
? [params[2]]
: [];
params = params[1].concat(params[2]);
} else {
params = match[3].split(' ');
}
parsed.params = params;
return parsed;
};
Client.prototype.onConnect = function() {
this.send('NICK', this.nick);
this.send('USER', this.user, '0', '*', ':'+this.real);
};
Client.prototype.onReceive = function(chunk) {
this.buffer = this.buffer + chunk;
while (this.buffer) {
var offset = this.buffer.indexOf("\r\n");
if (offset < 0) {
return;
}
var message = this.buffer.substr(0, offset);
this.buffer = this.buffer.substr(offset + 2);
sys.puts('< '+message);
message = this.parse(message);
this.emit.apply(this, [message.command, message.prefix].concat(message.params));
if (message !== false) {
this.onMessage(message);
}
}
};
Client.prototype.onMessage = function(message) {
switch (message.command) {
case 'PING':
this.send('PONG', ':'+message.params[0]);
break;
}
};
Client.prototype.onEof = function() {
this.disconnect('eof');
};
Client.prototype.onTimeout = function() {
this.disconnect('timeout');
};
Client.prototype.onClose = function() {
this.disconnect('close');
};
exports.user = function(prefix) {
return prefix.match(/:([^!]+)!/)[1]
};

View file

@ -1,10 +0,0 @@
{
"name": "socket.io-irc"
, "version": "0.0.1"
, "dependencies": {
"express": "2.5.5"
, "jade": "0.16.4"
, "stylus": "0.19.0"
, "nib": "0.2.0"
}
}

View file

@ -1,69 +0,0 @@
@import 'nib'
h2
font bold 18px Helvetica Neue, Arial
#irc, #messages
width 600px
#irc
position relative
border 1px solid #ccc
#connecting
position absolute
height 410px
z-index 100
left 0
top 0
background #fff
text-align center
width 600px
font 15px Georgia
color #666
display block
.wrap
padding-top 150px
.connected
#connecting
display none
#messages
height 380px
background #eee
overflow auto
overflow-x hidden
overflow-y auto
&::-webkit-scrollbar
width 6px
height 6px
&::-webkit-scrollbar-button:start:decrement, ::-webkit-scrollbar-button:end:increment
display block
height 10px
&::-webkit-scrollbar-button:vertical:increment
background-color #fff
&::-webkit-scrollbar-track-piece
background-color #fff
-webkit-border-radius 3px
&::-webkit-scrollbar-thumb:vertical
height 50px
background-color #ccc
-webkit-border-radius 3px
&::-webkit-scrollbar-thumb:horizontal
width 50px
background-color #fff
-webkit-border-radius 3px
em
text-shadow 0 1px 0 #fff
color #999
p
padding 0
margin 0
font 12px Helvetica, Arial
padding 5px 10px
b
display inline-block
padding-right 10px
p:nth-child(even)
background #fafafa

View file

@ -1,167 +0,0 @@
/**
* Module dependencies.
*/
var parser = require('socket.io-client').parser
, EventEmitter = require('events').EventEmitter
/**
* Client constructor.
*
* @api public
*/
function Client (id, server) {
this.id = id;
this.acks = {};
this.store = server.store;
var self = this;
store.subscribe(id, function (packet) {
});
store.subscribe(id + '.disconect', function () {
self.onDisconnect();
});
}
/**
* Inherits from EventEmitter.
*/
Client.prototype.__proto__ = EventEmitter.prototype;
/**
* Save reference to original `emit`.
*
* @api private
*/
Client.prototype._emit = Client.prototype.emit;
/**
* Broadcast flag.
*
* @api public
*/
Client.prototype.__defineGetter__('broadcast', function () {
this.flags.broadcast = true;
});
/**
* JSON flag (deprecated)
*
* @api public
*/
Client.prototype.__defineGetter__('json', function () {
this.flags.broadcast = true;
});
/**
* Joins a group.
*
* @param {String} group
* @return {Client} for chaining
* @api public
*/
Client.prototype.join = function (group, fn) {
if (!~this.subscriptions.indexOf(group)) {
var self = this;
this.subscriptions.push(group);
this.store.addToGroup(group, this.sid, function (ev, args) {
self.onGroupEvent(ev, args);
}, fn);
} else {
fn && fn();
}
return this;
};
/**
* Leaves a group.
*
* @return {Client} for chaining
* @api public
*/
Client.prototype.leave = function (group) {
var index = this.subscriptions.indexOf(group);
if (~index) {
this.subscriptions.splice(index, 1);
}
return this;
};
Client.prototype.disconnect = function () {
if (this.socket) {
this.socket.disconnect();
} else {
this.publish('disconnect');
}
}
/**
* Called upon disconnect.
*
* @api private
*/
Client.prototype.onDisconnect = function () {
for (var i = 0, l = this.subscriptions; i < l; i++) {
this.store.removeFromGroup(id, group, fn);
}
};
/**
* Registers ACK.
*/
Client.prototype.ack = function (fn, callback) {
this.subscribe('ack');
};
/**
* Emits an event.
*/
Client.prototype.emit = function () {
var args = toArray(arguments), fn;
if ('function' == typeof args[args.length - 1]) {
fn = args.pop();
}
var data = args.shift();
if (args.length) {
data += '\n' + JSON.stringify(args);
}
if (fn) {
this.ack(fn, function (id) {
self.sendPacket('event', data, id);
});
} else {
this.sendPacket('event', data);
}
return this;
};
/**
* Sends a packet.
*/
Client.prototype.sendPacket = function (type, data, id) {
var data = parser.encode({ type: type, data: data, id: id });
if (this.server.sockets[id]) {
this.server.sockets[id].write(data);
}
};

131
node/node_modules/socket.io/lib/index.js generated vendored Normal file
View file

@ -0,0 +1,131 @@
/**
* Module dependencies.
*/
var http = require('http')
, engine = require('engine.io')
, Client = require('./client')
, Namespace = require('./namespace')
, debug = require('debug')('socket.io:server');
/**
* Read client
*/
var client = {
source: require('socket.io-client').source,
version: require('socket.io-client/package').version
};
/**
* Server constructor.
*
* @param {http.Server|Number|Object} http server, port or options
* @param {Object} options
* @api public
*/
function Server(srv, opts){
if (!(this instanceof Server)) return new Server(srv, opts);
if ('object' == typeof srv && !srv.listen) {
opts = srv;
srv = null;
}
opts = opts || {};
if (srv) this.attach(srv, opts);
this.sockets = this.of('/');
this.client(true);
}
/**
* Serve client code.
*
* @api public
*/
/**
* Attaches socket.io to a server or port.
*
* @param {http.Server|Number} server or port
* @param {Object} options
* @api public
*/
Server.prototype.attach = function(srv, opts){
if ('number' == typeof srv) {
debug('creating engine.io on port %d', srv);
srv = engine.listen(srv, opts);
} else {
debug('creating engine.io instance', opts);
srv = engine.attach(srv, opts);
}
this.bind(srv);
};
/**
* Binds socket.io to an engine.io instance.
*
* @param {engine.Server} engine.io (or compatible) server
* @api public
*/
Server.prototype.bind = function(engine){
this.engine = engine;
this.engine.on('connection', this.onconnection.bind(this));
};
/**
* Called with each incoming transport connection.
*
* @api public
*/
Server.prototype.onconnection = function(conn){
debug('incoming connection with id %s', conn.id);
var client = new Client(this, conn);
client.connect('/');
this.emit('client', client);
};
/**
* Looks up a namespace.
*
* @param {String} nsp name
* @api public
*/
Server.prototype.of = function(name){
if (!this.nsps[name]) {
debug('initializing namespace %s', name);
var nsp = new Namespace(this, name);
this.nsps[name] = nsp;
}
return this.nsps[name];
};
/**
* Expose main namespace (/).
*/
['use', 'to', 'in', 'emit', 'send', 'write'].forEach(function(name){
Server.prototype[name] = function(){
var nsp = this.sockets[name];
return nsp.apply(this.sockets, arguments);
};
});
Namespace.flags.forEach(function(flag){
Server.prototype.__defineGetter__(flag, function(name){
this.flags.push(name);
return this;
});
});
/**
* BC with `io.listen`
*/
Server.listen = Server;

View file

@ -11,6 +11,7 @@
var fs = require('fs')
, url = require('url')
, tty = require('tty')
, crypto = require('crypto')
, util = require('./util')
, store = require('./store')
, client = require('socket.io-client')
@ -44,7 +45,8 @@ var defaultTransports = exports.defaultTransports = [
*/
var parent = module.parent.exports
, protocol = parent.protocol;
, protocol = parent.protocol
, jsonpolling_re = /^\d+$/;
/**
* Manager constructor.
@ -91,7 +93,9 @@ function Manager (server, options) {
};
for (var i in options) {
this.settings[i] = options[i];
if (options.hasOwnProperty(i)) {
this.settings[i] = options[i];
}
}
var self = this;
@ -108,7 +112,7 @@ function Manager (server, options) {
});
// reset listeners
this.oldListeners = server.listeners('request');
this.oldListeners = server.listeners('request').splice(0);
server.removeAllListeners('request');
server.on('request', function (req, res) {
@ -128,8 +132,10 @@ function Manager (server, options) {
});
for (var i in transports) {
if (transports[i].init) {
transports[i].init(this);
if (transports.hasOwnProperty(i)) {
if (transports[i].init) {
transports[i].init(this);
}
}
}
@ -139,6 +145,8 @@ function Manager (server, options) {
self.emit('connection', conn);
});
this.sequenceNumber = Date.now() | 0;
this.log.info('socket.io started');
};
@ -343,12 +351,21 @@ Manager.prototype.onConnect = function (id) {
Manager.prototype.onOpen = function (id) {
this.open[id] = true;
// if we were buffering messages for the client, clear them
if (this.closed[id]) {
var self = this;
this.store.unsubscribe('dispatch:' + id, function () {
delete self.closed[id];
var transport = self.transports[id];
if (self.closed[id] && self.closed[id].length && transport) {
// if we have buffered messages that accumulate between calling
// onOpen an this async callback, send them if the transport is
// still open, otherwise leave them buffered
if (transport.open) {
transport.payload(self.closed[id]);
self.closed[id] = [];
}
}
});
}
@ -419,7 +436,10 @@ Manager.prototype.onLeave = function (id, room) {
if (!this.rooms[room].length) {
delete this.rooms[room];
}
delete this.roomClients[id][room];
if (this.roomClients[id]) {
delete this.roomClients[id][room];
}
}
};
@ -477,8 +497,10 @@ Manager.prototype.onClientMessage = function (id, packet) {
Manager.prototype.onClientDisconnect = function (id, reason) {
for (var name in this.namespaces) {
this.namespaces[name].handleDisconnect(id, reason, typeof this.roomClients[id] !== 'undefined' &&
typeof this.roomClients[id][name] !== 'undefined');
if (this.namespaces.hasOwnProperty(name)) {
this.namespaces[name].handleDisconnect(id, reason, typeof this.roomClients[id] !== 'undefined' &&
typeof this.roomClients[id][name] !== 'undefined');
}
}
this.onDisconnect(id);
@ -512,7 +534,9 @@ Manager.prototype.onDisconnect = function (id, local) {
if (this.roomClients[id]) {
for (var room in this.roomClients[id]) {
this.onLeave(id, room);
if (this.roomClients[id].hasOwnProperty(room)) {
this.onLeave(id, room);
}
}
delete this.roomClients[id]
}
@ -616,12 +640,15 @@ Manager.prototype.handleClient = function (data, req) {
, store = this.store
, self = this;
// handle sync disconnect xhrs
if (undefined != data.query.disconnect) {
if (this.transports[data.id] && this.transports[data.id].open) {
this.transports[data.id].onForcedDisconnect();
} else {
this.store.publish('disconnect-force:' + data.id);
}
req.res.writeHead(200);
req.res.end();
return;
}
@ -662,11 +689,13 @@ Manager.prototype.handleClient = function (data, req) {
// initialize the socket for all namespaces
for (var i in this.namespaces) {
var socket = this.namespaces[i].socket(data.id, true);
if (this.namespaces.hasOwnProperty(i)) {
var socket = this.namespaces[i].socket(data.id, true);
// echo back connect packet and fire connection event
if (i === '') {
this.namespaces[i].handlePacket(data.id, { type: 'connect' });
// echo back connect packet and fire connection event
if (i === '') {
this.namespaces[i].handlePacket(data.id, { type: 'connect' });
}
}
}
@ -694,8 +723,22 @@ Manager.prototype.handleClient = function (data, req) {
*/
Manager.prototype.generateId = function () {
return Math.abs(Math.random() * Math.random() * Date.now() | 0).toString()
+ Math.abs(Math.random() * Math.random() * Date.now() | 0).toString();
var rand = new Buffer(15); // multiple of 3 for base64
if (!rand.writeInt32BE) {
return Math.abs(Math.random() * Math.random() * Date.now() | 0).toString()
+ Math.abs(Math.random() * Math.random() * Date.now() | 0).toString();
}
this.sequenceNumber = (this.sequenceNumber + 1) | 0;
rand.writeInt32BE(this.sequenceNumber, 11);
if (crypto.randomBytes) {
crypto.randomBytes(12).copy(rand);
} else {
// not secure for node 0.4
[0, 4, 8].forEach(function(i) {
rand.writeInt32BE(Math.random() * Math.pow(2, 32) | 0, i);
});
}
return rand.toString('base64').replace(/\//g, '_').replace(/\+/g, '-');
};
/**
@ -712,7 +755,7 @@ Manager.prototype.handleHandshake = function (data, req, res) {
};
function writeErr (status, message) {
if (data.query.jsonp) {
if (data.query.jsonp && jsonpolling_re.test(data.query.jsonp)) {
res.writeHead(200, { 'Content-Type': 'application/javascript' });
res.end('io.j[' + data.query.jsonp + '](new Error("' + message + '"));');
} else {
@ -751,7 +794,7 @@ Manager.prototype.handleHandshake = function (data, req, res) {
, self.transports(data).join(',')
].join(':');
if (data.query.jsonp) {
if (data.query.jsonp && jsonpolling_re.test(data.query.jsonp)) {
hs = 'io.j[' + data.query.jsonp + '](' + JSON.stringify(hs) + ');';
res.writeHead(200, { 'Content-Type': 'application/javascript' });
} else {

View file

@ -15,7 +15,7 @@ var client = require('socket.io-client');
* Version.
*/
exports.version = '0.9.4';
exports.version = '0.9.11';
/**
* Supported protocol version.
@ -39,6 +39,13 @@ exports.clientVersion = client.version;
*/
exports.listen = function (server, options, fn) {
if ('function' == typeof server) {
console.warn('Socket.IO\'s `listen()` method expects an `http.Server` instance\n'
+ 'as its first parameter. Are you migrating from Express 2.x to 3.x?\n'
+ 'If so, check out the "Socket.IO compatibility" section at:\n'
+ 'https://github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x');
}
if ('function' == typeof options) {
fn = options;
options = {};

View file

@ -178,7 +178,7 @@ Static.prototype.gzip = function (data, callback) {
buffer.length = 0;
});
gzip.on('exit', function () {
gzip.on('close', function () {
if (err) return callback(err);
var size = 0

View file

@ -455,7 +455,7 @@ Transport.prototype.onClose = function () {
Transport.prototype.end = function (reason) {
if (!this.disconnected) {
this.log.info('transport end');
this.log.info('transport end (' + reason + ')');
var local = this.manager.transports[this.id];

View file

@ -1,4 +1,3 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
@ -53,9 +52,16 @@ FlashSocket.prototype.name = 'flashsocket';
FlashSocket.init = function (manager) {
var server;
function create () {
// Drop out immediately if the user has
// disabled the flash policy server
if (!manager.get('flash policy server')) {
return;
}
server = require('policyfile').createServer({
log: function(msg){
manager.log.info(msg.toLowerCase());
manager.log.info(msg);
}
}, manager.get('origins'));
@ -93,6 +99,23 @@ FlashSocket.init = function (manager) {
}
});
// create or destroy the server
manager.on('set:flash policy server', function (value, key) {
var transports = manager.get('transports');
if (~transports.indexOf('flashsocket')) {
if (server && !value) {
// destroy the server
try {
server.close();
}
catch (e) { /* ignore exception. could e.g. be that the server isn't started yet */ }
}
} else if (!server && value) {
// create the server
create();
}
});
// only start the server
manager.on('set:transports', function (value, key){
if (!server && ~manager.get('transports').indexOf('flashsocket')) {

View file

@ -43,6 +43,18 @@ HTTPPolling.prototype.__proto__ = HTTPTransport.prototype;
HTTPPolling.prototype.name = 'httppolling';
/**
* Override setHandlers
*
* @api private
*/
HTTPPolling.prototype.setHandlers = function () {
HTTPTransport.prototype.setHandlers.call(this);
this.socket.removeListener('end', this.bound.end);
this.socket.removeListener('close', this.bound.close);
};
/**
* Removes heartbeat timeouts for polling.
*/
@ -128,8 +140,8 @@ HTTPPolling.prototype.write = function (data, close) {
* @api private
*/
HTTPPolling.prototype.end = function () {
HTTPPolling.prototype.end = function (reason) {
this.clearPollTimeout();
return HTTPTransport.prototype.end.call(this);
return HTTPTransport.prototype.end.call(this, reason);
};

View file

@ -42,6 +42,10 @@ HTTPTransport.prototype.__proto__ = Transport.prototype;
*/
HTTPTransport.prototype.handleRequest = function (req) {
// Always set the response in case an error is returned to the client
this.response = req.res;
if (req.method == 'POST') {
var buffer = ''
, res = req.res
@ -68,6 +72,7 @@ HTTPTransport.prototype.handleRequest = function (req) {
// prevent memory leaks for uncompleted requests
req.on('close', function () {
buffer = '';
self.onClose();
});
if (origin) {
@ -76,8 +81,6 @@ HTTPTransport.prototype.handleRequest = function (req) {
headers['Access-Control-Allow-Credentials'] = 'true';
}
} else {
this.response = req.res;
Transport.prototype.handleRequest.call(this, req);
}
};

View file

@ -10,6 +10,7 @@
*/
var HTTPPolling = require('./http-polling');
var jsonpolling_re = /^\d+$/
/**
* Export the constructor.
@ -29,7 +30,7 @@ function JSONPPolling (mng, data, req) {
this.head = 'io.j[0](';
this.foot = ');';
if (data.query.i) {
if (data.query.i && jsonpolling_re.test(data.query.i)) {
this.head = 'io.j[' + data.query.i + '](';
}
};

View file

@ -1,4 +1,3 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
@ -89,11 +88,14 @@ WebSocket.prototype.onSocketConnect = function () {
}
var origin = this.req.headers['origin']
, location = ((this.manager.settings['match origin protocol'] ?
origin.match(/^https/) : this.socket.encrypted) ?
'wss' : 'ws')
+ '://' + this.req.headers.host + this.req.url
, waitingForNonce = false;
, waitingForNonce = false;
if(this.manager.settings['match origin protocol']){
location = (origin.indexOf('https')>-1 ? 'wss' : 'ws') + '://' + this.req.headers.host + this.req.url;
}else if(this.socket.encrypted){
location = 'wss://' + this.req.headers.host + this.req.url;
}else{
location = 'ws://' + this.req.headers.host + this.req.url;
}
if (this.req.headers['sec-websocket-key1']) {
// If we don't have the nonce yet, wait for it (HAProxy compatibility).

View file

@ -1,4 +1,3 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
@ -98,7 +97,7 @@ WebSocket.prototype.onSocketConnect = function () {
return;
}
var origin = this.req.headers['origin']
var origin = this.req.headers['origin'] || ''
, location = ((this.manager.settings['match origin protocol'] ?
origin.match(/^https/) : this.socket.encrypted) ?
'wss' : 'ws')

View file

@ -0,0 +1,3 @@
support
test
examples

View file

@ -0,0 +1,18 @@
base64id
========
Node.js module that generates a base64 id.
Uses crypto.randomBytes when available, falls back to unsafe methods for node.js <= 0.4.
To increase performance, random bytes are buffered to minimize the number of synchronous calls to crypto.randomBytes.
## Installation
$ npm install mongoose
## Usage
var base64id = require('base64id');
var id = base64id.generateId();

View file

@ -0,0 +1,103 @@
/*!
* base64id v0.1.0
*/
/**
* Module dependencies
*/
var crypto = require('crypto');
/**
* Constructor
*/
var Base64Id = function() { };
/**
* Get random bytes
*
* Uses a buffer if available, falls back to crypto.randomBytes
*/
Base64Id.prototype.getRandomBytes = function(bytes) {
var BUFFER_SIZE = 4096
var self = this;
bytes = bytes || 12;
if (bytes > BUFFER_SIZE) {
return crypto.randomBytes(bytes);
}
var bytesInBuffer = parseInt(BUFFER_SIZE/bytes);
var threshold = parseInt(bytesInBuffer*0.85);
if (!threshold) {
return crypto.randomBytes(bytes);
}
if (this.bytesBufferIndex == null) {
this.bytesBufferIndex = -1;
}
if (this.bytesBufferIndex == bytesInBuffer) {
this.bytesBuffer = null;
this.bytesBufferIndex = -1;
}
// No buffered bytes available or index above threshold
if (this.bytesBufferIndex == -1 || this.bytesBufferIndex > threshold) {
if (!this.isGeneratingBytes) {
this.isGeneratingBytes = true;
crypto.randomBytes(BUFFER_SIZE, function(err, bytes) {
self.bytesBuffer = bytes;
self.bytesBufferIndex = 0;
self.isGeneratingBytes = false;
});
}
// Fall back to sync call when no buffered bytes are available
if (this.bytesBufferIndex == -1) {
return crypto.randomBytes(bytes);
}
}
var result = this.bytesBuffer.slice(bytes*this.bytesBufferIndex, bytes*(this.bytesBufferIndex+1));
this.bytesBufferIndex++;
return result;
}
/**
* Generates a base64 id
*
* (Original version from socket.io <http://socket.io>)
*/
Base64Id.prototype.generateId = function () {
var rand = new Buffer(15); // multiple of 3 for base64
if (!rand.writeInt32BE) {
return Math.abs(Math.random() * Math.random() * Date.now() | 0).toString()
+ Math.abs(Math.random() * Math.random() * Date.now() | 0).toString();
}
this.sequenceNumber = (this.sequenceNumber + 1) | 0;
rand.writeInt32BE(this.sequenceNumber, 11);
if (crypto.randomBytes) {
this.getRandomBytes(12).copy(rand);
} else {
// not secure for node 0.4
[0, 4, 8].forEach(function(i) {
rand.writeInt32BE(Math.random() * Math.pow(2, 32) | 0, i);
});
}
return rand.toString('base64').replace(/\//g, '_').replace(/\+/g, '-');
};
/**
* Export
*/
exports = module.exports = new Base64Id();

View file

@ -0,0 +1,26 @@
{
"name": "base64id",
"version": "0.1.0",
"description": "Generates a base64 id",
"author": {
"name": "Kristian Faeldt",
"email": "faeldt_kristian@cyberagent.co.jp"
},
"repository": {
"type": "git",
"url": "git://github.com/faeldt/base64id.git"
},
"main": "./lib/base64id.js",
"engines": {
"node": ">= 0.4.0"
},
"_id": "base64id@0.1.0",
"dependencies": {},
"devDependencies": {},
"optionalDependencies": {},
"_engineSupported": true,
"_npmVersion": "1.1.12",
"_nodeVersion": "v0.6.14",
"_defaultsLoaded": true,
"_from": "base64id@0.1.0"
}

View file

@ -48,8 +48,5 @@
"_npmVersion": "1.1.12",
"_nodeVersion": "v0.6.14",
"_defaultsLoaded": true,
"dist": {
"shasum": "c43c7192ee7f5d9548139d1e4e5f4da24edfeb9d"
},
"_from": "policyfile@0.0.4"
}

View file

@ -0,0 +1 @@
node_modules

View file

@ -8,7 +8,7 @@ experimental Redis server branches.
Install with:
npm install redis
Pieter Noordhuis has provided a binding to the official `hiredis` C library, which is non-blocking and fast. To use `hiredis`, do:
npm install hiredis redis
@ -23,9 +23,13 @@ happen between node and native code modules after a node upgrade.
Simple example, included as `examples/simple.js`:
```js
var redis = require("redis"),
client = redis.createClient();
// if you'd like to select database 3, instead of 0 (default), call
// client.select(3, function() { /* ... */ });
client.on("error", function (err) {
console.log("Error " + err);
});
@ -40,6 +44,7 @@ Simple example, included as `examples/simple.js`:
});
client.quit();
});
```
This will display:
@ -50,7 +55,7 @@ This will display:
2 replies:
0: hashtest 1
1: hashtest 2
mjr:~/work/node_redis (master)$
mjr:~/work/node_redis (master)$
## Performance
@ -84,7 +89,7 @@ The performance of `node_redis` improves dramatically with pipelining, which hap
### Sending Commands
Each Redis command is exposed as a function on the `client` object.
All functions take either take either an `args` Array plus optional `callback` Function or
All functions take either an `args` Array plus optional `callback` Function or
a variable number of individual arguments followed by an optional callback.
Here is an example of passing an array of arguments and a callback:
@ -93,18 +98,25 @@ Here is an example of passing an array of arguments and a callback:
Here is that same call in the second style:
client.mset("test keys 1", "test val 1", "test keys 2", "test val 2", function (err, res) {});
Note that in either form the `callback` is optional:
client.set("some key", "some val");
client.set(["some other key", "some val"]);
If the key is missing, reply will be null (probably):
client.get("missingkey", function(err, reply) {
// reply is null when the key is missing
console.log(reply);
});
For a list of Redis commands, see [Redis Command Reference](http://redis.io/commands)
The commands can be specified in uppercase or lowercase for convenience. `client.get()` is the same as `client.GET()`.
Minimal parsing is done on the replies. Commands that return a single line reply return JavaScript Strings,
integer replies return JavaScript Numbers, "bulk" replies return node Buffers, and "multi bulk" replies return a
Minimal parsing is done on the replies. Commands that return a single line reply return JavaScript Strings,
integer replies return JavaScript Numbers, "bulk" replies return node Buffers, and "multi bulk" replies return a
JavaScript Array of node Buffers. `HGETALL` returns an Object with Buffers keyed by the hash keys.
# API
@ -115,8 +127,8 @@ JavaScript Array of node Buffers. `HGETALL` returns an Object with Buffers keye
### "ready"
`client` will emit `ready` a connection is established to the Redis server and the server reports
that it is ready to receive commands. Commands issued before the `ready` event are queued,
`client` will emit `ready` a connection is established to the Redis server and the server reports
that it is ready to receive commands. Commands issued before the `ready` event are queued,
then replayed just before this event is emitted.
### "connect"
@ -129,11 +141,11 @@ you are free to try to send commands.
`client` will emit `error` when encountering an error connecting to the Redis server.
Note that "error" is a special event type in node. If there are no listeners for an
"error" event, node will exit. This is usually what you want, but it can lead to some
Note that "error" is a special event type in node. If there are no listeners for an
"error" event, node will exit. This is usually what you want, but it can lead to some
cryptic error messages like this:
mjr:~/work/node_redis (master)$ node example.js
mjr:~/work/node_redis (master)$ node example.js
node.js:50
throw e;
@ -156,7 +168,7 @@ It would be nice to distinguish these two cases.
`client` will emit `drain` when the TCP connection to the Redis server has been buffering, but is now
writable. This event can be used to stream commands in to Redis and adapt to backpressure. Right now,
you need to check `client.command_queue.length` to decide when to reduce your send rate. Then you can
you need to check `client.command_queue.length` to decide when to reduce your send rate. Then you can
resume sending when you get `drain`.
### "idle"
@ -171,8 +183,43 @@ port and host are probably fine. `options` in an object with the following poss
* `parser`: which Redis protocol reply parser to use. Defaults to `hiredis` if that module is installed.
This may also be set to `javascript`.
* `return_buffers`: defaults to false. If set to `true`, then bulk data replies will be returned as node Buffer
* `return_buffers`: defaults to `false`. If set to `true`, then all replies will be sent to callbacks as node Buffer
objects instead of JavaScript Strings.
* `detect_buffers`: default to `false`. If set to `true`, then replies will be sent to callbacks as node Buffer objects
if any of the input arguments to the original command were Buffer objects.
This option lets you switch between Buffers and Strings on a per-command basis, whereas `return_buffers` applies to
every command on a client.
* `socket_nodelay`: defaults to `true`. Whether to call setNoDelay() on the TCP stream, which disables the
Nagle algorithm on the underlying socket. Setting this option to `false` can result in additional throughput at the
cost of more latency. Most applications will want this set to `true`.
* `no_ready_check`: defaults to `false`. When a connection is established to the Redis server, the server might still
be loading the database from disk. While loading, the server not respond to any commands. To work around this,
`node_redis` has a "ready check" which sends the `INFO` command to the server. The response from the `INFO` command
indicates whether the server is ready for more commands. When ready, `node_redis` emits a `ready` event.
Setting `no_ready_check` to `true` will inhibit this check.
* `enable_offline_queue`: defaults to `true`. By default, if there is no active
connection to the redis server, commands are added to a queue and are executed
once the connection has been established. Setting `enable_offline_queue` to
`false` will disable this feature and the callback will be execute immediately
with an error, or an error will be thrown if no callback is specified.
```js
var redis = require("redis"),
client = redis.createClient(null, null, {detect_buffers: true});
client.set("foo_rand000000000000", "OK");
// This will return a JavaScript String
client.get("foo_rand000000000000", function (err, reply) {
console.log(reply.toString()); // Will print `OK`
});
// This will return a Buffer since original key is specified as a Buffer
client.get(new Buffer("foo_rand000000000000"), function (err, reply) {
console.log(reply.toString()); // Will print `<Buffer 4f 4b>`
});
client.end();
```
`createClient()` returns a `RedisClient` object that is named `client` in all of the examples here.
@ -183,15 +230,19 @@ first command after connecting. This can be tricky to coordinate with reconnect
etc. To make this easier, `client.auth()` stashes `password` and will send it after each connection,
including reconnections. `callback` is invoked only once, after the response to the very first
`AUTH` command sent.
NOTE: Your call to `client.auth()` should not be inside the ready handler. If
you are doing this wrong, `client` will emit an error that looks
something like this `Error: Ready check failed: ERR operation not permitted`.
## client.end()
Forcibly close the connection to the Redis server. Note that this does not wait until all replies have been parsed.
If you want to exit cleanly, call `client.quit()` to send the `QUIT` command after you have handled all replies.
This example closes the connection to the Redis server before the replies have been read. You probably don't
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();
@ -200,17 +251,19 @@ want to do this:
console.log(reply.toString());
});
client.end();
```
`client.end()` is useful for timeout cases where something is stuck or taking too long and you want
`client.end()` is useful for timeout cases where something is stuck or taking too long and you want
to start over.
## Friendlier hash commands
Most Redis commands take a single String or an Array of Strings as arguments, and replies are sent back as a single String or an Array of Strings. When dealing with hash values, there are a couple of useful exceptions to this.
Most Redis commands take a single String or an Array of Strings as arguments, and replies are sent back as a single String or an Array of Strings.
When dealing with hash values, there are a couple of useful exceptions to this.
### client.hgetall(hash)
The reply from an HGETALL command will be converted into a JavaScript Object by `node_redis`. That way you can interact
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:
@ -229,7 +282,7 @@ Output:
Multiple values in a hash can be set by supplying an object:
client.HMSET(key2, {
"0123456789": "abcdefghij",
"0123456789": "abcdefghij", // NOTE: the key and value must both be strings
"some manner of key": "a type of value"
});
@ -245,9 +298,10 @@ Multiple values may also be set by supplying a list:
## Publish / Subscribe
Here is a simple example of the API for publish / subscribe. This program opens two
client connections, subscribes to a channel on one of them, and publishes to that
client connections, subscribes to a channel on one of them, and publishes to that
channel on the other:
```js
var redis = require("redis"),
client1 = redis.createClient(), client2 = redis.createClient(),
msg_count = 0;
@ -270,9 +324,10 @@ channel on the other:
client1.incr("did a thing");
client1.subscribe("a nice channel");
```
When a client issues a `SUBSCRIBE` or `PSUBSCRIBE`, that connection is put into "pub/sub" mode.
At that point, only commands that modify the subscription set are valid. When the subscription
At that point, only commands that modify the subscription set are valid. When the subscription
set is empty, the connection is put back into regular mode.
If you need to send regular commands to Redis while in pub/sub mode, just open another connection.
@ -294,23 +349,23 @@ name as `channel`, and the message Buffer as `message`.
### "subscribe" (channel, count)
Client will emit `subscribe` in response to a `SUBSCRIBE` command. Listeners are passed the
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)
### "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
Client will emit `unsubscribe` in response to a `UNSUBSCRIBE` command. Listeners are passed the
channel name as `channel` and the new count of subscriptions for this client as `count`. When
`count` is 0, this client has left pub/sub mode and no more pub/sub events will be emitted.
### "punsubscribe" (pattern, count)
Client will emit `punsubscribe` in response to a `PUNSUBSCRIBE` command. Listeners are passed the
Client will emit `punsubscribe` in response to a `PUNSUBSCRIBE` command. Listeners are passed the
channel name as `channel` and the new count of subscriptions for this client as `count`. When
`count` is 0, this client has left pub/sub mode and no more pub/sub events will be emitted.
@ -319,6 +374,7 @@ channel name as `channel` and the new count of subscriptions for this client as
`MULTI` commands are queued up until an `EXEC` is issued, and then all commands are run atomically by
Redis. The interface in `node_redis` is to return an individual `Multi` object by calling `client.multi()`.
```js
var redis = require("./index"),
client = redis.createClient(), set_size = 20;
@ -335,6 +391,8 @@ Redis. The interface in `node_redis` is to return an individual `Multi` object
.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()
@ -344,6 +402,7 @@ Redis. The interface in `node_redis` is to return an individual `Multi` object
console.log("Reply " + index + ": " + reply.toString());
});
});
```
`client.multi()` is a constructor that returns a `Multi` object. `Multi` objects share all of the
same command methods as `client` objects do. Commands are queued up inside the `Multi` object
@ -352,10 +411,11 @@ until `Multi.exec()` is invoked.
You can either chain together `MULTI` commands as in the above example, or you can queue individual
commands while still sending regular client command as in this example:
```js
var redis = require("redis"),
client = redis.createClient(), multi;
// start a separate multi command queue
// start a separate multi command queue
multi = client.multi();
multi.incr("incr thing", redis.print);
multi.incr("incr other thing", redis.print);
@ -373,10 +433,12 @@ commands while still sending regular client command as in this example:
console.log(replies); // 102, 3
client.quit();
});
```
In addition to adding commands to the `MULTI` queue individually, you can also pass an array
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;
@ -387,6 +449,7 @@ of commands and arguments to the constructor:
]).exec(function (err, replies) {
console.log(replies);
});
```
## Monitor mode
@ -395,11 +458,12 @@ Redis supports the `MONITOR` command, which lets you see all commands received b
across all client connections, including from other client libraries and other computers.
After you send the `MONITOR` command, no other commands are valid on that connection. `node_redis`
will emit a `monitor` event for every new monitor message that comes across. The callback for the
will emit a `monitor` event for every new monitor message that comes across. The callback for the
`monitor` event takes a timestamp from the Redis server and an array of command arguments.
Here is a simple example:
```js
var client = require("redis").createClient(),
util = require("util");
@ -410,7 +474,7 @@ Here is a simple example:
client.on("monitor", function (time, args) {
console.log(time + ": " + util.inspect(args));
});
```
# Extras
@ -418,7 +482,7 @@ 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`
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.
@ -432,6 +496,7 @@ The `versions` key contains an array of the elements of the version string for e
A handy callback function for displaying return values when testing. Example:
```js
var redis = require("redis"),
client = redis.createClient();
@ -439,6 +504,7 @@ A handy callback function for displaying return values when testing. Example:
client.set("foo_rand000000000000", "some fantastic value", redis.print);
client.get("foo_rand000000000000", redis.print);
});
```
This will print:
@ -451,6 +517,7 @@ Note that this program will not exit cleanly because the client is still connect
Boolean to enable debug mode and protocol tracing.
```js
var redis = require("redis"),
client = redis.createClient();
@ -459,10 +526,11 @@ Boolean to enable debug mode and protocol tracing.
client.on("connect", function () {
client.set("foo_rand000000000000", "some fantastic value");
});
```
This will display:
mjr:~/work/node_redis (master)$ node ~/example.js
mjr:~/work/node_redis (master)$ node ~/example.js
send command: *3
$3
SET
@ -477,12 +545,11 @@ This will display:
## client.send_command(command_name, args, callback)
Used internally to send commands to Redis. For convenience, nearly all commands that are published on the Redis
Used internally to send commands to Redis. For convenience, nearly all commands that are published on the Redis
Wiki have been added to the `client` object. However, if I missed any, or if new commands are introduced before
this library is updated, you can use `send_command()` to send arbitrary commands to Redis.
All commands are sent as multi-bulk commands. `args` can either be an Array of arguments, or individual arguments,
or omitted completely.
All commands are sent as multi-bulk commands. `args` can either be an Array of arguments, or omitted.
## client.connected
@ -490,7 +557,7 @@ 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
The number of commands that have been sent to the Redis server but not yet replied to. You can use this to
enforce some kind of maximum queue depth for commands while connected.
Don't mess with `client.command_queue` though unless you really know what you are doing.
@ -509,10 +576,38 @@ Current delay in milliseconds before a connection retry will be attempted. This
Multiplier for future retry timeouts. This should be larger than 1 to add more time between retries.
Defaults to 1.7. The default initial connection retry is 250, so the second retry will be 425, followed by 723.5, etc.
### Commands with Optional and Keyword arguments
This applies to anything that uses an optional `[WITHSCORES]` or `[LIMIT offset count]` in the [redis.io/commands](http://redis.io/commands) documentation.
Example:
```js
var args = [ 'myzset', 1, 'one', 2, 'two', 3, 'three', 99, 'ninety-nine' ];
client.zadd(args, function (err, response) {
if (err) throw err;
console.log('added '+response+' items.');
// -Infinity and +Infinity also work
var args1 = [ 'myzset', '+inf', '-inf' ];
client.zrevrangebyscore(args1, function (err, response) {
if (err) throw err;
console.log('example1', response);
// write your code here
});
var max = 3, min = 1, offset = 1, count = 2;
var args2 = [ 'myzset', max, min, 'WITHSCORES', 'LIMIT', offset, count ];
client.zrevrangebyscore(args2, function (err, response) {
if (err) throw err;
console.log('example2', response);
// write your code here
});
});
```
## TODO
Better tests for monitor mode, auth, disconnect/reconnect, and all combinations thereof.
Better tests for auth, disconnect/reconnect, and all combinations thereof.
Stream large set/get values into and out of Redis. Otherwise the entire value must be in node's memory.
@ -520,22 +615,51 @@ Performance can be better for very large values.
I think there are more performance improvements left in there for smaller values, especially for large lists of small values.
## Contributors
## How to Contribute
- open a pull request and then wait for feedback (if
[DTrejo](http://github.com/dtrejo) does not get back to you within 2 days,
comment again with indignation!)
## Contributors
Some people have have added features and fixed bugs in `node_redis` other than me.
In order of first contribution, they are:
Ordered by date of first contribution.
[Auto-generated](http://github.com/dtrejo/node-authors) on Wed Jul 25 2012 19:14:59 GMT-0700 (PDT).
* [Tim Smart](https://github.com/Tim-Smart)
* [TJ Holowaychuk](https://github.com/visionmedia)
* [Rick Olson](https://github.com/technoweenie)
* [Orion Henry](https://github.com/orionz)
* [Hank Sims](https://github.com/hanksims)
* [Aivo Paas](https://github.com/aivopaas)
* [Paul Carey](https://github.com/paulcarey)
* [Pieter Noordhuis](https://github.com/pietern)
* [Vladimir Dronnikov](https://github.com/dvv)
* [Dave Hoover](https://github.com/redsquirrel)
- [Matt Ranney aka `mranney`](https://github.com/mranney)
- [Tim-Smart aka `tim-smart`](https://github.com/tim-smart)
- [Tj Holowaychuk aka `visionmedia`](https://github.com/visionmedia)
- [rick aka `technoweenie`](https://github.com/technoweenie)
- [Orion Henry aka `orionz`](https://github.com/orionz)
- [Aivo Paas aka `aivopaas`](https://github.com/aivopaas)
- [Hank Sims aka `hanksims`](https://github.com/hanksims)
- [Paul Carey aka `paulcarey`](https://github.com/paulcarey)
- [Pieter Noordhuis aka `pietern`](https://github.com/pietern)
- [nithesh aka `nithesh`](https://github.com/nithesh)
- [Andy Ray aka `andy2ray`](https://github.com/andy2ray)
- [unknown aka `unknowdna`](https://github.com/unknowdna)
- [Dave Hoover aka `redsquirrel`](https://github.com/redsquirrel)
- [Vladimir Dronnikov aka `dvv`](https://github.com/dvv)
- [Umair Siddique aka `umairsiddique`](https://github.com/umairsiddique)
- [Louis-Philippe Perron aka `lp`](https://github.com/lp)
- [Mark Dawson aka `markdaws`](https://github.com/markdaws)
- [Ian Babrou aka `bobrik`](https://github.com/bobrik)
- [Felix Geisendörfer aka `felixge`](https://github.com/felixge)
- [Jean-Hugues Pinson aka `undefined`](https://github.com/undefined)
- [Maksim Lin aka `maks`](https://github.com/maks)
- [Owen Smith aka `orls`](https://github.com/orls)
- [Zachary Scott aka `zzak`](https://github.com/zzak)
- [TEHEK Firefox aka `TEHEK`](https://github.com/TEHEK)
- [Isaac Z. Schlueter aka `isaacs`](https://github.com/isaacs)
- [David Trejo aka `DTrejo`](https://github.com/DTrejo)
- [Brian Noguchi aka `bnoguchi`](https://github.com/bnoguchi)
- [Philip Tellis aka `bluesmoon`](https://github.com/bluesmoon)
- [Marcus Westin aka `marcuswestin2`](https://github.com/marcuswestin2)
- [Jed Schmidt aka `jed`](https://github.com/jed)
- [Dave Peticolas aka `jdavisp3`](https://github.com/jdavisp3)
- [Trae Robrock aka `trobrock`](https://github.com/trobrock)
- [Shankar Karuppiah aka `shankar0306`](https://github.com/shankar0306)
- [Ignacio Burgueño aka `ignacio`](https://github.com/ignacio)
Thanks.

View file

@ -0,0 +1,89 @@
var source = new Buffer(100),
dest = new Buffer(100), i, j, k, tmp, count = 1000000, bytes = 100;
for (i = 99 ; i >= 0 ; i--) {
source[i] = 120;
}
var str = "This is a nice String.",
buf = new Buffer("This is a lovely Buffer.");
var start = new Date();
for (i = count * 100; i > 0 ; i--) {
if (Buffer.isBuffer(str)) {}
}
var end = new Date();
console.log("Buffer.isBuffer(str) " + (end - start) + " ms");
var start = new Date();
for (i = count * 100; i > 0 ; i--) {
if (Buffer.isBuffer(buf)) {}
}
var end = new Date();
console.log("Buffer.isBuffer(buf) " + (end - start) + " ms");
var start = new Date();
for (i = count * 100; i > 0 ; i--) {
if (str instanceof Buffer) {}
}
var end = new Date();
console.log("str instanceof Buffer " + (end - start) + " ms");
var start = new Date();
for (i = count * 100; i > 0 ; i--) {
if (buf instanceof Buffer) {}
}
var end = new Date();
console.log("buf instanceof Buffer " + (end - start) + " ms");
for (i = bytes ; i > 0 ; i --) {
var start = new Date();
for (j = count ; j > 0; j--) {
tmp = source.toString("ascii", 0, bytes);
}
var end = new Date();
console.log("toString() " + i + " bytes " + (end - start) + " ms");
}
for (i = bytes ; i > 0 ; i --) {
var start = new Date();
for (j = count ; j > 0; j--) {
tmp = "";
for (k = 0; k <= i ; k++) {
tmp += String.fromCharCode(source[k]);
}
}
var end = new Date();
console.log("manual string " + i + " bytes " + (end - start) + " ms");
}
for (i = bytes ; i > 0 ; i--) {
var start = new Date();
for (j = count ; j > 0 ; j--) {
for (k = i ; k > 0 ; k--) {
dest[k] = source[k];
}
}
var end = new Date();
console.log("Manual copy " + i + " bytes " + (end - start) + " ms");
}
for (i = bytes ; i > 0 ; i--) {
var start = new Date();
for (j = count ; j > 0 ; j--) {
for (k = i ; k > 0 ; k--) {
dest[k] = 120;
}
}
var end = new Date();
console.log("Direct assignment " + i + " bytes " + (end - start) + " ms");
}
for (i = bytes ; i > 0 ; i--) {
var start = new Date();
for (j = count ; j > 0 ; j--) {
source.copy(dest, 0, 0, i);
}
var end = new Date();
console.log("Buffer.copy() " + i + " bytes " + (end - start) + " ms");
}

View file

@ -0,0 +1,38 @@
var Parser = require('../lib/parser/hiredis').Parser;
var assert = require('assert');
/*
This test makes sure that exceptions thrown inside of "reply" event handlers
are not trapped and mistakenly emitted as parse errors.
*/
(function testExecuteDoesNotCatchReplyCallbackExceptions() {
var parser = new Parser();
var replies = [{}];
parser.reader = {
feed: function() {},
get: function() {
return replies.shift();
}
};
var emittedError = false;
var caughtException = false;
parser
.on('error', function() {
emittedError = true;
})
.on('reply', function() {
throw new Error('bad');
});
try {
parser.execute();
} catch (err) {
caughtException = true;
}
assert.equal(caughtException, true);
assert.equal(emittedError, false);
})();

View file

@ -0,0 +1,14 @@
var client = require('../index').createClient()
, client2 = require('../index').createClient()
, assert = require('assert');
client.once('subscribe', function (channel, count) {
client.unsubscribe('x');
client.subscribe('x', function () {
client.quit();
client2.quit();
});
client2.publish('x', 'hi');
});
client.subscribe('x');

View file

@ -0,0 +1,29 @@
var redis = require("../index").createClient(null, null, {
// max_attempts: 4
});
redis.on("error", function (err) {
console.log("Redis says: " + err);
});
redis.on("ready", function () {
console.log("Redis ready.");
});
redis.on("reconnecting", function (arg) {
console.log("Redis reconnecting: " + JSON.stringify(arg));
});
redis.on("connect", function () {
console.log("Redis connected.");
});
setInterval(function () {
var now = Date.now();
redis.set("now", now, function (err, res) {
if (err) {
console.log(now + " Redis reply error: " + err);
} else {
console.log(now + " Redis reply: " + res);
}
});
}, 100);

View file

@ -0,0 +1,16 @@
var json = {
encode: JSON.stringify,
decode: JSON.parse
};
var MsgPack = require('node-msgpack');
msgpack = {
encode: MsgPack.pack,
decode: function(str) { return MsgPack.unpack(new Buffer(str)); }
};
bison = require('bison');
module.exports = json;
//module.exports = msgpack;
//module.exports = bison;

View file

@ -0,0 +1,38 @@
'use strict';
var freemem = require('os').freemem;
var profiler = require('v8-profiler');
var codec = require('../codec');
var sent = 0;
var pub = require('redis').createClient(null, null, {
//command_queue_high_water: 5,
//command_queue_low_water: 1
})
.on('ready', function() {
this.emit('drain');
})
.on('drain', function() {
process.nextTick(exec);
});
var payload = '1'; for (var i = 0; i < 12; ++i) payload += payload;
console.log('Message payload length', payload.length);
function exec() {
pub.publish('timeline', codec.encode({ foo: payload }));
++sent;
if (!pub.should_buffer) {
process.nextTick(exec);
}
}
profiler.takeSnapshot('s_0');
exec();
setInterval(function() {
profiler.takeSnapshot('s_' + sent);
console.error('sent', sent, 'free', freemem(), 'cmdqlen', pub.command_queue.length, 'offqlen', pub.offline_queue.length);
}, 2000);

View file

@ -0,0 +1,10 @@
#!/bin/sh
node server.js &
node server.js &
node server.js &
node server.js &
node server.js &
node server.js &
node server.js &
node server.js &
node --debug pub.js

View file

@ -0,0 +1,23 @@
'use strict';
var freemem = require('os').freemem;
var codec = require('../codec');
var id = Math.random();
var recv = 0;
var sub = require('redis').createClient()
.on('ready', function() {
this.subscribe('timeline');
})
.on('message', function(channel, message) {
var self = this;
if (message) {
message = codec.decode(message);
++recv;
}
});
setInterval(function() {
console.error('id', id, 'received', recv, 'free', freemem());
}, 2000);

View file

@ -0,0 +1,49 @@
'use strict';
var freemem = require('os').freemem;
//var profiler = require('v8-profiler');
var codec = require('../codec');
var sent = 0;
var pub = require('redis').createClient(null, null, {
//command_queue_high_water: 5,
//command_queue_low_water: 1
})
.on('ready', function() {
this.del('timeline');
this.emit('drain');
})
.on('drain', function() {
process.nextTick(exec);
});
var payload = '1'; for (var i = 0; i < 12; ++i) payload += payload;
console.log('Message payload length', payload.length);
function exec() {
pub.rpush('timeline', codec.encode({ foo: payload }));
++sent;
if (!pub.should_buffer) {
process.nextTick(exec);
}
}
//profiler.takeSnapshot('s_0');
exec();
setInterval(function() {
//var ss = profiler.takeSnapshot('s_' + sent);
//console.error(ss.stringify());
pub.llen('timeline', function(err, result) {
console.error('sent', sent, 'free', freemem(),
'cmdqlen', pub.command_queue.length, 'offqlen', pub.offline_queue.length,
'llen', result
);
});
}, 2000);
/*setTimeout(function() {
process.exit();
}, 30000);*/

View file

@ -0,0 +1,6 @@
#!/bin/sh
node server.js &
#node server.js &
#node server.js &
#node server.js &
node --debug pub.js

View file

@ -0,0 +1,30 @@
'use strict';
var freemem = require('os').freemem;
var codec = require('../codec');
var id = Math.random();
var recv = 0;
var cmd = require('redis').createClient();
var sub = require('redis').createClient()
.on('ready', function() {
this.emit('timeline');
})
.on('timeline', function() {
var self = this;
this.blpop('timeline', 0, function(err, result) {
var message = result[1];
if (message) {
message = codec.decode(message);
++recv;
}
self.emit('timeline');
});
});
setInterval(function() {
cmd.llen('timeline', function(err, result) {
console.error('id', id, 'received', recv, 'free', freemem(), 'llen', result);
});
}, 2000);

View file

@ -0,0 +1,13 @@
# size JSON msgpack bison
26602 2151.0170848180414
25542 ? 2842.589272665782
24835 ? ? 7280.4538397469805
6104 6985.234528557929
5045 ? 7217.461392841478
4341 ? ? 14261.406335354604
4180 15864.633685636572
4143 ? 12954.806235781925
4141 ? ? 44650.70733912719
75 114227.07313350472
40 ? 30162.440062810834
39 ? ? 119815.66013519121

View file

@ -0,0 +1,13 @@
#!/bin/sh
gnuplot >size-rate.jpg << _EOF_
set terminal png nocrop enhanced font verdana 12 size 640,480
set logscale x
set logscale y
set grid
set xlabel 'Serialized object size, octets'
set ylabel 'decode(encode(obj)) rate, 1/sec'
plot '00' using 1:2 title 'json' smooth bezier, '00' using 1:3 title 'msgpack' smooth bezier, '00' using 1:4 title 'bison' smooth bezier
_EOF_

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View file

@ -0,0 +1,84 @@
var msgpack = require('node-msgpack');
var bison = require('bison');
var codec = {
JSON: {
encode: JSON.stringify,
decode: JSON.parse
},
msgpack: {
encode: msgpack.pack,
decode: msgpack.unpack
},
bison: bison
};
var obj, l;
var s = '0';
for (var i = 0; i < 12; ++i) s += s;
obj = {
foo: s,
arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333],
rand: [],
a: s,
ccc: s,
b: s + s + s
};
for (i = 0; i < 100; ++i) obj.rand.push(Math.random());
forObj(obj);
obj = {
foo: s,
arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333],
rand: []
};
for (i = 0; i < 100; ++i) obj.rand.push(Math.random());
forObj(obj);
obj = {
foo: s,
arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333],
rand: []
};
forObj(obj);
obj = {
arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333],
rand: []
};
forObj(obj);
function run(obj, codec) {
var t1 = Date.now();
var n = 10000;
for (var i = 0; i < n; ++i) {
codec.decode(l = codec.encode(obj));
}
var t2 = Date.now();
//console.log('DONE', n*1000/(t2-t1), 'codecs/sec, length=', l.length);
return [n*1000/(t2-t1), l.length];
}
function series(obj, cname, n) {
var rate = 0;
var len = 0;
for (var i = 0; i < n; ++i) {
var r = run(obj, codec[cname]);
rate += r[0];
len += r[1];
}
rate /= n;
len /= n;
console.log(cname + ' ' + rate + ' ' + len);
return [rate, len];
}
function forObj(obj) {
var r = {
JSON: series(obj, 'JSON', 20),
msgpack: series(obj, 'msgpack', 20),
bison: series(obj, 'bison', 20)
};
return r;
}

View file

@ -0,0 +1,18 @@
var client = require("redis").createClient(),
client2 = require("redis").createClient();
client.subscribe("something");
client.on("subscribe", function (channel, count) {
console.log("Got sub: " + channel);
client.unsubscribe("something");
});
client.on("unsubscribe", function (channel, count) {
console.log("Got unsub: " + channel + ", quitting");
client.quit();
});
// exercise unsub before sub
client2.unsubscribe("something");
client2.subscribe("another thing");
client2.quit();

View file

@ -1,6 +1,41 @@
Changelog
=========
## v0.7.2 - April 29, 2012
Many contributed fixes. Thank you, contributors.
* [GH-190] - pub/sub mode fix (Brian Noguchi)
* [GH-165] - parser selection fix (TEHEK)
* numerous documentation and examples updates
* auth errors emit Errors instead of Strings (David Trejo)
## v0.7.1 - November 15, 2011
Fix regression in reconnect logic.
Very much need automated tests for reconnection and queue logic.
## v0.7.0 - November 14, 2011
Many contributed fixes. Thanks everybody.
* [GH-127] - properly re-initialize parser on reconnect
* [GH-136] - handle passing undefined as callback (Ian Babrou)
* [GH-139] - properly handle exceptions thrown in pub/sub event handlers (Felix Geisendörfer)
* [GH-141] - detect closing state on stream error (Felix Geisendörfer)
* [GH-142] - re-select database on reconnection (Jean-Hugues Pinson)
* [GH-146] - add sort example (Maksim Lin)
Some more goodies:
* Fix bugs with node 0.6
* Performance improvements
* New version of `multi_bench.js` that tests more realistic scenarios
* [GH-140] - support optional callback for subscribe commands
* Properly flush and error out command queue when connection fails
* Initial work on reconnection thresholds
## v0.6.7 - July 30, 2011
(accidentally skipped v0.6.6)

View file

@ -0,0 +1,87 @@
#!/usr/bin/env node
var colors = require('colors'),
fs = require('fs'),
_ = require('underscore'),
metrics = require('metrics'),
// `node diff_multi_bench_output.js before.txt after.txt`
before = process.argv[2],
after = process.argv[3];
if (!before || !after) {
console.log('Please supply two file arguments:');
var n = __filename;
n = n.substring(n.lastIndexOf('/', n.length));
console.log(' ./' + n + ' multiBenchBefore.txt multiBenchAfter.txt');
console.log('To generate multiBenchBefore.txt, run');
console.log(' node multi_bench.js > multiBenchBefore.txt');
console.log('Thank you for benchmarking responsibly.');
return;
}
var before_lines = fs.readFileSync(before, 'utf8').split('\n'),
after_lines = fs.readFileSync(after, 'utf8').split('\n');
console.log('Comparing before,', before.green, '(', before_lines.length,
'lines)', 'to after,', after.green, '(', after_lines.length, 'lines)');
var total_ops = new metrics.Histogram.createUniformHistogram();
before_lines.forEach(function(b, i) {
var a = after_lines[i];
if (!a || !b || !b.trim() || !a.trim()) {
// console.log('#ignored#', '>'+a+'<', '>'+b+'<');
return;
}
b_words = b.split(' ').filter(is_whitespace);
a_words = a.split(' ').filter(is_whitespace);
var ops =
[b_words, a_words]
.map(function(words) {
// console.log(words);
return parseInt10(words.slice(-2, -1));
}).filter(function(num) {
var isNaN = !num && num !== 0;
return !isNaN;
});
if (ops.length != 2) return
var delta = ops[1] - ops[0];
total_ops.update(delta);
delta = humanize_diff(delta);
console.log(
// name of test
command_name(a_words) == command_name(b_words)
? command_name(a_words) + ':'
: '404:',
// results of test
ops.join(' -> '), 'ops/sec (∆', delta, ')');
});
console.log('Mean difference in ops/sec:', humanize_diff(total_ops.mean()));
function is_whitespace(s) {
return !!s.trim();
}
function parseInt10(s) {
return parseInt(s, 10);
}
// green if greater than 0, red otherwise
function humanize_diff(num) {
if (num > 0) {
return ('+' + num).green;
}
return ('' + num).red;
}
function command_name(words) {
var line = words.join(' ');
return line.substr(0, line.indexOf(','));
}

View file

@ -2,16 +2,23 @@ var redis = require("redis"),
client = redis.createClient();
client.on("error", function (err) {
console.log("Redis connection error to " + client.host + ":" + client.port + " - " + err);
console.log("error event - " + client.host + ":" + client.port + " - " + err);
});
client.set("string key", "string val", redis.print);
client.hset("hash key", "hashtest 1", "some value", redis.print);
client.hset(["hash key", "hashtest 2", "some other value"], redis.print);
client.hkeys("hash key", function (err, replies) {
if (err) {
return console.error("error response - " + err);
}
console.log(replies.length + " replies:");
replies.forEach(function (reply, i) {
console.log(" " + i + ": " + reply);
});
client.quit();
});
client.quit(function (err, res) {
console.log("Exiting from quit command.");
});

View file

@ -0,0 +1,17 @@
var redis = require("redis"),
client = redis.createClient();
client.sadd("mylist", 1);
client.sadd("mylist", 2);
client.sadd("mylist", 3);
client.set("weight_1", 5);
client.set("weight_2", 500);
client.set("weight_3", 1);
client.set("object_1", "foo");
client.set("object_2", "bar");
client.set("object_3", "qux");
client.sort("mylist", "by", "weight_*", "get", "object_*", redis.print);
// Prints Reply: qux,foo,bar

View file

@ -1,5 +1,4 @@
var http = require("http"),
sys = require("sys"),
fs = require("fs");
function prettyCurrentTime() {

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more