conduit
Version:
Evented pipelines.
69 lines (59 loc) • 2.2 kB
JavaScript
// Control-flow utilities.
var cadence = require('cadence')
// An evented message queue.
var Procession = require('procession')
var assert = require('assert')
var Destructible = require('destructible')
function Multiplexer (routes) {
this.outbox = new Procession
this.inbox = new Procession
this.conduits = {}
this._eos = 0
}
// Note that our pumps are not going to error because they are nothing more than
// copies. We still use `Destructible` to signal that we're coming to a close,
// but we don't cancel the pumps. We wait for the end-of-stream.
//
Multiplexer.prototype._monitor = cadence(function (async, destructible, routes) {
async(function () {
this.inbox.pump(this, '_dispatch').run(destructible.durable('dispatch'))
async.forEach([ Object.keys(routes) ], function (qualifier) {
var receiver = this.conduits[qualifier] = routes[qualifier]
receiver.outbox.pump(this, function (envelope) {
this._envelop(qualifier, envelope)
}).run(destructible.durable([ 'receiver', 'envelop', qualifier ]))
})
}, function () {
return [ this ]
})
})
Multiplexer.prototype._dispatch = cadence(function (async, envelope) {
if (envelope == null) {
async.forEach([ Object.keys(this.conduits) ], function (qualifier) {
this.conduits[qualifier].inbox.enqueue(null, async())
})
} else if (
envelope.module == 'conduit/multiplexer' &&
envelope.method == 'envelope' &&
this.conduits[envelope.qualifier] != null
) {
this.conduits[envelope.qualifier].inbox.enqueue(envelope.body, async())
}
})
Multiplexer.prototype._envelop = function (qualifier, envelope) {
if (envelope == null) {
if (++this._eos === Object.keys(this.conduits).length) {
this.outbox.push(null)
}
} else {
this.outbox.push({
module: 'conduit/multiplexer',
method: 'envelope',
qualifier: qualifier,
body: envelope
})
}
}
module.exports = cadence(function (async, destructible, routes) {
new Multiplexer()._monitor(destructible, routes, async())
})