UNPKG

@nestjs/common

Version:

Decorators, pipes, exceptions and utilities for NestJS applications: @Controller(), @Injectable(), @Body(), ValidationPipe, HttpException and more.

89 lines (88 loc) • 2.86 kB
import { Readable } from 'stream'; import { types } from 'util'; import { HttpStatus } from '../enums/index.js'; import { Logger } from '../services/index.js'; import { isFunction } from '../utils/shared.utils.js'; /** * @see [Streaming files](https://docs.nestjs.com/techniques/streaming-files) * * @publicApi */ export class StreamableFile { options; stream; logger = new Logger('StreamableFile'); handleError = (err, res) => { if (res.destroyed) { return; } if (res.headersSent) { // Ending the response would make the truncated file look complete. A // stream that fails after it ended (e.g. while closing the file) has // already handed over every byte, so the response is left to finish. this.logError(err); if (isFunction(res.destroy) && !this.stream?.readableEnded) { res.destroy(); } else { res.end(); } return; } // The message may name the path the stream reads from, so it is // logged rather than sent. this.logError(err); res.statusCode = HttpStatus.BAD_REQUEST; res.send('Bad Request'); }; logError = (err) => { this.logger.error(err); }; constructor(bufferOrReadStream, options = {}) { this.options = options; if (types.isUint8Array(bufferOrReadStream)) { this.stream = new Readable(); this.stream.push(bufferOrReadStream); this.stream.push(null); this.options = { ...this.options, length: this.options.length ?? bufferOrReadStream.length, }; } else if (bufferOrReadStream.pipe && isFunction(bufferOrReadStream.pipe)) { this.stream = bufferOrReadStream; // Without a listener, an 'error' emitted before the adapter attaches // its own (e.g. ENOENT from `fs.createReadStream()` while an // interceptor awaits), or by a file that is never sent, would bring // the process down. if (isFunction(this.stream.on)) { this.stream.on('error', () => { }); } } } getStream() { return this.stream; } getHeaders() { const { type = 'application/octet-stream', disposition = undefined, length = undefined, } = this.options; return { type, disposition, length, }; } get errorHandler() { return this.handleError; } setErrorHandler(handler) { this.handleError = handler; return this; } get errorLogger() { return this.logError; } setErrorLogger(handler) { this.logError = handler; return this; } }