Skip to content

Commit f217025

Browse files
committed
stream: add errored and closed props
PR-URL: #40696 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 3e5a5e8 commit f217025

10 files changed

+112
-15
lines changed

doc/api/stream.md

+43-1
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,16 @@ further errors except from `_destroy()` may be emitted as `'error'`.
456456
Implementors should not override this method,
457457
but instead implement [`writable._destroy()`][writable-_destroy].
458458

459+
##### `writable.closed`
460+
461+
<!-- YAML
462+
added: REPLACEME
463+
-->
464+
465+
* {boolean}
466+
467+
Is `true` after `'close'` has been emitted.
468+
459469
##### `writable.destroyed`
460470

461471
<!-- YAML
@@ -611,6 +621,17 @@ added:
611621
Number of times [`writable.uncork()`][stream-uncork] needs to be
612622
called in order to fully uncork the stream.
613623

624+
##### `writable.writableErrored`
625+
626+
<!-- YAML
627+
added:
628+
REPLACEME
629+
-->
630+
631+
* {Error}
632+
633+
Returns error if the stream has been destroyed with an error.
634+
614635
##### `writable.writableFinished`
615636

616637
<!-- YAML
@@ -1080,14 +1101,24 @@ further errors except from `_destroy()` may be emitted as `'error'`.
10801101
Implementors should not override this method, but instead implement
10811102
[`readable._destroy()`][readable-_destroy].
10821103

1083-
##### `readable.destroyed`
1104+
##### `readable.closed`
10841105

10851106
<!-- YAML
10861107
added: v8.0.0
10871108
-->
10881109

10891110
* {boolean}
10901111

1112+
Is `true` after `'close'` has been emitted.
1113+
1114+
##### `readable.destroyed`
1115+
1116+
<!-- YAML
1117+
added: REPLACEME
1118+
-->
1119+
1120+
* {boolean}
1121+
10911122
Is `true` after [`readable.destroy()`][readable-destroy] has been called.
10921123

10931124
##### `readable.isPaused()`
@@ -1346,6 +1377,17 @@ added: v12.9.0
13461377

13471378
Becomes `true` when [`'end'`][] event is emitted.
13481379

1380+
##### `readable.readableErrored`
1381+
1382+
<!-- YAML
1383+
added:
1384+
REPLACEME
1385+
-->
1386+
1387+
* {Error}
1388+
1389+
Returns error if the stream has been destroyed with an error.
1390+
13491391
##### `readable.readableFlowing`
13501392

13511393
<!-- YAML

lib/internal/fs/streams.js

