Skip to content

Commit ba97b76

Browse files
committed
Add decompress part to web Next.js stream example
1 parent 4fa04d6 commit ba97b76

File tree

2 files changed

+55
-13
lines changed

2 files changed

+55
-13
lines changed

example/web-next-transformstream/app/page.tsx

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,32 @@
22

33
import streamSaver from 'streamsaver'
44

5-
import { BrotliCompressTransformStream } from './utils'
5+
import { BrotliCompressTransformStream, BrotliDecompressTransformStream } from './utils'
66

77
export default function Home() {
88
const brotli = (op: string) => async () => {
99
const brotliWasm = await (await import('brotli-wasm')).default
10+
const fileInput = document.querySelector('#file-input') as HTMLInputElement
11+
const file = fileInput.files![0]
12+
if (!file) throw new Error('No file selected')
13+
const inputStream = file.stream()
14+
let transformStream = null
15+
let outputFilename = null
1016
switch (op) {
1117
case 'enc':
12-
const fileInput = document.querySelector('#file-input') as HTMLInputElement
13-
const file = fileInput.files![0]
14-
if (!file) throw new Error('No file selected')
15-
const inputStream = file.stream()
16-
const outputStream = streamSaver.createWriteStream(file.name + '.br')
1718
// 1KB chunks
18-
const transformStream = new BrotliCompressTransformStream(brotliWasm, 1024)
19-
inputStream.pipeThrough(transformStream).pipeTo(outputStream)
19+
transformStream = new BrotliCompressTransformStream(brotliWasm, 1024)
20+
outputFilename = file.name + '.br'
2021
break
2122
case 'dec':
22-
console.error('Not implemented')
23+
transformStream = new BrotliDecompressTransformStream(brotliWasm, 1024)
24+
outputFilename = file.name.match(/\.br$/) ? file.name.slice(0, -3) : file.name + '.debr'
2325
break
26+
default:
27+
throw new Error('Invalid operation')
2428
}
29+
const outputStream = streamSaver.createWriteStream(outputFilename)
30+
inputStream.pipeThrough(transformStream).pipeTo(outputStream)
2531
}
2632

2733
return (
@@ -33,9 +39,7 @@ export default function Home() {
3339
<button onClick={brotli('enc')}>Compress</button>
3440
</div>
3541
<div>
36-
<button disabled onClick={brotli('dec')}>
37-
Decompress
38-
</button>
42+
<button onClick={brotli('dec')}>Decompress</button>
3943
</div>
4044
</div>
4145
</main>

example/web-next-transformstream/app/utils.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// The structure is from the MDN docs: https://developer.mozilla.org/en-US/docs/Web/API/TransformStream
22

3-
import type { CompressStream, BrotliWasmType } from 'brotli-wasm'
3+
import type { CompressStream, BrotliWasmType, DecompressStream } from 'brotli-wasm'
44

55
interface BrotliCompressTransformer extends Transformer<Uint8Array, Uint8Array> {
66
brotliWasm: BrotliWasmType
@@ -49,3 +49,41 @@ export class BrotliCompressTransformStream extends TransformStream<Uint8Array, U
4949
super(brotliCompressTransformerBuilder(brotliWasm, outputSize, quality))
5050
}
5151
}
52+
53+
interface BrotliDecompressTransformer extends Transformer<Uint8Array, Uint8Array> {
54+
brotliWasm: BrotliWasmType
55+
outputSize: number
56+
stream: DecompressStream
57+
}
58+
59+
const brotliDecompressTransformerBuilder: (
60+
brotliWasm: BrotliWasmType,
61+
outputSize: number
62+
) => BrotliDecompressTransformer = (brotliWasm, outputSize) => ({
63+
brotliWasm,
64+
outputSize,
65+
stream: new brotliWasm.DecompressStream(),
66+
start() {},
67+
transform(chunk, controller) {
68+
do {
69+
const inputOffset = this.stream.last_input_offset()
70+
const input = chunk.slice(inputOffset)
71+
const output = this.stream.decompress(input, this.outputSize)
72+
controller.enqueue(output)
73+
} while (this.stream.result() === brotliWasm.BrotliStreamResult.NeedsMoreOutput)
74+
if (
75+
this.stream.result() !== brotliWasm.BrotliStreamResult.NeedsMoreInput &&
76+
this.stream.result() !== brotliWasm.BrotliStreamResult.ResultSuccess
77+
) {
78+
controller.error(`Brotli decompression failed when transforming with error code ${this.stream.result()}`)
79+
}
80+
},
81+
// Brotli decompression does not need flushing
82+
flush() {},
83+
})
84+
85+
export class BrotliDecompressTransformStream extends TransformStream<Uint8Array, Uint8Array> {
86+
constructor(brotliWasm: BrotliWasmType, outputSize: number) {
87+
super(brotliDecompressTransformerBuilder(brotliWasm, outputSize))
88+
}
89+
}

0 commit comments

Comments
 (0)