Skip to content

Commit

Permalink
add chunker transform stream (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
huan committed Oct 27, 2020
1 parent 7b4b2f2 commit e81103a
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 1 deletion.
8 changes: 7 additions & 1 deletion src/file-box.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
bufferToQrValue,
qrValueToStream,
} from './qrcode'
import { chunkerTransformStream } from './pure-functions/chunker-transform-stream'

const EMPTY_META_DATA = Object.freeze({})

Expand Down Expand Up @@ -492,7 +493,12 @@ export class FileBox implements Pipeable {
private transformBufferToStream (buffer?: Buffer): Readable {
const bufferStream = new PassThrough()
bufferStream.end(buffer || this.buffer)
return bufferStream

/**
* Use small `chunks` with `toStream()` #44
* https://github.com/huan/file-box/issues/44
*/
return bufferStream.pipe(chunkerTransformStream())
}

private transformBase64ToStream (): Readable {
Expand Down
52 changes: 52 additions & 0 deletions src/pure-functions/chunker-transform-stream.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env ts-node

/* eslint @typescript-eslint/no-unused-vars:off */

import { test } from 'tstest'

import {
PassThrough,
Readable,
} from 'stream'

import { chunkerTransformStream } from './chunker-transform-stream'

test('chunkerTransformStream()', async t => {
const DATA_LIST = [
'a',
'b',
]
const DATA = DATA_LIST.join('')

const createStream = () => {
const stream = new PassThrough()
stream.end(DATA)
return stream
}

const getDataList = (stream: Readable) => {
return new Promise<any[]>(resolve => {
const list = [] as any[]
stream.on('end', () => resolve(list))
stream.on('data', chunk => list.push(chunk))
})
}

const newStream0 = createStream()
const dataList0 = await getDataList(newStream0)

t.equal(dataList0.length, 1, 'should get 1 chunks')
t.equal(dataList0[0].toString(), DATA, 'should get data')

const newStream1 = createStream().pipe(chunkerTransformStream(2))
const dataList1 = await getDataList(newStream1)

t.equal(dataList1.length, 1, 'should get 1 chunks')
t.equal(dataList1[0].toString(), DATA, 'should get data')

const newStream2 = createStream().pipe(chunkerTransformStream(1))
const dataList2 = await getDataList(newStream2)

t.equal(dataList2.length, 2, 'should get 2 chunks')
t.equal(dataList2.join(''), DATA, 'should get data')
})
36 changes: 36 additions & 0 deletions src/pure-functions/chunker-transform-stream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* ChunkerTransformStream, a transform stream to take arbitrary chunk sizes and make them consistent
* https://codereview.stackexchange.com/q/57492/185709
*/
import stream from 'stream'

function chunkerTransformStream (chunkSize = 16384) {
let buffer = Buffer.from([])

const chunker = new stream.Transform({
objectMode: true,
})
chunker._transform = function (chunk, _, done) {
buffer = Buffer.concat([buffer, chunk])

while (buffer.length >= chunkSize) {
this.push(buffer.slice(0, chunkSize))
buffer = buffer.slice(chunkSize)
}

done()
}

chunker._flush = function (done) {
if (buffer.length) {
this.push(buffer)
}
done()
}

return chunker
}

export {
chunkerTransformStream,
}

0 comments on commit e81103a

Please sign in to comment.