♻ Extract waiting for stream to be readable
This commit is contained in:
parent
0122104f4c
commit
ab1280d46c
4 changed files with 29 additions and 34 deletions
|
@ -4,7 +4,7 @@ import * as stream from 'stream';
|
||||||
import * as zlib from 'zlib';
|
import * as zlib from 'zlib';
|
||||||
import { ISsnFileEntry } from '../interfaces/ISsnFileEntry';
|
import { ISsnFileEntry } from '../interfaces/ISsnFileEntry';
|
||||||
import decryptStream from './streams/decryptStream';
|
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.
|
/** Extracts the file with the given metadata from the stream.
|
||||||
* The stream must already start at the .zip's local file header
|
* 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);
|
const decryptTransform = decryptStream(file.decryptionKeys);
|
||||||
curStream = curStream.pipe(decryptTransform);
|
curStream = curStream.pipe(decryptTransform);
|
||||||
//skip encryption header
|
//skip encryption header
|
||||||
const encryptionHeader = curStream.read(12);
|
readBytesFromStream(curStream, 12);
|
||||||
if (encryptionHeader === null) {
|
|
||||||
//need to wait until data is ready for reading
|
|
||||||
await waitReadableLength(curStream, 12);
|
|
||||||
curStream.read(12);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipDecompression) {
|
if (!skipDecompression) {
|
||||||
|
|
24
src/ssn/streams/readBytesFromStream.ts
Normal file
24
src/ssn/streams/readBytesFromStream.ts
Normal 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;
|
||||||
|
}
|
|
@ -1,17 +1,12 @@
|
||||||
import * as stream from 'stream';
|
import * as stream from 'stream';
|
||||||
import waitReadableLength from './waitReadableLength';
|
import readBytesFromStream from './readBytesFromStream';
|
||||||
|
|
||||||
/** Reads the local file header, which is included before
|
/** Reads the local file header, which is included before
|
||||||
* each stored file, and advances the stream accordingly.
|
* each stored file, and advances the stream accordingly.
|
||||||
* Returns length of the local file header.
|
* Returns length of the local file header.
|
||||||
*/
|
*/
|
||||||
export default async function readLocalFileHeader(inputStream: stream.Readable, skipAdditionalLength = false): Promise<number> {
|
export default async function readLocalFileHeader(inputStream: stream.Readable, skipAdditionalLength = false): Promise<number> {
|
||||||
let localFileHeader: Buffer = inputStream.read(30);
|
const localFileHeader = await readBytesFromStream(inputStream, 30);
|
||||||
if (localFileHeader === null) {
|
|
||||||
//need to wait until data is ready for reading
|
|
||||||
await waitReadableLength(inputStream, 30);
|
|
||||||
localFileHeader = inputStream.read(30);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Local file header signature
|
//Local file header signature
|
||||||
const magic = localFileHeader.readUInt32LE(0);
|
const magic = localFileHeader.readUInt32LE(0);
|
||||||
|
@ -27,13 +22,7 @@ export default async function readLocalFileHeader(inputStream: stream.Readable,
|
||||||
//skip local file name and extra field
|
//skip local file name and extra field
|
||||||
const additionalLength = localFilenameSize + localExtraSize;
|
const additionalLength = localFilenameSize + localExtraSize;
|
||||||
if (skipAdditionalLength && additionalLength > 0) {
|
if (skipAdditionalLength && additionalLength > 0) {
|
||||||
await waitReadableLength(inputStream, additionalLength);
|
await readBytesFromStream(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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 30 + additionalLength;
|
return 30 + additionalLength;
|
||||||
|
|
|
@ -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);
|
|
||||||
});
|
|
||||||
}
|
|
Loading…
Reference in a new issue