Comparing version 1.1.0 to 2.0.0
48
index.js
@@ -11,8 +11,11 @@ const c = require('compact-encoding') | ||
this.mux = mux | ||
this.name = null | ||
this.version = null | ||
this.messages = EMPTY | ||
this.context = null | ||
this.offset = 0 | ||
this.length = 0 | ||
this.opened = false | ||
this.corked = false | ||
@@ -25,3 +28,2 @@ this.remoteVersion = null | ||
this.onmessage = noop | ||
this.onremoteopen = noop | ||
@@ -31,3 +33,3 @@ this.onremoteclose = noop | ||
_attach ({ name, version = { major: 0, minor: 0 }, messages, onmessage = noop, onremoteopen = noop, onremoteclose = noop }) { | ||
_attach ({ name, version = { major: 0, minor: 0 }, messages = 0, context = null, onremoteopen = noop, onremoteclose = noop }) { | ||
const opened = this.opened | ||
@@ -37,9 +39,9 @@ | ||
this.version = version | ||
this.messages = messages | ||
this.messages = new Array(messages) | ||
this.context = context | ||
this.offset = this.mux.offset | ||
this.length = messages.length | ||
this.length = messages | ||
this.opened = true | ||
this.corked = false | ||
this.onmessage = onmessage | ||
this.onremoteopen = onremoteopen | ||
@@ -51,2 +53,23 @@ this.onremoteclose = onremoteclose | ||
_nextMessage () { | ||
for (let i = this.messages.length - 1; i >= 0; i--) { | ||
if (this.messages[i] === undefined && (i === 0 || this.messages[i - 1] !== undefined)) { | ||
return i | ||
} | ||
} | ||
return -1 | ||
} | ||
addMessage ({ type = this._nextMessage(), encoding = c.binary, onmessage = noop } = {}) { | ||
if (type < 0 || type >= this.messages.length) { | ||
throw new Error('Invalid type, must be <= ' + this.messages.length) | ||
} | ||
const t = this.offset + type | ||
const send = (message) => this.opened && this.mux._push(t, m.encoding, message) | ||
const m = this.messages[type] = { encoding, onmessage, send } | ||
return m | ||
} | ||
cork () { | ||
@@ -64,11 +87,2 @@ if (this.corked) return | ||
send (type, message) { | ||
if (!this.opened) return false | ||
const t = this.offset + type | ||
const m = this.messages[type] | ||
return this.mux._push(t, m, message) | ||
} | ||
close () { | ||
@@ -85,3 +99,3 @@ if (this.opened === false) return | ||
this.length = 0 | ||
this.onmessage = this.onremoteopen = this.onremoteclose = noop | ||
this.onremoteopen = this.onremoteclose = noop | ||
this.mux._push(2, c.uint, offset) | ||
@@ -102,5 +116,3 @@ this._gc() | ||
const m = this.messages[type] | ||
const message = m.decode(state) | ||
this.mux._catch(this.onmessage(type, message)) | ||
if (m !== undefined) this.mux._catch(m.onmessage(m.encoding.decode(state), this.context)) | ||
} | ||
@@ -107,0 +119,0 @@ } |
{ | ||
"name": "protomux", | ||
"version": "1.1.0", | ||
"version": "2.0.0", | ||
"description": "Multiplex multiple message oriented protocols over a stream", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -28,22 +28,33 @@ # protomux | ||
}, | ||
// an array of compact encoders, each encoding/decoding the messages sent | ||
messages: [ | ||
c.string, | ||
c.bool | ||
], | ||
messages: 2, // protocol has 2 messages | ||
onremoteopen () { | ||
console.log('the other side opened this protocol!') | ||
}, | ||
onemoteclose () { | ||
onremoteclose () { | ||
console.log('the other side closed this protocol!') | ||
}, | ||
onmessage (type, message) { | ||
console.log('the other side sent a message', type, message) | ||
} | ||
}) | ||
// And send some messages | ||
// And add some messages | ||
cool.send(0, 'a string') | ||
cool.send(1, true) | ||
const one = cool.addMessage({ | ||
type: 0, | ||
encoding: c.string, | ||
onmessage (m) { | ||
console.log('recv message (1)', m) | ||
} | ||
}) | ||
const two = cool.addMessage({ | ||
type: 1, | ||
encoding: c.bool, | ||
onmessage (m) { | ||
console.log('recv message (2)', m) | ||
} | ||
}) | ||
// And send some data | ||
one.send('a string') | ||
two.send(true) | ||
``` | ||
@@ -91,6 +102,4 @@ | ||
}, | ||
// Array of the message types you want to send/receive. Should be compact-encoders | ||
messages: [ | ||
... | ||
], | ||
// Number of messages types you want to send/receive. | ||
messages: 2, | ||
// Called when the remote side adds this protocol. | ||
@@ -101,6 +110,3 @@ // Errors here are caught and forwared to stream.destroy | ||
// Errors here are caught and forwared to stream.destroy | ||
async onremoteclose () {}, | ||
// Called when the remote sends a message | ||
// Errors here are caught and forwared to stream.destroy | ||
async onmessage (type, message) {} | ||
async onremoteclose () {} | ||
} | ||
@@ -111,10 +117,34 @@ ``` | ||
#### `p.close()` | ||
#### `const m = p.addMessage(opts)` | ||
Closes the protocol | ||
Specify a message. Options include: | ||
#### `p.send(type, message)` | ||
``` js | ||
{ | ||
// Defaults to an incrementing number | ||
type: numericIndex, | ||
// compact-encoding specifying how to encode/decode this message | ||
encoding: c.binary, | ||
// Called when the remote side sends a message. | ||
// Errors here are caught and forwared to stream.destroy | ||
async onmessage (message) { } | ||
} | ||
``` | ||
Send a message, type is the offset into the messages array. | ||
#### `m.send(data)` | ||
Send a message. | ||
#### `m.onmessage` | ||
Function that is called when a message arrives. | ||
#### `m.encoding` | ||
The encoding for this message. | ||
#### `p.close()` | ||
Closes the protocol. | ||
#### `p.cork()` | ||
@@ -121,0 +151,0 @@ |
130
test.js
@@ -12,10 +12,13 @@ const Protomux = require('./') | ||
a.addProtocol({ | ||
const p = a.addProtocol({ | ||
name: 'foo', | ||
messages: [c.string], | ||
messages: 1, | ||
onremoteopen () { | ||
t.pass('a remote opened') | ||
}, | ||
onmessage (type, message) { | ||
t.is(type, 0) | ||
} | ||
}) | ||
p.addMessage({ | ||
encoding: c.string, | ||
onmessage (message) { | ||
t.is(message, 'hello world') | ||
@@ -27,8 +30,8 @@ } | ||
name: 'foo', | ||
messages: [c.string] | ||
messages: 1 | ||
}) | ||
t.plan(3) | ||
t.plan(2) | ||
bp.send(0, 'hello world') | ||
bp.addMessage({ encoding: c.string }).send('hello world') | ||
}) | ||
@@ -38,11 +41,4 @@ | ||
const a = new Protomux(new SecretStream(true)) | ||
const b = new Protomux(new SecretStream(false)) | ||
const b = new Protomux(new SecretStream(false), [{ | ||
name: 'other', | ||
messages: [c.bool, c.bool] | ||
}, { | ||
name: 'foo', | ||
messages: [c.string] | ||
}]) | ||
replicate(a, b) | ||
@@ -52,5 +48,9 @@ | ||
name: 'foo', | ||
messages: [c.string], | ||
onmessage (type, message) { | ||
ap.send(type, 'echo: ' + message) | ||
messages: 1 | ||
}) | ||
const aEcho = ap.addMessage({ | ||
encoding: c.string, | ||
onmessage (message) { | ||
aEcho.send('echo: ' + message) | ||
} | ||
@@ -61,3 +61,3 @@ }) | ||
name: 'other', | ||
messages: [c.bool, c.bool] | ||
messages: 2 | ||
}) | ||
@@ -67,8 +67,11 @@ | ||
name: 'foo', | ||
messages: [c.string], | ||
messages: 1, | ||
onremoteopen () { | ||
t.pass('b remote opened') | ||
}, | ||
onmessage (type, message) { | ||
t.is(type, 0) | ||
} | ||
}) | ||
const bEcho = bp.addMessage({ | ||
encoding: c.string, | ||
onmessage (message) { | ||
t.is(message, 'echo: hello world') | ||
@@ -78,5 +81,5 @@ } | ||
t.plan(3) | ||
t.plan(2) | ||
bp.send(0, 'hello world') | ||
bEcho.send('hello world') | ||
}) | ||
@@ -89,3 +92,3 @@ | ||
name: 'other', | ||
messages: [c.bool, c.bool] | ||
messages: 2 | ||
}) | ||
@@ -95,5 +98,9 @@ | ||
name: 'multi', | ||
messages: [c.int, c.string, c.string] | ||
messages: 3 | ||
}) | ||
const a1 = ap.addMessage({ encoding: c.int }) | ||
const a2 = ap.addMessage({ encoding: c.string }) | ||
const a3 = ap.addMessage({ encoding: c.string }) | ||
const b = new Protomux(new SecretStream(false)) | ||
@@ -103,23 +110,28 @@ | ||
name: 'multi', | ||
messages: [c.int, c.string] | ||
messages: 2 | ||
}) | ||
const b1 = bp.addMessage({ encoding: c.int }) | ||
const b2 = bp.addMessage({ encoding: c.string }) | ||
replicate(a, b) | ||
t.plan(4) | ||
t.plan(2) | ||
ap.send(0, 42) | ||
ap.send(1, 'a string with 42') | ||
ap.send(2, 'should be ignored') | ||
a1.send(42) | ||
a2.send('a string with 42') | ||
a3.send('should be ignored') | ||
const expected = [ | ||
[0, 42], | ||
[1, 'a string with 42'] | ||
42, | ||
'a string with 42' | ||
] | ||
bp.onmessage = function (type, message) { | ||
const e = expected.shift() | ||
t.is(type, e[0]) | ||
t.is(message, e[1]) | ||
b1.onmessage = function (message) { | ||
t.is(message, expected.shift()) | ||
} | ||
b2.onmessage = function (message) { | ||
t.is(message, expected.shift()) | ||
} | ||
}) | ||
@@ -134,3 +146,3 @@ | ||
name: 'other', | ||
messages: [c.bool, c.bool] | ||
messages: 2 | ||
}) | ||
@@ -140,5 +152,8 @@ | ||
name: 'multi', | ||
messages: [c.int, c.string] | ||
messages: 2 | ||
}) | ||
const a1 = ap.addMessage({ encoding: c.int }) | ||
const a2 = ap.addMessage({ encoding: c.string }) | ||
const b = new Protomux(new SecretStream(false)) | ||
@@ -148,20 +163,23 @@ | ||
name: 'multi', | ||
messages: [c.int, c.string] | ||
messages: 2 | ||
}) | ||
const b1 = bp.addMessage({ encoding: c.int }) | ||
const b2 = bp.addMessage({ encoding: c.string }) | ||
replicate(a, b) | ||
t.plan(8 + 1) | ||
t.plan(4 + 1) | ||
const expected = [ | ||
[0, 1], | ||
[0, 2], | ||
[0, 3], | ||
[1, 'a string'] | ||
1, | ||
2, | ||
3, | ||
'a string' | ||
] | ||
ap.send(0, 1) | ||
ap.send(0, 2) | ||
ap.send(0, 3) | ||
ap.send(1, 'a string') | ||
a1.send(1) | ||
a1.send(2) | ||
a1.send(3) | ||
a2.send('a string') | ||
@@ -174,7 +192,9 @@ a.uncork() | ||
bp.onmessage = function (type, message) { | ||
const e = expected.shift() | ||
t.is(type, e[0]) | ||
t.is(message, e[1]) | ||
b1.onmessage = function (message) { | ||
t.is(message, expected.shift()) | ||
} | ||
b2.onmessage = function (message) { | ||
t.is(message, expected.shift()) | ||
} | ||
}) | ||
@@ -181,0 +201,0 @@ |
19773
508
165