Repository navigation
stream: implement finished() for ReadableStream and WritableStream #46205
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
Changes from 1 commit
fd2fa5a
7938b4a
f0b8c92
3937b22
70630b3
2d7ea18
b6461d9
1572862
ebeab98
dd5391b
9aadb9e
e924b60
f1cbaea
5ae4f8a
4ab3a7b
f1ef9e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
Refs: #39316
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,7 +22,7 @@ const { | |
| validateBoolean | ||
| } = require('internal/validators'); | ||
|
|
||
| const { Promise } = primordials; | ||
| const { Promise, PromisePrototypeThen } = primordials; | ||
|
|
||
| const { | ||
| isClosed, | ||
|
|
@@ -38,6 +38,15 @@ const { | |
| willEmitClose: _willEmitClose, | ||
| } = require('internal/streams/utils'); | ||
|
|
||
| const { | ||
| isBrandCheck, | ||
| } = require('internal/webstreams/util'); | ||
|
|
||
| const isReadableStream = | ||
|
ronag marked this conversation as resolved.
Outdated
|
||
| isBrandCheck('ReadableStream'); | ||
| const isWritableStream = | ||
| isBrandCheck('WritableStream'); | ||
|
Member
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. I don't think we can use isBrandCheck due to
Contributor
Author
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. any alternatives? I had tried importing isReadableStream from
Member
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. Check for expected signature? For example check for pipeThrough.
Contributor
Author
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. Done removed the brandchecks based checking |
||
|
|
||
| function isRequest(stream) { | ||
| return stream.setHeader && typeof stream.abort === 'function'; | ||
| } | ||
|
|
@@ -62,8 +71,7 @@ function eos(stream, options, callback) { | |
| const writable = options.writable ?? isWritableNodeStream(stream); | ||
|
|
||
| if (!isNodeStream(stream)) { | ||
|
ronag marked this conversation as resolved.
Outdated
|
||
| // TODO: Webstreams. | ||
| throw new ERR_INVALID_ARG_TYPE('stream', 'Stream', stream); | ||
| return eosWeb(stream, options, callback); | ||
| } | ||
|
|
||
| const wState = stream._writableState; | ||
|
|
@@ -255,6 +263,15 @@ function eos(stream, options, callback) { | |
| return cleanup; | ||
| } | ||
|
|
||
| function eosWeb(stream, opts, callback) { | ||
|
RaisinTen marked this conversation as resolved.
Outdated
|
||
| PromisePrototypeThen( | ||
| stream.streamClosed, | ||
| () => callback.call(stream), | ||
| (err) => callback.call(stream, err) | ||
| ); | ||
| return nop; | ||
| } | ||
|
|
||
| function finished(stream, opts) { | ||
| let autoCleanup = false; | ||
| if (opts === null) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -231,7 +231,8 @@ class ReadableStream { | |
| port1: undefined, | ||
| port2: undefined, | ||
| promise: undefined, | ||
| } | ||
| }, | ||
| streamClosed: createDeferredPromise(), | ||
|
ronag marked this conversation as resolved.
Outdated
|
||
| }; | ||
|
|
||
| // The spec requires handling of the strategy first | ||
|
|
@@ -288,6 +289,12 @@ class ReadableStream { | |
| return isReadableStreamLocked(this); | ||
| } | ||
|
|
||
| get streamClosed() { | ||
| if (!isReadableStream(this)) | ||
| throw new ERR_INVALID_THIS('ReadableStream'); | ||
| return this[kState].streamClosed.promise; | ||
| } | ||
|
|
||
|
Member
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. You can't add new public properties to web streams. That is not allowed by the spec.
Contributor
Author
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. ok updating this to private access?
Contributor
Author
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. Have updated to access using [kState] |
||
| /** | ||
| * @param {any} [reason] | ||
| * @returns { Promise<void> } | ||
|
|
@@ -1869,6 +1876,7 @@ function readableStreamCancel(stream, reason) { | |
| function readableStreamClose(stream) { | ||
| assert(stream[kState].state === 'readable'); | ||
| stream[kState].state = 'closed'; | ||
| stream[kState].streamClosed?.resolve?.(); | ||
|
Member
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. Can streamClosed be nully?
Contributor
Author
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. I think it can because initially when I tested without null checks it failed
Member
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. Then I think there might be a bug somewhere. What does it mean when it's nully?
Contributor
Author
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. Okay trying to investigate
Contributor
Author
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. Fixed this, removed the null checks basically it was breaking tests where tee() was being used to construct streams |
||
|
|
||
| const { | ||
| reader, | ||
|
|
@@ -1900,6 +1908,10 @@ function readableStreamError(stream, error) { | |
|
|
||
| reader[kState].close.reject(error); | ||
| setPromiseHandled(reader[kState].close.promise); | ||
| if (stream[kState].streamClosed?.promise !== undefined) { | ||
| stream[kState].streamClosed?.reject?.(error); | ||
| setPromiseHandled(stream[kState].streamClosed?.promise); | ||
| } | ||
|
|
||
| if (readableStreamHasDefaultReader(stream)) { | ||
| for (let n = 0; n < reader[kState].readRequests.length; n++) | ||
|
|
||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| 'use strict'; | ||
|
|
||
| const common = require('../common'); | ||
| const assert = require('assert'); | ||
| const { ReadableStream, WritableStream } = require('stream/web'); | ||
| const { finished } = require('stream'); | ||
|
|
||
| { | ||
| const rs = new ReadableStream({ | ||
| start(controller) { | ||
| controller.enqueue('asd'); | ||
| controller.close(); | ||
| }, | ||
| }); | ||
| finished(rs, common.mustSucceed()); | ||
| async function test() { | ||
| const values = []; | ||
| for await (const chunk of rs) { | ||
| values.push(chunk); | ||
| } | ||
| assert.deepStrictEqual(values, ['asd']); | ||
| } | ||
| test(); | ||
| } | ||
|
|
||
| { | ||
| let str = ''; | ||
| const ws = new WritableStream({ | ||
| write(chunk) { | ||
| console.log(chunk); | ||
| str += chunk; | ||
| } | ||
| }); | ||
| finished(ws, common.mustSucceed(() => { | ||
| assert.strictEqual(str, 'asd'); | ||
| })); | ||
| const writer = ws.getWriter(); | ||
| writer.write('asd'); | ||
| writer.close(); | ||
| } |
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.
Unfortunately, this will break
readable-streamI think you need to inverse the dependency and have webstream require symbols from stream.FYI @mcollina
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.
As in having the symbols defined in
internal/streams/utiland webstreams requiring from there?Uh oh!
There was an error while loading. Please reload this page.
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.
Exactly.
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.
Actually, we might even need to use a
SymbolFor('nodejs.webstream.closed'). Similar to #45671.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 so would try to do the following, define
SymbolFor('nodejs.webstream.closed')ininternal/streams/utiland use that instead of storing closed in the kState?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.
Have implemented this could you check?