mirror of
https://github.com/nodejs/node.git
synced 2025-05-08 18:14:08 +00:00

Make the callback mandatory as mostly done in all other Node.js callback APIs so users explicitly have to decide what to do in error cases. This also documents the options for `Stream.finished()`. When originally implemented it was missed that Stream.finished() has an optional options object. PR-URL: https://github.com/nodejs/node/pull/21058 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Mathias Buus <mathiasbuus@gmail.com>
105 lines
2.7 KiB
JavaScript
105 lines
2.7 KiB
JavaScript
// Ported from https://github.com/mafintosh/end-of-stream with
|
|
// permission from the author, Mathias Buus (@mafintosh).
|
|
|
|
'use strict';
|
|
|
|
const {
|
|
ERR_INVALID_ARG_TYPE,
|
|
ERR_STREAM_PREMATURE_CLOSE
|
|
} = require('internal/errors').codes;
|
|
|
|
function isRequest(stream) {
|
|
return stream.setHeader && typeof stream.abort === 'function';
|
|
}
|
|
|
|
function once(callback) {
|
|
let called = false;
|
|
return function(err) {
|
|
if (called) return;
|
|
called = true;
|
|
callback.call(this, err);
|
|
};
|
|
}
|
|
|
|
function eos(stream, opts, callback) {
|
|
if (arguments.length === 2) {
|
|
callback = opts;
|
|
opts = {};
|
|
} else if (opts == null) {
|
|
opts = {};
|
|
} else if (typeof opts !== 'object') {
|
|
throw new ERR_INVALID_ARG_TYPE('opts', 'object', opts);
|
|
}
|
|
if (typeof callback !== 'function') {
|
|
throw new ERR_INVALID_ARG_TYPE('callback', 'function', callback);
|
|
}
|
|
|
|
callback = once(callback);
|
|
|
|
const ws = stream._writableState;
|
|
const rs = stream._readableState;
|
|
let readable = opts.readable || (opts.readable !== false && stream.readable);
|
|
let writable = opts.writable || (opts.writable !== false && stream.writable);
|
|
|
|
const onlegacyfinish = () => {
|
|
if (!stream.writable) onfinish();
|
|
};
|
|
|
|
const onfinish = () => {
|
|
writable = false;
|
|
if (!readable) callback.call(stream);
|
|
};
|
|
|
|
const onend = () => {
|
|
readable = false;
|
|
if (!writable) callback.call(stream);
|
|
};
|
|
|
|
const onerror = (err) => {
|
|
callback.call(stream, err);
|
|
};
|
|
|
|
const onclose = () => {
|
|
if (readable && !(rs && rs.ended)) {
|
|
return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE());
|
|
}
|
|
if (writable && !(ws && ws.ended)) {
|
|
return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE());
|
|
}
|
|
};
|
|
|
|
const onrequest = () => {
|
|
stream.req.on('finish', onfinish);
|
|
};
|
|
|
|
if (isRequest(stream)) {
|
|
stream.on('complete', onfinish);
|
|
stream.on('abort', onclose);
|
|
if (stream.req) onrequest();
|
|
else stream.on('request', onrequest);
|
|
} else if (writable && !ws) { // legacy streams
|
|
stream.on('end', onlegacyfinish);
|
|
stream.on('close', onlegacyfinish);
|
|
}
|
|
|
|
stream.on('end', onend);
|
|
stream.on('finish', onfinish);
|
|
if (opts.error !== false) stream.on('error', onerror);
|
|
stream.on('close', onclose);
|
|
|
|
return function() {
|
|
stream.removeListener('complete', onfinish);
|
|
stream.removeListener('abort', onclose);
|
|
stream.removeListener('request', onrequest);
|
|
if (stream.req) stream.req.removeListener('finish', onfinish);
|
|
stream.removeListener('end', onlegacyfinish);
|
|
stream.removeListener('close', onlegacyfinish);
|
|
stream.removeListener('finish', onfinish);
|
|
stream.removeListener('end', onend);
|
|
stream.removeListener('error', onerror);
|
|
stream.removeListener('close', onclose);
|
|
};
|
|
}
|
|
|
|
module.exports = eos;
|