|
'use strict'; |
|
|
|
var Transform = require('streamx').Transform; |
|
|
|
|
|
|
|
function toThrough(readable) { |
|
var highWaterMark = readable._readableState.highWaterMark; |
|
|
|
|
|
|
|
|
|
|
|
if (readable._readableState.objectMode) { |
|
highWaterMark = readable._readableState.highWaterMark * 1024; |
|
} |
|
|
|
var destroyedByError = false; |
|
var readableClosed = false; |
|
var readableEnded = false; |
|
|
|
function flush(cb) { |
|
var self = this; |
|
|
|
|
|
self._read = function (cb) { |
|
readable.resume(); |
|
cb(); |
|
}; |
|
|
|
readable.on('data', onData); |
|
readable.once('error', onError); |
|
readable.once('end', onEnd); |
|
|
|
function cleanup() { |
|
readable.off('data', onData); |
|
readable.off('error', onError); |
|
readable.off('end', onEnd); |
|
} |
|
|
|
function onData(data) { |
|
var drained = self.push(data); |
|
|
|
if (!drained) { |
|
readable.pause(); |
|
} |
|
} |
|
|
|
function onError(err) { |
|
cleanup(); |
|
cb(err); |
|
} |
|
|
|
function onEnd() { |
|
cleanup(); |
|
cb(); |
|
} |
|
} |
|
|
|
|
|
function predestroy() { |
|
|
|
|
|
if (destroyedByError) { |
|
return; |
|
} |
|
if (readableClosed) { |
|
return; |
|
} |
|
readable.destroy(new Error('Wrapper destroyed')); |
|
} |
|
|
|
var wrapper = new Transform({ |
|
highWaterMark: highWaterMark, |
|
flush: flush, |
|
predestroy: predestroy, |
|
}); |
|
|
|
|
|
readable.once('error', onError); |
|
readable.once('end', onEnd); |
|
readable.once('close', onClose); |
|
|
|
function onError(err) { |
|
destroyedByError = true; |
|
wrapper.destroy(err); |
|
} |
|
|
|
function onEnd() { |
|
readableEnded = true; |
|
} |
|
|
|
function onClose() { |
|
readableClosed = true; |
|
|
|
if (!readableEnded) { |
|
wrapper.destroy(); |
|
} |
|
} |
|
|
|
var shouldFlow = true; |
|
wrapper.once('pipe', onPipe); |
|
wrapper.on('piping', onPiping); |
|
wrapper.on('newListener', onListener); |
|
|
|
function onPiping() { |
|
maybeFlow(); |
|
wrapper.off('piping', onPiping); |
|
wrapper.off('newListener', onListener); |
|
} |
|
|
|
function onListener(event) { |
|
|
|
if (event === 'data' || event === 'readable') { |
|
onPiping(); |
|
} |
|
} |
|
|
|
function onPipe() { |
|
|
|
shouldFlow = false; |
|
} |
|
|
|
function maybeFlow() { |
|
|
|
if (shouldFlow) { |
|
wrapper.end(); |
|
} |
|
} |
|
|
|
return wrapper; |
|
} |
|
|
|
module.exports = toThrough; |
|
|