-
Notifications
You must be signed in to change notification settings - Fork 21
/
utils.ts
92 lines (85 loc) · 3.17 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// The structure is from the MDN docs: https://developer.mozilla.org/en-US/docs/Web/API/TransformStream
import type { CompressStream, BrotliWasmType, DecompressStream } from 'brotli-wasm'
interface BrotliCompressTransformer extends Transformer<Uint8Array, Uint8Array> {
brotliWasm: BrotliWasmType
outputSize: number
stream: CompressStream
}
const brotliCompressTransformerBuilder: (
brotliWasm: BrotliWasmType,
outputSize: number,
quality?: number
) => BrotliCompressTransformer = (brotliWasm, outputSize, quality) => ({
brotliWasm,
outputSize,
stream: new brotliWasm.CompressStream(quality),
start() {},
transform(chunk, controller) {
let resultCode
let inputOffset = 0
do {
const input = chunk.slice(inputOffset)
const result = this.stream.compress(input, this.outputSize)
controller.enqueue(result.buf)
resultCode = result.code
inputOffset += result.input_offset
} while (resultCode === brotliWasm.BrotliStreamResultCode.NeedsMoreOutput)
if (resultCode !== brotliWasm.BrotliStreamResultCode.NeedsMoreInput) {
controller.error(`Brotli compression failed when transforming with code ${resultCode}`)
}
},
flush(controller) {
let resultCode
do {
const result = this.stream.compress(undefined, this.outputSize)
controller.enqueue(result.buf)
resultCode = result.code
} while (resultCode === brotliWasm.BrotliStreamResultCode.NeedsMoreOutput)
if (resultCode !== brotliWasm.BrotliStreamResultCode.ResultSuccess) {
controller.error(`Brotli compression failed when flushing with code ${resultCode}`)
}
},
})
export class BrotliCompressTransformStream extends TransformStream<Uint8Array, Uint8Array> {
constructor(brotliWasm: BrotliWasmType, outputSize: number, quality?: number) {
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))
}
}