stream-flow-control
Version:
Stream Flow Control
114 lines (99 loc) • 3.37 kB
JavaScript
const {Readable} = require('stream');
const {Manager} = require('../manager/manager.js');
const uuid = require('uuid');
const {DataWrapper} = require('../wrapper/data_wrapper.js')
/**
* Join messages from multiple sources into a single messages. If no method is overwitten, then releases a message when there is exactly one message from each source.
*
* @extends Readable
*/
class FlowJoin extends Readable {
/**
* Create a FlowJoin stream
* @param {object} options Global options.
* @param {string} [options.name] Name for this stream.
* @param {Process} [options.join] How messages are joined.
*/
constructor(options) {
options = {...options, objectMode: true};
super(options);
this.options = options;
this._sources = {};
this._payloads = [];
this._readableState.sync = false;
this.type = 'FlowJoin';
if(this.options.name) Manager.set(this.type, this);
if(this.options.join && typeof this.options.join == 'function') this._join = this.options.join;
this.on('pipe', (src)=>{
const id = this.goal || (src.options && src.options.name)?src.options.name:uuid.v4();
if(src.options && src.options.port) {
id += '/'+src.options.port;
}
this._sources[id] = src;
src.on('data', (data)=>{
//console.log('hay data');
this._join({
id,
data
});
});
//src.on('end', () => this.end(src));
this.on('pause', ()=>{
src.pause();
});
this.on('resume', ()=>{
src.resume();
});
});
}
// none(dst) {
// if(!this._none_reader) {
// this._none_reader = new Readable({
// objectMode: true,
// read() {}
// });
// this._none_reader._readableState.sync = false;
// }
// const pipes = Array.isArray(dst)?dst:[dst];
// pipes.forEach(dst=>this._none_reader.pipe(dst));
// return Array.isArray(dst)?this:dst;
// }
_join(data) {
var found = false;
var doSend = false;
for(let i = 0; i < this._payloads.length; i++) {
let payload = this._payloads[i];
if(payload.hasOwnProperty(data.id)) continue;
found=true;
payload[data.id] = data.data;
doSend = Object.keys(payload).length == Object.keys(this._sources).length;
break;
}
if(doSend) {
let payload = this._payloads.shift();
if(this.goal) {
// Is goal player
payload = new DataWrapper(null, this).setParents(payload);
}
if(!this.push(payload)) this.pause();
return;
}
if(!found) {
let payload = {};
payload[data.id] = data.data;
this._payloads.push(payload);
}
}
_read() {
this.resume();
}
write(payload) {
}
end(src) {
for(let i in this._sources) {
if(!this._sources[i]._readableState.ended) return;
}
this.push(null);
}
}
module.exports.FlowJoin = FlowJoin;