@@ -88,38 +88,70 @@ const inputStream = new ReadableStream({
8888// Convert the streaming data to Uint8Arrays, if necessary:
8989const textEncoderStream = new TextEncoderStream ();
9090
91+ // You can use whatever stream chunking size you like here, depending on your use case:
92+ const OUTPUT_SIZE = 100 ;
93+
9194// Create a stream to incrementally compress the data as it streams:
9295const compressStream = new brotli.CompressStream ();
9396const compressionStream = new TransformStream ({
94- start () { },
9597 transform (chunk , controller ) {
96- // Compress data, producing 1024 bytes of output at a time (i.e. limiting the output):
97- controller .enqueue (compressStream .compress (chunk, 1024 ));
98+ let resultCode;
99+ let inputOffset = 0 ;
100+
101+ // Compress this chunk, producing up to OUTPUT_SIZE output bytes at a time, until the
102+ // entire input has been compressed.
103+
104+ do {
105+ const input = chunk .slice (inputOffset);
106+ const result = compressStream .compress (input, OUTPUT_SIZE );
107+ controller .enqueue (result .buf );
108+ resultCode = result .code ;
109+ inputOffset += result .input_offset ;
110+ } while (resultCode === brotli .BrotliStreamResultCode .NeedsMoreOutput );
111+ if (resultCode !== brotli .BrotliStreamResultCode .NeedsMoreInput ) {
112+ controller .error (` Brotli compression failed when transforming with code ${ resultCode} ` );
113+ }
98114 },
99115 flush (controller ) {
100- // Stream remaining compressed data after input finishes, 1024 bytes of output at a time:
101- while (
102- compressStream .result () === brotli .BrotliStreamResult .NeedsMoreInput ||
103- compressStream .result () === brotli .BrotliStreamResult .NeedsMoreOutput
104- ) {
105- controller .enqueue (compressStream .compress (undefined , 1024 ));
116+ // Once the chunks are finished, flush any remaining data (again in repeated fixed-output
117+ // chunks) to finish the stream:
118+ let resultCode;
119+ do {
120+ const result = compressStream .compress (undefined , OUTPUT_SIZE );
121+ controller .enqueue (result .buf );
122+ resultCode = result .code ;
123+ } while (resultCode === brotli .BrotliStreamResultCode .NeedsMoreOutput )
124+ if (resultCode !== brotli .BrotliStreamResultCode .ResultSuccess ) {
125+ controller .error (` Brotli compression failed when flushing with code ${ resultCode} ` );
106126 }
107127 controller .terminate ();
108128 }
109129});
110130
111131const decompressStream = new brotli.DecompressStream ();
112132const decompressionStream = new TransformStream ({
113- start () { },
114133 transform (chunk , controller ) {
115- // Decompress, producing 1024 bytes of output at a time:
116- controller .enqueue (decompressStream .decompress (chunk, 1024 ));
134+ let resultCode;
135+ let inputOffset = 0 ;
136+
137+ // Decompress this chunk, producing up to OUTPUT_SIZE output bytes at a time, until the
138+ // entire input has been decompressed.
139+
140+ do {
141+ const input = chunk .slice (inputOffset);
142+ const result = decompressStream .decompress (input, OUTPUT_SIZE );
143+ controller .enqueue (result .buf );
144+ resultCode = result .code ;
145+ inputOffset += result .input_offset ;
146+ } while (resultCode === brotli .BrotliStreamResultCode .NeedsMoreOutput );
147+ if (
148+ resultCode !== brotli .BrotliStreamResultCode .NeedsMoreInput &&
149+ resultCode !== brotli .BrotliStreamResultCode .ResultSuccess
150+ ) {
151+ controller .error (` Brotli decompression failed with code ${ resultCode} ` )
152+ }
117153 },
118154 flush (controller ) {
119- // Decompress all remaining output after input finishes, 1024 bytes at a time:
120- while (decompressStream .result () === brotli .BrotliStreamResult .NeedsMoreOutput ) {
121- controller .enqueue (decompressStream .decompress (new Uint8Array (0 ), 1024 ));
122- }
123155 controller .terminate ();
124156 }
125157});
0 commit comments