node/lib/internal/webstreams/compression.js
James M Snell 09ad64d66d
stream: add CompressionStream and DecompressionStream
Signed-off-by: James M Snell <jasnell@gmail.com>

PR-URL: https://github.com/nodejs/node/pull/39348
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2021-07-14 10:52:59 -07:00

165 lines
3.7 KiB
JavaScript

'use strict';
const {
ObjectDefineProperties,
Symbol,
} = primordials;
const {
codes: {
ERR_INVALID_ARG_VALUE,
ERR_INVALID_THIS,
},
} = require('internal/errors');
const {
newReadableWritablePairFromDuplex,
} = require('internal/webstreams/adapters');
const {
customInspect,
kEnumerableProperty,
} = require('internal/webstreams/util');
const {
customInspectSymbol: kInspect,
} = require('internal/util');
let zlib;
function lazyZlib() {
zlib ??= require('zlib');
return zlib;
}
const kHandle = Symbol('kHandle');
const kTransform = Symbol('kTransform');
const kType = Symbol('kType');
/**
* @typedef {import('./readablestream').ReadableStream} ReadableStream
* @typedef {import('./writablestream').WritableStream} WritableStream
*/
function isCompressionStream(value) {
return typeof value?.[kHandle] === 'object' &&
value?.[kType] === 'CompressionStream';
}
function isDecompressionStream(value) {
return typeof value?.[kHandle] === 'object' &&
value?.[kType] === 'DecompressionStream';
}
class CompressionStream {
/**
* @param {'deflate'|'gzip'} format
*/
constructor(format) {
this[kType] = 'CompressionStream';
switch (format) {
case 'deflate':
this[kHandle] = lazyZlib().createDeflate();
break;
case 'gzip':
this[kHandle] = lazyZlib().createGzip();
break;
default:
throw new ERR_INVALID_ARG_VALUE('format', format);
}
this[kTransform] = newReadableWritablePairFromDuplex(this[kHandle]);
}
/**
* @readonly
* @type {ReadableStream}
*/
get readable() {
if (!isCompressionStream(this))
throw new ERR_INVALID_THIS('CompressionStream');
return this[kTransform].readable;
}
/**
* @readonly
* @type {WritableStream}
*/
get writable() {
if (!isCompressionStream(this))
throw new ERR_INVALID_THIS('CompressionStream');
return this[kTransform].writable;
}
[kInspect](depth, options) {
if (!isCompressionStream(this))
throw new ERR_INVALID_THIS('CompressionStream');
customInspect(depth, options, 'CompressionStream', {
readable: this[kTransform].readable,
writable: this[kTransform].writable,
});
}
}
class DecompressionStream {
/**
* @param {'deflate'|'gzip'} format
*/
constructor(format) {
this[kType] = 'DecompressionStream';
switch (format) {
case 'deflate':
this[kHandle] = lazyZlib().createInflate();
break;
case 'gzip':
this[kHandle] = lazyZlib().createGunzip();
break;
default:
throw new ERR_INVALID_ARG_VALUE('format', format);
}
this[kTransform] = newReadableWritablePairFromDuplex(this[kHandle]);
}
/**
* @readonly
* @type {ReadableStream}
*/
get readable() {
if (!isDecompressionStream(this))
throw new ERR_INVALID_THIS('DecompressionStream');
return this[kTransform].readable;
}
/**
* @readonly
* @type {WritableStream}
*/
get writable() {
if (!isDecompressionStream(this))
throw new ERR_INVALID_THIS('DecompressionStream');
return this[kTransform].writable;
}
[kInspect](depth, options) {
if (!isDecompressionStream(this))
throw new ERR_INVALID_THIS('DecompressionStream');
customInspect(depth, options, 'DecompressionStream', {
readable: this[kTransform].readable,
writable: this[kTransform].writable,
});
}
}
ObjectDefineProperties(CompressionStream.prototype, {
readable: kEnumerableProperty,
writable: kEnumerableProperty,
});
ObjectDefineProperties(DecompressionStream.prototype, {
readable: kEnumerableProperty,
writable: kEnumerableProperty,
});
module.exports = {
CompressionStream,
DecompressionStream,
};