@promistream/from-node-stream 0.1.8 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/src/index.js +21 -2
- package/test.js +77 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@promistream/from-node-stream",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"main": "src/index.js",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"@promistream/parallelize": "^0.1.10",
|
|
34
34
|
"@promistream/pipe": "^0.1.8",
|
|
35
35
|
"@promistream/range-numbers": "^0.1.2",
|
|
36
|
+
"@promistream/spy": "^0.1.0",
|
|
36
37
|
"@promistream/test-abort": "^0.1.0",
|
|
37
38
|
"bluebird": "^3.7.2",
|
|
38
39
|
"p-defer": "^4.0.1",
|
package/src/index.js
CHANGED
|
@@ -123,11 +123,26 @@ function isWritableStreamEnded(stream) {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
function wireWritable(debug, stream) {
|
|
126
|
-
let errorEncountered;
|
|
126
|
+
let errorEncountered, lastAbort;
|
|
127
|
+
let aborted = false;
|
|
128
|
+
|
|
129
|
+
function abortPromistream(reason) {
|
|
130
|
+
/* If an abort/end of the underlying Node stream occurred for a reason that's entirely unrelated to our current pipeline - most notably, this happens if the error originates from the *read* side of a non-transform Duplex stream - then we want to make sure that we tear down the Promistream pipeline on this side too. */
|
|
131
|
+
if (lastAbort != null && !aborted) {
|
|
132
|
+
aborted = true;
|
|
133
|
+
lastAbort(reason);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
127
136
|
|
|
128
137
|
stream.on("error", (error) => {
|
|
129
138
|
debug("Logging writable interface error:", error);
|
|
130
139
|
errorEncountered = ensureValidError(error);
|
|
140
|
+
abortPromistream(error);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
stream.on("end", () => {
|
|
144
|
+
debug("Reached end of underlying Writable stream");
|
|
145
|
+
abortPromistream(true);
|
|
131
146
|
});
|
|
132
147
|
|
|
133
148
|
async function maybeWaitForDrain() {
|
|
@@ -149,6 +164,7 @@ function wireWritable(debug, stream) {
|
|
|
149
164
|
await maybeWaitForDrain();
|
|
150
165
|
if (!isStdioStream(stream) && !isWritableStreamEnded(stream)) {
|
|
151
166
|
debug("Calling .destroy on Writable stream");
|
|
167
|
+
aborted = true;
|
|
152
168
|
stream.destroy(error);
|
|
153
169
|
}
|
|
154
170
|
},
|
|
@@ -156,10 +172,13 @@ function wireWritable(debug, stream) {
|
|
|
156
172
|
await maybeWaitForDrain();
|
|
157
173
|
if (!isStdioStream(stream) && !isWritableStreamEnded(stream)) {
|
|
158
174
|
debug("Calling .end on Writable stream");
|
|
175
|
+
aborted = true;
|
|
159
176
|
stream.end();
|
|
160
177
|
}
|
|
161
178
|
},
|
|
162
179
|
tryWrite: async function (value, abort) {
|
|
180
|
+
lastAbort = abort;
|
|
181
|
+
|
|
163
182
|
if (isWritableStreamEnded(stream)) {
|
|
164
183
|
debug("Could not write because underlying stream has ended");
|
|
165
184
|
if (errorEncountered != null) {
|
|
@@ -227,7 +246,7 @@ function convertFromTransform(stream) {
|
|
|
227
246
|
// This is essentially a 'background process' of sorts, with manual error handling wiring.
|
|
228
247
|
try {
|
|
229
248
|
while (endMarker == null) {
|
|
230
|
-
await tryWrite(await lastSource.read());
|
|
249
|
+
await tryWrite(await lastSource.read(), lastSource.abort);
|
|
231
250
|
}
|
|
232
251
|
} catch (error) {
|
|
233
252
|
if (endMarker == null && (isEndOfStream(error) || isAborted(error))) { // FIXME: isExhausted?
|
package/test.js
CHANGED
|
@@ -16,6 +16,7 @@ const parallelize = require("@promistream/parallelize");
|
|
|
16
16
|
const testAbort = require("@promistream/test-abort");
|
|
17
17
|
const debug = require("@promistream/debug");
|
|
18
18
|
const { once } = require("node:events");
|
|
19
|
+
const spy = require("@promistream/spy");
|
|
19
20
|
|
|
20
21
|
test("readable stream", async () => {
|
|
21
22
|
let testFile = path.join(__dirname, "pnpm-lock.yaml"); // Big-ish file, so we're likely to read in multiple chunks
|
|
@@ -60,7 +61,6 @@ test("readable stream with happy abort", { timeout: 500 }, async () => {
|
|
|
60
61
|
assert.deepStrictEqual(result, []);
|
|
61
62
|
});
|
|
62
63
|
|
|
63
|
-
|
|
64
64
|
test("writable stream", async () => {
|
|
65
65
|
let buffer = Buffer.alloc(400000);
|
|
66
66
|
|
|
@@ -86,6 +86,34 @@ test("writable stream", async () => {
|
|
|
86
86
|
assert.strictEqual(endReached, true);
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
+
test("writable stream with error abort", async () => {
|
|
90
|
+
let buffer = Buffer.alloc(400000);
|
|
91
|
+
|
|
92
|
+
let writableBuffer = Buffer.alloc(0);
|
|
93
|
+
let endReached = false;
|
|
94
|
+
let nodeWritable = new stream.Writable({
|
|
95
|
+
write(chunk, _encoding, callback) {
|
|
96
|
+
writableBuffer = Buffer.concat([ writableBuffer, chunk ]);
|
|
97
|
+
callback();
|
|
98
|
+
},
|
|
99
|
+
final(callback) {
|
|
100
|
+
endReached = true;
|
|
101
|
+
callback();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
await assert.rejects(async () => {
|
|
106
|
+
await pipe([
|
|
107
|
+
fromIterable([ buffer, buffer, buffer ]),
|
|
108
|
+
testAbort(0, new Error("sample error")),
|
|
109
|
+
fromNodeStream(nodeWritable)
|
|
110
|
+
]).read();
|
|
111
|
+
}, { message: "sample error" });
|
|
112
|
+
|
|
113
|
+
assert.strictEqual(writableBuffer.length, 0);
|
|
114
|
+
assert.strictEqual(endReached, false);
|
|
115
|
+
});
|
|
116
|
+
|
|
89
117
|
test("transform stream", async () => {
|
|
90
118
|
let result = await pipe([
|
|
91
119
|
fromIterable([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]),
|
|
@@ -107,7 +135,7 @@ test("transform stream", async () => {
|
|
|
107
135
|
});
|
|
108
136
|
|
|
109
137
|
test("transform stream with abort", async () => {
|
|
110
|
-
assert.rejects(async () => {
|
|
138
|
+
await assert.rejects(async () => {
|
|
111
139
|
let pipeline = pipe([
|
|
112
140
|
fromIterable([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]),
|
|
113
141
|
fromNodeStream(new stream.Transform({
|
|
@@ -203,3 +231,50 @@ test("network socket", async () => {
|
|
|
203
231
|
server.close();
|
|
204
232
|
}
|
|
205
233
|
});
|
|
234
|
+
|
|
235
|
+
async function wait10() {
|
|
236
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
test("network socket with error abort", { timeout: 500 }, async () => {
|
|
240
|
+
let { resolve, promise } = pDefer();
|
|
241
|
+
|
|
242
|
+
let server = net.createServer((socket) => {
|
|
243
|
+
let serverRead = fromNodeStream.fromReadable(socket);
|
|
244
|
+
let serverWrite = fromNodeStream.fromWritable(socket);
|
|
245
|
+
resolve({ serverRead, serverWrite });
|
|
246
|
+
});
|
|
247
|
+
server.listen(14292);
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
let client = net.connect({ host: "localhost", port: 14292 });
|
|
251
|
+
let clientRead = fromNodeStream.fromReadable(client);
|
|
252
|
+
let clientWrite = fromNodeStream.fromWritable(client);
|
|
253
|
+
let { serverRead, serverWrite } = await promise;
|
|
254
|
+
|
|
255
|
+
let serverPipe = pipe([ serverRead, collect() ]);
|
|
256
|
+
let serverWritePipe = pipe([
|
|
257
|
+
fromIterable([ Buffer.from("c"), Buffer.from("d") ]),
|
|
258
|
+
testAbort(0, new Error("sample error")),
|
|
259
|
+
serverWrite
|
|
260
|
+
]);
|
|
261
|
+
|
|
262
|
+
let clientPipe = pipe([ clientRead, collect() ]);
|
|
263
|
+
let clientWritePipe = pipe([
|
|
264
|
+
fromIterable([ Buffer.from("a"), Buffer.from("b") ]),
|
|
265
|
+
/* Give the client side some time to notice that the server side closed the connection */
|
|
266
|
+
spy(async(value) => { await wait10(); return value; }),
|
|
267
|
+
clientWrite
|
|
268
|
+
]);
|
|
269
|
+
|
|
270
|
+
let results = await Promise.all([
|
|
271
|
+
assert.rejects(() => serverPipe.read(), { message: "sample error" }),
|
|
272
|
+
assert.rejects(() => serverWritePipe.read(), { message: "sample error" }),
|
|
273
|
+
/* The other side of the connection closes normally, like it would for any disconnection */
|
|
274
|
+
clientPipe.read(),
|
|
275
|
+
clientWritePipe.read(),
|
|
276
|
+
]);
|
|
277
|
+
} finally {
|
|
278
|
+
server.close();
|
|
279
|
+
}
|
|
280
|
+
});
|