♻ Extract waiting for stream to be readable

This commit is contained in:
C-3PO 2018-07-08 21:58:42 +02:00
parent 0122104f4c
commit ab1280d46c
Signed by: c3po
GPG key ID: 62993C4BB4D86F24
4 changed files with 29 additions and 34 deletions

View file

@ -4,7 +4,7 @@ import * as stream from 'stream';
import * as zlib from 'zlib';
import { ISsnFileEntry } from '../interfaces/ISsnFileEntry';
import decryptStream from './streams/decryptStream';
import waitReadableLength from './streams/waitReadableLength';
import readBytesFromStream from './streams/readBytesFromStream';
/** Extracts the file with the given metadata from the stream.
* The stream must already start at the .zip's local file header
@ -18,12 +18,7 @@ export default async function extractFileStream(file: ISsnFileEntry, inputStream
const decryptTransform = decryptStream(file.decryptionKeys);
curStream = curStream.pipe(decryptTransform);
//skip encryption header
const encryptionHeader = curStream.read(12);
if (encryptionHeader === null) {
//need to wait until data is ready for reading
await waitReadableLength(curStream, 12);
curStream.read(12);
}
readBytesFromStream(curStream, 12);
}
if (!skipDecompression) {

View file

@ -0,0 +1,24 @@
import * as stream from 'stream';
/** Returns a promise that resolves as soon as the given stream has the given number of bytes ready for reading. */
function waitReadableLength(inputStream: stream.Readable, minLength: number): Promise<void> {
return new Promise((resolve) => {
const interval = setInterval(() => {
if (inputStream.readableLength >= minLength) {
clearInterval(interval);
resolve();
}
}, 100);
});
}
/** Reads the given number of bytes from the stream and returns them as a buffer, optionally waiting until the bytes are ready for reading. */
export default async function readBytesFromStream(inputStream: stream.Readable, length: number): Promise<Buffer> {
let localFileHeader: Buffer = inputStream.read(length);
while (localFileHeader === null) {
//need to wait until data is ready for reading
await waitReadableLength(inputStream, length);
localFileHeader = inputStream.read(length);
}
return localFileHeader;
}

View file

@ -1,17 +1,12 @@
import * as stream from 'stream';
import waitReadableLength from './waitReadableLength';
import readBytesFromStream from './readBytesFromStream';
/** Reads the local file header, which is included before
* each stored file, and advances the stream accordingly.
* Returns length of the local file header.
*/
export default async function readLocalFileHeader(inputStream: stream.Readable, skipAdditionalLength = false): Promise<number> {
let localFileHeader: Buffer = inputStream.read(30);
if (localFileHeader === null) {
//need to wait until data is ready for reading
await waitReadableLength(inputStream, 30);
localFileHeader = inputStream.read(30);
}
const localFileHeader = await readBytesFromStream(inputStream, 30);
//Local file header signature
const magic = localFileHeader.readUInt32LE(0);
@ -27,13 +22,7 @@ export default async function readLocalFileHeader(inputStream: stream.Readable,
//skip local file name and extra field
const additionalLength = localFilenameSize + localExtraSize;
if (skipAdditionalLength && additionalLength > 0) {
await waitReadableLength(inputStream, additionalLength);
const tmpChunk = inputStream.read(additionalLength);
if (tmpChunk === null) {
//need to wait until data is ready for reading
await waitReadableLength(inputStream, additionalLength);
inputStream.read(additionalLength);
}
await readBytesFromStream(inputStream, additionalLength);
}
return 30 + additionalLength;

View file

@ -1,13 +0,0 @@
import * as stream from 'stream';
/** Returns a promise that resolves as soon as the given stream has the given number of bytes ready for reading. */
export default function waitReadableLength(inputStream: stream.Readable, minLength: number): Promise<void> {
return new Promise((resolve) => {
const interval = setInterval(() => {
if (inputStream.readableLength >= minLength) {
clearInterval(interval);
resolve();
}
}, 100);
});
}