stream-flow-control
Version:
Stream Flow Control
111 lines (97 loc) • 3.5 kB
JavaScript
const {Readable} = require('stream');
const {Manager} = require('../manager/manager.js');
const uuid = require('uuid');
const {DataWrapper} = require('../wrapper/data_wrapper.js')
/**
* Hold flow from multiple source streams until a condition is met. If no method is overwitten, then holds flow until end is signaled on all sources.
*
* @extends Readable
*/
class FlowHold extends Readable {
/**
* Create a FlowHold stream
* @param {object} options Global options.
* @param {string} [options.name] Name for this stream.
* @param {Process} [options.hold] How messages are stored.
* @param {function} [options.check] Checks a certain condition is met and call _options.release_.
* @param {function} [options.release] Controls how messages are released.
*/
constructor(options) {
options = {...options, objectMode: true};
super(options);
this.options = options;
/** @property Source streams */
this._sources = {};
/** @property Stored messages. There is an array for each source */
this._payloads = {};
this._parents = [];
this._readableState.sync = false;
this.type = 'FlowHold';
if(this.options.name) Manager.set(this.type, this);
if(this.options.hold && typeof this.options.hold == 'function') this._hold = this.options.hold;
if(this.options.release && typeof this.options.release == 'function') this._release = this.options.release;
if(this.options.check && typeof this.options.check == 'function') this._check = this.options.check;
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, ended: false};
src.on('data', (data)=>{
//console.log('hay data');
if(this.goal) {
// Is goal player
this._parents.push(data);
}
this._hold({
id,
data
});
});
src.on('end', () => {
this._sources[id].ended = true;
this._check();
});
this.on('pause', ()=>{
src.pause();
});
this.on('resume', ()=>{
src.resume();
});
});
}
_hold(payload) {
if(!this._payloads[payload.id]) this._payloads[payload.id] = [];
if(this.goal) {
// Is goal player
// means payload.data is a DataWrapper
payload.data = payload.data.data;
}
this._payloads[payload.id].push(payload.data);
}
_check() {
for(let i in this._sources) {
if(!this._sources[i].ended) return;
}
this._release();
}
_release() {
let payload = this._payloads;
if(Object.keys(payload).length === 1) {
for(let i in payload) {
payload = payload[i];
}
}
if(this.goal) {
// Is goal player
payload = new DataWrapper(null, this).setParents(this._parents, payload);
}
this.push(payload);
this.push(null);
}
write(payload) {
}
end() {}
_read() {}
}
module.exports.FlowHold = FlowHold;