Skip to content

Commit

Permalink
Merge pull request #27 from myl7/web-next-example-dec
Browse files Browse the repository at this point in the history
Add decompress part to web Next.js stream example
  • Loading branch information
pimterry committed Jul 12, 2023
2 parents 4fa04d6 + 185ee97 commit 8f534b0
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 13 deletions.
28 changes: 16 additions & 12 deletions example/web-next-transformstream/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,32 @@

import streamSaver from 'streamsaver'

import { BrotliCompressTransformStream } from './utils'
import { BrotliCompressTransformStream, BrotliDecompressTransformStream } from './utils'

export default function Home() {
const brotli = (op: string) => async () => {
const brotliWasm = await (await import('brotli-wasm')).default
const fileInput = document.querySelector('#file-input') as HTMLInputElement
const file = fileInput.files![0]
if (!file) throw new Error('No file selected')
const inputStream = file.stream()
let transformStream = null
let outputFilename = null
switch (op) {
case 'enc':
const fileInput = document.querySelector('#file-input') as HTMLInputElement
const file = fileInput.files![0]
if (!file) throw new Error('No file selected')
const inputStream = file.stream()
const outputStream = streamSaver.createWriteStream(file.name + '.br')
// 1KB chunks
const transformStream = new BrotliCompressTransformStream(brotliWasm, 1024)
inputStream.pipeThrough(transformStream).pipeTo(outputStream)
transformStream = new BrotliCompressTransformStream(brotliWasm, 1024)
outputFilename = file.name + '.br'
break
case 'dec':
console.error('Not implemented')
transformStream = new BrotliDecompressTransformStream(brotliWasm, 1024)
outputFilename = file.name.match(/\.br$/) ? file.name.slice(0, -3) : file.name + '.debr'
break
default:
throw new Error('Invalid operation')
}
const outputStream = streamSaver.createWriteStream(outputFilename)
inputStream.pipeThrough(transformStream).pipeTo(outputStream)
}

return (
Expand All @@ -33,9 +39,7 @@ export default function Home() {
<button onClick={brotli('enc')}>Compress</button>
</div>
<div>
<button disabled onClick={brotli('dec')}>
Decompress
</button>
<button onClick={brotli('dec')}>Decompress</button>
</div>
</div>
</main>
Expand Down
43 changes: 42 additions & 1 deletion example/web-next-transformstream/app/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// The structure is from the MDN docs: https://developer.mozilla.org/en-US/docs/Web/API/TransformStream

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

interface BrotliCompressTransformer extends Transformer<Uint8Array, Uint8Array> {
brotliWasm: BrotliWasmType
Expand Down Expand Up @@ -49,3 +49,44 @@ export class BrotliCompressTransformStream extends TransformStream<Uint8Array, U
super(brotliCompressTransformerBuilder(brotliWasm, outputSize, quality))
}
}

interface BrotliDecompressTransformer extends Transformer<Uint8Array, Uint8Array> {
brotliWasm: BrotliWasmType
outputSize: number
stream: DecompressStream
}

const brotliDecompressTransformerBuilder: (
brotliWasm: BrotliWasmType,
outputSize: number
) => BrotliDecompressTransformer = (brotliWasm, outputSize) => ({
brotliWasm,
outputSize,
stream: new brotliWasm.DecompressStream(),
start() {},
transform(chunk, controller) {
let resultCode
let inputOffset = 0
do {
const input = chunk.slice(inputOffset)
const result = this.stream.decompress(input, this.outputSize)
controller.enqueue(result.buf)
resultCode = result.code
inputOffset += result.input_offset
} while (resultCode === brotliWasm.BrotliStreamResultCode.NeedsMoreOutput)
if (
resultCode !== brotliWasm.BrotliStreamResultCode.NeedsMoreInput &&
resultCode !== brotliWasm.BrotliStreamResultCode.ResultSuccess
) {
controller.error(`Brotli decompression failed with code ${resultCode}`)
}
},
// Brotli decompression does not need flushing
flush() {},
})

export class BrotliDecompressTransformStream extends TransformStream<Uint8Array, Uint8Array> {
constructor(brotliWasm: BrotliWasmType, outputSize: number) {
super(brotliDecompressTransformerBuilder(brotliWasm, outputSize))
}
}

0 comments on commit 8f534b0

Please sign in to comment.