send-stream
Version:
Streaming file serving library with Range and conditional-GET support from file system or any streaming sources.
110 lines • 3.83 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.StreamResponse = void 0;
const node_http_1 = require("node:http");
const node_http2_1 = require("node:http2");
const node_stream_1 = require("node:stream");
const node_util_1 = require("node:util");
const promisifiedStreamPipeline = (0, node_util_1.promisify)(node_stream_1.pipeline);
async function pipeline(readStream, res, ignorePrematureClose) {
try {
await promisifiedStreamPipeline(readStream, res);
}
catch (err) {
if (ignorePrematureClose) {
return;
}
throw err;
}
}
/**
* Stream response
* @template AttachedData - attached data type
*/
class StreamResponse {
/**
* Create stream response
* @param statusCode - the status code matching the required resource
* @param headers - the response headers to be sent for the required resource
* @param stream - the response stream to be sent for the required resource
* @param storageInfo - the storage information for the required resource (if existing)
* @param error - the error if the resource can not be found or openned for any reason
*/
constructor(statusCode, headers, stream, storageInfo, error) {
Object.defineProperty(this, "statusCode", {
enumerable: true,
configurable: true,
writable: true,
value: statusCode
});
Object.defineProperty(this, "headers", {
enumerable: true,
configurable: true,
writable: true,
value: headers
});
Object.defineProperty(this, "stream", {
enumerable: true,
configurable: true,
writable: true,
value: stream
});
Object.defineProperty(this, "storageInfo", {
enumerable: true,
configurable: true,
writable: true,
value: storageInfo
});
Object.defineProperty(this, "error", {
enumerable: true,
configurable: true,
writable: true,
value: error
});
}
/**
* Send response to http response
* @param res - http response
* @param opts - options
* @param opts.ignorePrematureClose - ignore premature close errors
* @throws error when response is already closed
*/
async send(res, { ignorePrematureClose = true } = {}) {
const { statusCode } = this;
const { headers: responseHeaders, stream: readStream } = this;
if (res.headersSent) {
readStream.destroy();
throw new Error('response headers already sent');
}
if (res instanceof node_http_1.ServerResponse) {
const { socket, destroyed } = res;
if (destroyed || !socket || socket.destroyed) {
readStream.destroy();
return;
}
res.writeHead(statusCode, responseHeaders);
await pipeline(readStream, res, ignorePrematureClose);
}
else {
const resStream = res instanceof node_http2_1.Http2ServerResponse ? res.stream : res;
if (resStream.destroyed || resStream.closed) {
readStream.destroy();
return;
}
resStream.respond({
// eslint-disable-next-line @typescript-eslint/naming-convention
':status': statusCode,
...responseHeaders,
});
await pipeline(readStream, resStream, ignorePrematureClose);
}
}
/**
* Disposes of resources within the stream response object
*/
dispose() {
this.stream.destroy();
}
}
exports.StreamResponse = StreamResponse;
//# sourceMappingURL=response.js.map