-6
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,9 @@ const FileHandleOperations = (handle) => {
107107

108108
function close(stream, err, cb) {
109109
if (!stream.fd) {
110-
// TODO(ronag)
111-
// stream.closed = true;
112110
cb(err);
113111
} else {
114112
stream[kFs].close(stream.fd, (er) => {
115-
stream.closed = true;
116113
cb(er || err);
117114
});
118115
stream.fd = null;
@@ -186,7 +183,6 @@ function ReadStream(path, options) {
186183
this.end = options.end;
187184
this.pos = undefined;
188185
this.bytesRead = 0;
189-
this.closed = false;
190186
this[kIsPerformingIO] = false;
191187

192188
if (this.start !== undefined) {
@@ -358,10 +354,8 @@ function WriteStream(path, options) {
358354
this.start = options.start;
359355
this.pos = undefined;
360356
this.bytesWritten = 0;
361-
this.closed = false;
362357
this[kIsPerformingIO] = false;
363358

364-
365359
if (this.start !== undefined) {
366360
validateInteger(this.start, 'start', 0);
367361

lib/internal/streams/end-of-stream.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ const {
2222
isReadable,
2323
isReadableNodeStream,
2424
isReadableFinished,
25+
isReadableErrored,
2526
isWritable,
2627
isWritableNodeStream,
2728
isWritableFinished,
29+
isWritableErrored,
2830
isNodeStream,
2931
willEmitClose: _willEmitClose,
3032
} = require('internal/streams/utils');
@@ -110,7 +112,7 @@ function eos(stream, options, callback) {
110112
const onclose = () => {
111113
closed = true;
112114

113-
const errored = wState?.errored || rState?.errored;
115+
const errored = isWritableErrored(stream) || isReadableErrored(stream);
114116

115117
if (errored && typeof errored !== 'boolean') {
116118
return callback.call(stream, errored);

lib/internal/streams/readable.js

+14-4
Original file line numberDiff line numberDiff line change
@@ -1239,13 +1239,23 @@ ObjectDefineProperties(Readable.prototype, {
12391239
}
12401240
},
12411241

1242+
readableErrored: {
1243+
enumerable: false,
1244+
get() {
1245+
return this._readableState ? this._readableState.errored : null;
1246+
}
1247+
},
1248+
1249+
closed: {
1250+
get() {
1251+
return this._readableState ? this._readableState.closed : false;
1252+
}
1253+
},
1254+
12421255
destroyed: {
12431256
enumerable: false,
12441257
get() {
1245-
if (this._readableState === undefined) {
1246-
return false;
1247-
}
1248-
return this._readableState.destroyed;
1258+
return this._readableState ? this._readableState.destroyed : false;
12491259
},
12501260
set(value) {
12511261
// We ignore the value if the stream

lib/internal/streams/utils.js

+30
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,39 @@ function isFinished(stream, opts) {
144144
return true;
145145
}
146146

147+
function isWritableErrored(stream) {
148+
if (!isNodeStream(stream)) {
149+
return null;
150+
}
151+
152+
if (stream.writableErrored) {
153+
return stream.writableErrored;
154+
}
155+
156+
return stream._writableState?.errored ?? null;
157+
}
158+
159+
function isReadableErrored(stream) {
160+
if (!isNodeStream(stream)) {
161+
return null;
162+
}
163+
164+
if (stream.readableErrored) {
165+
return stream.readableErrored;
166+
}
167+
168+
return stream._readableState?.errored ?? null;
169+
}
170+
147171
function isClosed(stream) {
148172
if (!isNodeStream(stream)) {
149173
return null;
150174
}
151175

176+
if (typeof stream.closed === 'boolean') {
177+
return stream.closed;
178+
}
179+
152180
const wState = stream._writableState;
153181
const rState = stream._readableState;
154182

@@ -226,11 +254,13 @@ module.exports = {
226254
isReadableNodeStream,
227255
isReadableEnded,
228256
isReadableFinished,
257+
isReadableErrored,
229258
isNodeStream,
230259
isWritable,
231260
isWritableNodeStream,
232261
isWritableEnded,
233262
isWritableFinished,
263+
isWritableErrored,
234264
isServerRequest,
235265
isServerResponse,
236266
willEmitClose,

lib/internal/streams/writable.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,12 @@ function finish(stream, state) {
768768

769769
ObjectDefineProperties(Writable.prototype, {
770770

771+
closed: {
772+
get() {
773+
return this._writableState ? this._writableState.closed : false;
774+
}
775+
},
776+
771777
destroyed: {
772778
get() {
773779
return this._writableState ? this._writableState.destroyed : false;
@@ -846,7 +852,14 @@ ObjectDefineProperties(Writable.prototype, {
846852
get() {
847853
return this._writableState && this._writableState.length;
848854
}
849-
}
855+
},
856+
857+
writableErrored: {
858+
enumerable: false,
859+
get() {
860+
return this._writableState ? this._writableState.errored : null;
861+
}
862+
},
850863
});
851864

852865
const destroy = destroyImpl.destroy;

test/parallel/test-fs-read-stream-inherit.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ const rangeFile = fixtures.path('x.txt');
199199
file.on('error', common.mustCall());
200200

201201
process.on('exit', function() {
202-
assert(!file.closed);
202+
assert(file.closed);
203203
assert(file.destroyed);
204204
});
205205
}

test/parallel/test-fs-read-stream.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ if (!common.isWindows) {
271271
file.on('error', common.mustCall());
272272

273273
process.on('exit', function() {
274-
assert(!file.closed);
274+
assert(file.closed);
275275
assert(file.destroyed);
276276
});
277277
}

test/parallel/test-stream-finished.js

+4
Original file line numberDiff line numberDiff line change
@@ -612,8 +612,10 @@ testClosed((opts) => new Writable({ write() {}, ...opts }));
612612
const w = new Writable();
613613
const _err = new Error();
614614
w.destroy(_err);
615+
assert.strictEqual(w.writableErrored, _err);
615616
finished(w, common.mustCall((err) => {
616617
assert.strictEqual(_err, err);
618+
assert.strictEqual(w.closed, true);
617619
finished(w, common.mustCall((err) => {
618620
assert.strictEqual(_err, err);
619621
}));
@@ -623,7 +625,9 @@ testClosed((opts) => new Writable({ write() {}, ...opts }));
623625
{
624626
const w = new Writable();
625627
w.destroy();
628+
assert.strictEqual(w.writableErrored, null);
626629
finished(w, common.mustCall((err) => {
630+
assert.strictEqual(w.closed, true);
627631
assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE');
628632
finished(w, common.mustCall((err) => {
629633
assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE');

test/parallel/test-stream-readable-destroy.js

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const assert = require('assert');
1313
read.on('close', common.mustCall());
1414

1515
read.destroy();
16+
assert.strictEqual(read.readableErrored, null);
1617
assert.strictEqual(read.destroyed, true);
1718
}
1819

@@ -31,6 +32,7 @@ const assert = require('assert');
3132
}));
3233

3334
read.destroy(expected);
35+
assert.strictEqual(read.readableErrored, expected);
3436
assert.strictEqual(read.destroyed, true);
3537
}
3638

0 commit comments

Comments
 (0)