UNPKG

send-stream

Version:

Streaming file serving library with Range and conditional-GET support from file system or any streaming sources.

129 lines 3.88 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MultiStream = exports.BufferStream = void 0; const node_stream_1 = require("node:stream"); /** * Single buffer stream */ class BufferStream extends node_stream_1.Readable { /** * Create a single buffer stream * @param buffer - content buffer or undefined if stream need to be empty */ constructor(buffer) { super({ autoDestroy: true }); Object.defineProperty(this, "buffer", { enumerable: true, configurable: true, writable: true, value: void 0 }); this.buffer = buffer; } /** * Read implementation */ _read() { const { buffer } = this; if (buffer) { this.buffer = undefined; this.push(buffer); } this.push(null); } /** * Destroy implementation * @param error - error or null * @param callback - callback to be called after destroy */ _destroy(error, callback) { this.buffer = undefined; // eslint-disable-next-line no-underscore-dangle super._destroy(error, callback); } } exports.BufferStream = BufferStream; /** * Multi stream */ class MultiStream extends node_stream_1.PassThrough { /** * Create a multi streams stream * @param ranges - array of Buffer or StreamRange * @param onNextStream - function creating the Readable when needed * @param onDestroy - function called on close to release resources */ constructor(ranges, onNextStream, onDestroy) { super({ allowHalfOpen: false }); Object.defineProperty(this, "ranges", { enumerable: true, configurable: true, writable: true, value: ranges }); Object.defineProperty(this, "onNextStream", { enumerable: true, configurable: true, writable: true, value: onNextStream }); Object.defineProperty(this, "onDestroy", { enumerable: true, configurable: true, writable: true, value: onDestroy }); this.sendNextRange(); } /** * Destroy implementation * @param error - error or null * @param callback - callback to be called after destroy */ _destroy(error, callback) { this.onDestroy() .then(() => { // eslint-disable-next-line no-underscore-dangle super._destroy(error, callback); }) .catch((closeError) => { // eslint-disable-next-line no-underscore-dangle super._destroy(error ? new Error(`${String(error)}\nthen\n${String(closeError)}`) : new Error(String(closeError)), callback); }); } sendNextRange() { const currentRange = this.ranges.shift(); if (!currentRange) { this.end(() => { this.destroy(); }); return; } const stream = this.onNextStream(currentRange); const listenerMap = new Map(); const onClose = () => { for (const [eventType, listener] of listenerMap.entries()) { stream.off(eventType, listener); } }; const onError = (error) => { onClose(); this.end(() => { this.destroy(error); }); }; const onEnd = () => { onClose(); this.sendNextRange(); }; listenerMap.set('error', onError); stream.on('error', onError); listenerMap.set('end', onEnd); stream.on('end', onEnd); stream.pipe(this, { end: false }); } } exports.MultiStream = MultiStream; //# sourceMappingURL=streams.js.map