-
Notifications
You must be signed in to change notification settings - Fork 30.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
stream: add pipeline() for webstreams #46307
Changes from 5 commits
4d04a5e
06b8fff
08c333a
cb7de04
22ee747
2ec9a44
d1919d9
6c168d8
68c5c75
4eac7e3
4548998
86add31
78f0cf3
b5879c3
6190f6b
edfffa6
37df364
120c4fc
cd2a640
7d8414f
e3c139a
c1e0241
e37052b
d2fdac4
4ac3dc3
4c2c2eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,12 +35,22 @@ const { | |
isReadable, | ||
isReadableNodeStream, | ||
isNodeStream, | ||
isWritableStream, | ||
isTransformStream, | ||
isWebStream, | ||
} = require('internal/streams/utils'); | ||
const { AbortController } = require('internal/abort_controller'); | ||
|
||
let PassThrough; | ||
let Readable; | ||
|
||
function lazyloadReadable() { | ||
if (!Readable) { | ||
Readable = require('internal/streams/readable'); | ||
} | ||
return Readable; | ||
} | ||
|
||
function destroyer(stream, reading, writing) { | ||
let finished = false; | ||
stream.on('close', () => { | ||
|
@@ -81,17 +91,17 @@ function makeAsyncIterable(val) { | |
} | ||
|
||
async function* fromReadable(val) { | ||
if (!Readable) { | ||
Readable = require('internal/streams/readable'); | ||
} | ||
|
||
yield* Readable.prototype[SymbolAsyncIterator].call(val); | ||
yield* lazyloadReadable().prototype[SymbolAsyncIterator].call(val); | ||
} | ||
|
||
async function pump(iterable, writable, finish, { end }) { | ||
let error; | ||
let onresolve = null; | ||
|
||
if (isTransformStream(writable)) { | ||
writable = writable.writable; | ||
} | ||
|
||
const resume = (err) => { | ||
if (err) { | ||
error = err; | ||
|
@@ -118,22 +128,34 @@ async function pump(iterable, writable, finish, { end }) { | |
} | ||
}); | ||
|
||
writable.on('drain', resume); | ||
if (typeof writable.on === 'function') { | ||
writable.on('drain', resume); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is for node streams... not web streams |
||
} | ||
const cleanup = eos(writable, { readable: false }, resume); | ||
|
||
try { | ||
if (writable.writableNeedDrain) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is for node streams... not web streams |
||
await wait(); | ||
} | ||
|
||
let writer = writable; | ||
let endFn = () => {}; | ||
if (isWritableStream(writable)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this always be true here? |
||
writer = writable.getWriter(); | ||
endFn = writer.close.bind(writer); | ||
} else { | ||
endFn = writer.end.bind(writer); | ||
} | ||
|
||
for await (const chunk of iterable) { | ||
if (!writable.write(chunk)) { | ||
const written = writer.write(chunk); | ||
if (!written) { | ||
await wait(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How and when does this wait resume? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm yes this part is wrong writer.write will be promise |
||
} | ||
} | ||
|
||
if (end) { | ||
writable.end(); | ||
endFn(); | ||
} | ||
|
||
await wait(); | ||
debadree25 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
@@ -143,7 +165,9 @@ async function pump(iterable, writable, finish, { end }) { | |
finish(error !== err ? aggregateTwoErrors(error, err) : err); | ||
} finally { | ||
cleanup(); | ||
writable.off('drain', resume); | ||
if (typeof writable.off === 'function') { | ||
writable.off('drain', resume); | ||
} | ||
} | ||
} | ||
|
||
|
@@ -259,8 +283,13 @@ function pipelineImpl(streams, callback, opts) { | |
ret = Duplex.from(stream); | ||
} | ||
} else if (typeof stream === 'function') { | ||
ret = makeAsyncIterable(ret); | ||
ret = stream(ret, { signal }); | ||
if (isTransformStream(ret)) { | ||
ret = makeAsyncIterable(ret?.readable); | ||
ret = stream(ret, { signal }); | ||
} else { | ||
ret = makeAsyncIterable(ret); | ||
ret = stream(ret, { signal }); | ||
} | ||
|
||
if (reading) { | ||
if (!isIterable(ret, true)) { | ||
|
@@ -327,6 +356,23 @@ function pipelineImpl(streams, callback, opts) { | |
} else if (isIterable(ret)) { | ||
finishCount++; | ||
pump(ret, stream, finish, { end }); | ||
} else if (isTransformStream(ret)) { | ||
finishCount++; | ||
pump(ret.readable, stream, finish, { end }); | ||
} else { | ||
throw new ERR_INVALID_ARG_TYPE( | ||
'val', ['Readable', 'Iterable', 'AsyncIterable'], ret); | ||
} | ||
ret = stream; | ||
} else if (isWebStream(stream)) { | ||
if (isReadableNodeStream(ret)) { | ||
finishCount += 2; | ||
pipeNodeToWeb(ret, stream, finish, { end }); | ||
debadree25 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} else if (isIterable(ret)) { | ||
finishCount++; | ||
pump(ret, stream, finish, { end }); | ||
} else if (isTransformStream(ret)) { | ||
pump(ret.readable, stream, finish, { end }); | ||
} else { | ||
throw new ERR_INVALID_ARG_TYPE( | ||
'val', ['Readable', 'Iterable', 'AsyncIterable'], ret); | ||
|
@@ -392,4 +438,39 @@ function pipe(src, dst, finish, { end }) { | |
return eos(dst, { readable: false, writable: true }, finish); | ||
} | ||
|
||
function pipeNodeToWeb(src, dst, finish, { end }) { | ||
let writable = dst; | ||
if (isTransformStream(dst)) { | ||
writable = dst.writable; | ||
} | ||
const writer = writable.getWriter(); | ||
|
||
src.on('data', (chunk) => { | ||
writer.write(chunk); | ||
}); | ||
|
||
if (end) { | ||
src.once('end', () => { | ||
writer.close(); | ||
}); | ||
} else { | ||
finish(); | ||
} | ||
eos(src, { readable: true, writable: false }, (err) => { | ||
const rState = src._readableState; | ||
if ( | ||
err && | ||
err.code === 'ERR_STREAM_PREMATURE_CLOSE' && | ||
(rState && rState.ended && !rState.errored && !rState.errorEmitted) | ||
) { | ||
src | ||
.once('end', finish) | ||
.once('error', finish); | ||
} else { | ||
finish(err); | ||
} | ||
}); | ||
return eos(writable, finish); | ||
} | ||
|
||
module.exports = { pipelineImpl, pipeline }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok reverting this