Comparing version 0.1.0 to 0.2.0
0.2.0 / 2012-09-27 | ||
================== | ||
* add default random `identity` | ||
* add `req.send()` callback support | ||
* remove router / dealer | ||
* change `ReqSocket` to round-robin send()s | ||
0.1.0 / 2012-09-24 | ||
@@ -3,0 +11,0 @@ ================== |
@@ -15,4 +15,2 @@ | ||
exports.EmitterSocket = require('./sockets/emitter'); | ||
exports.RouterSocket = require('./sockets/router'); | ||
exports.DealerSocket = require('./sockets/dealer'); | ||
exports.ReqSocket = require('./sockets/req'); | ||
@@ -32,4 +30,2 @@ exports.RepSocket = require('./sockets/rep'); | ||
emitter: exports.EmitterSocket, | ||
router: exports.RouterSocket, | ||
dealer: exports.DealerSocket, | ||
req: exports.ReqSocket, | ||
@@ -36,0 +32,0 @@ rep: exports.RepSocket |
@@ -43,10 +43,4 @@ | ||
if (!multipart) return debug('rep expects multipart'); | ||
var envelopes = []; | ||
for (var i = 0; i < msg.length; ++i) { | ||
if ('\u0000' === String(msg[i])) { | ||
envelopes = msg.splice(0, ++i); | ||
} | ||
} | ||
var id = msg.pop(); | ||
self.emit.apply(self, ['message'].concat(msg, reply)); | ||
@@ -56,3 +50,4 @@ | ||
var args = [].slice.call(arguments); | ||
sock.write(self.pack(envelopes.concat(args))); | ||
args.push(id); | ||
sock.write(self.pack(args)); | ||
} | ||
@@ -59,0 +54,0 @@ }; |
@@ -10,3 +10,2 @@ | ||
/** | ||
@@ -26,2 +25,6 @@ * Expose `ReqSocket`. | ||
Socket.call(this); | ||
this.n = 0; | ||
this.ids = 0; | ||
this.callbacks = {}; | ||
this.identity = this.get('identity'); | ||
this.use(queue()); | ||
@@ -37,2 +40,13 @@ } | ||
/** | ||
* Return a message id. | ||
* | ||
* @return {String} | ||
* @api private | ||
*/ | ||
ReqSocket.prototype.id = function(){ | ||
return this.identity + ':' + this.ids++; | ||
}; | ||
/** | ||
* Emits the "message" event with all message parts | ||
@@ -50,4 +64,7 @@ * after the null delimeter part. | ||
if (!multipart) return debug('expected multipart'); | ||
if ('\u0000' != String(msg[0])) return debug('malformed message'); | ||
self.emit.apply(self, ['message'].concat(msg.slice(1))); | ||
var id = msg.pop(); | ||
var fn = self.callbacks[id]; | ||
if (!fn) return debug('missing callback %s', id); | ||
fn.apply(null, msg); | ||
delete self.callbacks[id]; | ||
}; | ||
@@ -65,3 +82,5 @@ }; | ||
ReqSocket.prototype.send = function(msg){ | ||
var sock = this.socks[0] | ||
var socks = this.socks | ||
, len = socks.length | ||
, sock = socks[this.n++ % len] | ||
, args = []; | ||
@@ -78,7 +97,16 @@ | ||
if (sock) { | ||
sock.write(this.pack(['\u0000'].concat(args))); | ||
if ('function' == typeof args[args.length - 1]) { | ||
var fn = args.pop(); | ||
fn.id = this.id(); | ||
this.callbacks[fn.id] = fn; | ||
args.push(fn.id); | ||
} | ||
} | ||
if (sock) { | ||
sock.write(this.pack(args)); | ||
} else { | ||
debug('no connected peers'); | ||
this.enqueue(msg); | ||
this.enqueue(args); | ||
} | ||
}; |
@@ -43,3 +43,3 @@ | ||
this.format('none'); | ||
this.set('identity', '\u0000'); | ||
this.set('identity', String(process.pid)); | ||
this.set('retry timeout', 100); | ||
@@ -46,0 +46,0 @@ this.set('retry max timeout', 2000); |
{ | ||
"name": "axon", | ||
"description": "High-level messaging & socket patterns implemented in pure js", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"author": "TJ Holowaychuk <tj@vision-media.ca>", | ||
@@ -6,0 +6,0 @@ "dependencies": { |
173
Readme.md
@@ -21,6 +21,4 @@ # Axon | ||
- pub / sub | ||
- req / rep | ||
- emitter | ||
- req / rep | ||
- router | ||
- dealer | ||
@@ -98,153 +96,138 @@ ## Push / Pull | ||
## EmitterSocket | ||
## Req / Rep | ||
`EmitterSocket`'s send and receive messages behaving like regular node `EventEmitter`s. | ||
This is achieved by using pub / sub sockets behind the scenes and automatically formatting | ||
messsages with the "json" codec. Currently we simply define the `EmitterSocket` as a `PubSocket` if you `.bind()`, and `SubSocket` if you `.connect()`, providing the natural API you're used to: | ||
`ReqSocket` is similar to a `PushSocket` in that it round-robins messages | ||
to connected `RepSocket`s, however it differs in that this communication is | ||
bi-directional, every `req.send()` _must_ provide a callback which is invoked | ||
when the `RepSocket` replies. | ||
server.js: | ||
```js | ||
var axon = require('axon') | ||
, sock = axon.socket('emitter'); | ||
, sock = axon.socket('req'); | ||
sock.bind(3000); | ||
console.log('pub server started'); | ||
req.bind(3000); | ||
setInterval(function(){ | ||
sock.emit('login', { name: 'tobi' }); | ||
}, 500); | ||
req.send(img, function(res){ | ||
}); | ||
``` | ||
client.js: | ||
`RepSocket`s receive a `reply` callback that is used to respond to the request, | ||
you may have several of these nodes. | ||
```js | ||
var axon = require('axon') | ||
, sock = axon.socket('emitter'); | ||
, sock = axon.socket('rep'); | ||
sock.connect(3000); | ||
console.log('sub client connected'); | ||
sock.on('login', function(user){ | ||
console.log('%s signed in', user.name); | ||
sock.on('message', function(img, reply){ | ||
// resize the image | ||
reply(img); | ||
}); | ||
``` | ||
## Req / Rep | ||
Like other sockets you may provide multiple arguments or an array of arguments, | ||
followed by the callbacks. For example here we provide a task name of "resize" | ||
to facilitate multiple tasks over a single socket: | ||
`ReqSocket`s send and recieve messages, queueing messages on remote disconnects. There | ||
is no "lock step" involved, allowing messages sent later to recieve replies prior to | ||
previously sent messages. `RepSocket`s reply to recieved messages, there is no concept of `send()`. Each | ||
recieved message will have a `reply` callback, which will send the response back to the remote peer: | ||
client.js | ||
```js | ||
var axon = require('../..') | ||
var axon = require('axon') | ||
, sock = axon.socket('req'); | ||
sock.connect(3000); | ||
req.bind(3000); | ||
sock.on('message', function(msg){ | ||
console.log('got: %s', msg.toString()); | ||
req.send('resize', img, function(res){ | ||
}); | ||
setInterval(function(){ | ||
sock.send('ping'); | ||
}, 150); | ||
``` | ||
server.js | ||
`RepSocket`s receive a `reply` callback that is used to respond to the request, | ||
you may have several of these nodes. | ||
```js | ||
var axon = require('../..') | ||
var axon = require('axon') | ||
, sock = axon.socket('rep'); | ||
sock.bind(3000); | ||
sock.connect(3000); | ||
sock.on('message', function(msg, reply){ | ||
console.log('got: %s', msg.toString()); | ||
reply('pong'); | ||
sock.on('message', function(task, img, reply){ | ||
switch (task.toString()) { | ||
case 'resize': | ||
// resize the image | ||
reply(img); | ||
break; | ||
} | ||
}); | ||
``` | ||
## Router | ||
## EmitterSocket | ||
`RouterSocket`s send a message to an "identified" peer using the socket's "identity" | ||
(see `socket options`). Sent messages are not queued. The message sent leverages | ||
multipart messages by framing the "identity" first, the delimiter second, and then | ||
the actual message body. | ||
`EmitterSocket`'s send and receive messages behaving like regular node `EventEmitter`s. | ||
This is achieved by using pub / sub sockets behind the scenes and automatically formatting | ||
messages with the "json" codec. Currently we simply define the `EmitterSocket` as a `PubSocket` if you `.bind()`, and `SubSocket` if you `.connect()`, providing the natural API you're used to: | ||
__Note:__ This will probably change due to the awkwardness of handling your own delimeters. | ||
server.js: | ||
client.js | ||
```js | ||
var axon = require('../..') | ||
, sock = axon.socket('router'); | ||
var axon = require('axon') | ||
, sock = axon.socket('emitter'); | ||
sock.bind(3000); | ||
console.log('pub server started'); | ||
sock.on('message', function(from, delim, msg){ | ||
console.log(msg.toString()); | ||
}); | ||
setInterval(function(){ | ||
sock.send('foo', '\u0000', 'hello foo'); | ||
sock.send('bar', '\u0000', 'hello bar'); | ||
}, 150); | ||
sock.emit('login', { name: 'tobi' }); | ||
}, 500); | ||
``` | ||
server.js | ||
client.js: | ||
```js | ||
var axon = require('../..') | ||
, foo = axon.socket('rep') | ||
, bar = axon.socket('rep'); | ||
var axon = require('axon') | ||
, sock = axon.socket('emitter'); | ||
foo.set('identity', 'foo'); | ||
foo.connect(3000); | ||
sock.connect(3000); | ||
console.log('sub client connected'); | ||
foo.on('message', function(msg, reply){ | ||
reply('foo: pong'); | ||
sock.on('login', function(user){ | ||
console.log('%s signed in', user.name); | ||
}); | ||
bar.set('identity', 'bar'); | ||
bar.connect(3000); | ||
bar.on('message', function(msg, reply){ | ||
reply('bar says: pong'); | ||
}); | ||
``` | ||
## Dealer | ||
## Req / Rep | ||
`DealerSocket`s receive messages and round-robin sent messages. There is no | ||
correlation between the two. They can be thought of as a `PushSocket` and `PullSocket` | ||
combined. Here the dealer the serves as an "echo-service", sending whatever is recieves: | ||
`ReqSocket`s send and receive messages, queueing messages on remote disconnects. There | ||
is no "lock step" involved, allowing messages sent later to receive replies prior to | ||
previously sent messages. `RepSocket`s reply to received messages, there is no concept of `send()`. Each | ||
received message will have a `reply` callback, which will send the response back to the remote peer: | ||
dealer.js | ||
client.js | ||
```js | ||
var axon = require('../..') | ||
, sock = axon.socket('dealer'); | ||
var axon = require('axon') | ||
, sock = axon.socket('req'); | ||
sock.set('identity', 'echo-service'); | ||
sock.connect(3000); | ||
sock.on('message', function(msg){ | ||
sock.send(msg); | ||
console.log('got: %s', msg.toString()); | ||
}); | ||
setInterval(function(){ | ||
sock.send('ping'); | ||
}, 150); | ||
``` | ||
client.js | ||
server.js | ||
```js | ||
var axon = require('../..') | ||
, sock = axon.socket('router'); | ||
var axon = require('axon') | ||
, sock = axon.socket('rep'); | ||
sock.bind(3000); | ||
sock.on('message', function(from, msg){ | ||
console.log('%s said: %s', from.toString(), msg.toString()); | ||
sock.on('message', function(msg, reply){ | ||
console.log('got: %s', msg.toString()); | ||
reply('pong'); | ||
}); | ||
setInterval(function(){ | ||
sock.send('echo-service', 'hey tobi'); | ||
}, 500); | ||
``` | ||
@@ -259,5 +242,5 @@ | ||
PubSockets additionaly have options for batching: | ||
PubSockets additionally have options for batching: | ||
- `batch max` - Max amount of messags to buffer in memory. | ||
- `batch max` - Max amount of messages to buffer in memory. | ||
- `batch ttl` - Amount of time to buffer messages before sending. | ||
@@ -317,3 +300,3 @@ | ||
axon cannot properly decode the messages. You may of course ignore this | ||
feature all together and simply paaxon encoded data to `.send()`. | ||
feature all together and simply pass encoded data to `.send()`. | ||
@@ -375,5 +358,3 @@ ## Performance | ||
- code cov | ||
- acks | ||
- weighted fair queuing | ||
- use mocha for tests | ||
- cap batch size | ||
@@ -380,0 +361,0 @@ - zero-copy for batches... |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
1
38053
23
1198
386