mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Pipe streams with the pump library
The library handles some edge cases we didn't yet. The GuardedStream was also updated to ignore error listeners already attached to the stream (since pump adds internal listeners).
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import type { Writable, ReadableOptions, DuplexOptions } from 'stream';
|
||||
import { Readable, Transform } from 'stream';
|
||||
import arrayifyStream from 'arrayify-stream';
|
||||
import pump from 'pump';
|
||||
import { getLoggerFor } from '../logging/LogUtil';
|
||||
import type { Guarded } from './GuardedStream';
|
||||
import { guardStream } from './GuardedStream';
|
||||
@@ -29,27 +30,16 @@ export async function readableToString(stream: Readable): Promise<string> {
|
||||
*/
|
||||
export function pipeSafely<T extends Writable>(readable: NodeJS.ReadableStream, destination: T,
|
||||
mapError?: (error: Error) => Error): Guarded<T> {
|
||||
// Not using `stream.pipeline` since the result there only emits an error event if the last stream has the error
|
||||
readable.pipe(destination);
|
||||
readable.on('error', (error): void => {
|
||||
logger.warn(`Piped stream errored with ${error.message}`);
|
||||
|
||||
// From https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options :
|
||||
// "One important caveat is that if the Readable stream emits an error during processing, the Writable destination
|
||||
// is not closed automatically. If an error occurs, it will be necessary to manually close each stream
|
||||
// in order to prevent memory leaks."
|
||||
destination.destroy(mapError ? mapError(error) : error);
|
||||
// In case the input readable is guarded, it will no longer log errors since `pump` attaches a new error listener
|
||||
pump(readable, destination, (error): void => {
|
||||
if (error) {
|
||||
logger.warn(`Piped stream errored with ${error.message}`);
|
||||
// Make sure the final error can be handled in a normal streaming fashion
|
||||
destination.emit('error', mapError ? mapError(error) : error);
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure we have no dangling streams in case of unpiping, which can happen if there's an error.
|
||||
// This can also happen if a stream naturally closes so most calls here will not be indication of a problem.
|
||||
// From https://nodejs.org/api/stream.html#stream_errors_while_writing :
|
||||
// "If a Readable stream pipes into a Writable stream when Writable emits an error,
|
||||
// the Readable stream will be unpiped."
|
||||
destination.on('unpipe', (source): void => {
|
||||
source.destroy();
|
||||
});
|
||||
|
||||
// Guarding the stream now means the internal error listeners of pump will be ignored
|
||||
// when checking if there is a valid error listener.
|
||||
return guardStream(destination);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user