♻ Read local file header separately
This commit is contained in:
parent
843314e475
commit
4d8a631db4
4 changed files with 22 additions and 16 deletions
|
@ -36,7 +36,7 @@ export default async function getManifest(product: Product): Promise<IManifest>
|
||||||
const stream = arrayBufferToStream(ssnFile, firstFile.offset);
|
const stream = arrayBufferToStream(ssnFile, firstFile.offset);
|
||||||
|
|
||||||
//Extract manifest.xml file
|
//Extract manifest.xml file
|
||||||
await readLocalFileHeader(stream);
|
await readLocalFileHeader(stream, true);
|
||||||
const patchmanifestStream = extractFileStream(firstFile, stream);
|
const patchmanifestStream = extractFileStream(firstFile, stream);
|
||||||
|
|
||||||
//Convert ArrayBuffer to string
|
//Convert ArrayBuffer to string
|
||||||
|
|
|
@ -41,7 +41,7 @@ export default async function getSolidpkg(product: Product, from: number, to: nu
|
||||||
const stream = arrayBufferToStream(ssnFile, firstFile.offset);
|
const stream = arrayBufferToStream(ssnFile, firstFile.offset);
|
||||||
|
|
||||||
//Extract metafile.solid file
|
//Extract metafile.solid file
|
||||||
await readLocalFileHeader(stream);
|
await readLocalFileHeader(stream, skipAdditionalLength);
|
||||||
const solidFileStream = extractFileStream(firstFile, stream);
|
const solidFileStream = extractFileStream(firstFile, stream);
|
||||||
const solidFileArrayBuffer = await streamToArrayBuffer(solidFileStream);
|
const solidFileArrayBuffer = await streamToArrayBuffer(solidFileStream);
|
||||||
const solidContents = parseBencode(new DataView(solidFileArrayBuffer)) as ISolid;
|
const solidContents = parseBencode(new DataView(solidFileArrayBuffer)) as ISolid;
|
||||||
|
|
|
@ -11,15 +11,14 @@ interface IGetFileFromDisksOptions {
|
||||||
storedSize: number;
|
storedSize: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStream(disks: string[], index: number, offset: number, length: number = Infinity) {
|
function createFileStream(disks: string[], index: number, offset: number, length: number = Infinity): fs.ReadStream {
|
||||||
return fs.createReadStream(disks[index], { start: offset, end: offset + length - 1 });
|
return fs.createReadStream(disks[index], { start: offset, end: offset + length - 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Takes a list of ReadableStreams (the disks), as well as the offset and length, and returns a stream for just one file. */
|
/** Takes a list of ReadableStreams (the disks), as well as the offset and length, and returns a stream for just one file. */
|
||||||
export default async function getFileFromDisks(disks: string[], { diskStart, offset, storedSize }: IGetFileFromDisksOptions): Promise<stream.Readable> {
|
async function getFullStream(disks: string[], { diskStart, offset, storedSize }: IGetFileFromDisksOptions): Promise<stream.Readable> {
|
||||||
let curDiskIndex = diskStart;
|
let curDiskIndex = diskStart;
|
||||||
let curDisk = getStream(disks, diskStart, offset);
|
let curDisk: fs.ReadStream = createFileStream(disks, diskStart, offset);
|
||||||
let localFileHeaderLength = 0;
|
|
||||||
let totalRead = 0;
|
let totalRead = 0;
|
||||||
|
|
||||||
//Create new stream that concatenates disks until storedSize is reached, then ends the stream.
|
//Create new stream that concatenates disks until storedSize is reached, then ends the stream.
|
||||||
|
@ -28,8 +27,8 @@ export default async function getFileFromDisks(disks: string[], { diskStart, off
|
||||||
const onData = (chunk: Buffer) => {
|
const onData = (chunk: Buffer) => {
|
||||||
totalRead += chunk.length;
|
totalRead += chunk.length;
|
||||||
//If we've reached the end, we can stop reading after this chunk
|
//If we've reached the end, we can stop reading after this chunk
|
||||||
const readTooManyBytes = totalRead - (localFileHeaderLength + storedSize);
|
const readTooManyBytes = totalRead - storedSize;
|
||||||
if (localFileHeaderLength !== 0 && readTooManyBytes >= 0) {
|
if (readTooManyBytes >= 0) {
|
||||||
//We can still write the whole chunk before ending the stream
|
//We can still write the whole chunk before ending the stream
|
||||||
if (readTooManyBytes === 0) {
|
if (readTooManyBytes === 0) {
|
||||||
outputStream.end(chunk);
|
outputStream.end(chunk);
|
||||||
|
@ -40,6 +39,7 @@ export default async function getFileFromDisks(disks: string[], { diskStart, off
|
||||||
const shortenedChunk = Buffer.alloc(shortenedLength, chunk);
|
const shortenedChunk = Buffer.alloc(shortenedLength, chunk);
|
||||||
outputStream.end(shortenedChunk);
|
outputStream.end(shortenedChunk);
|
||||||
curDisk.close();
|
curDisk.close();
|
||||||
|
curDisk.off('data', onData);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//Nowhere near the end, so just write normally
|
//Nowhere near the end, so just write normally
|
||||||
|
@ -52,10 +52,10 @@ export default async function getFileFromDisks(disks: string[], { diskStart, off
|
||||||
const onEnd = () => {
|
const onEnd = () => {
|
||||||
curDiskIndex += 1;
|
curDiskIndex += 1;
|
||||||
//End if we are at end of file or end of disks
|
//End if we are at end of file or end of disks
|
||||||
if (curDiskIndex >= disks.length || (localFileHeaderLength !== 0 && totalRead >= localFileHeaderLength + storedSize)) {
|
if (curDiskIndex >= disks.length || totalRead >= storedSize) {
|
||||||
outputStream.end();
|
outputStream.end();
|
||||||
} else {
|
} else {
|
||||||
curDisk = getStream(disks, curDiskIndex, 0, (localFileHeaderLength === 0) ? Infinity : localFileHeaderLength + storedSize - totalRead);
|
curDisk = createFileStream(disks, curDiskIndex, 0, storedSize - totalRead);
|
||||||
//set up new listeners for data and end
|
//set up new listeners for data and end
|
||||||
curDisk.on('data', onData);
|
curDisk.on('data', onData);
|
||||||
curDisk.on('end', onEnd);
|
curDisk.on('end', onEnd);
|
||||||
|
@ -67,9 +67,15 @@ export default async function getFileFromDisks(disks: string[], { diskStart, off
|
||||||
curDisk.on('end', onEnd);
|
curDisk.on('end', onEnd);
|
||||||
curDisk.on('error', onError);
|
curDisk.on('error', onError);
|
||||||
|
|
||||||
//Read local file header
|
|
||||||
localFileHeaderLength = await readLocalFileHeader(outputStream);
|
|
||||||
//now that local file header has been read, we will restrict length of stream to storedSize
|
|
||||||
|
|
||||||
return outputStream;
|
return outputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default async function getFileFromDisks(disks: string[], { diskStart, offset, storedSize }: IGetFileFromDisksOptions): Promise<stream.Readable> {
|
||||||
|
//read local file header
|
||||||
|
const headerStream = await getFullStream(disks, { diskStart, offset, storedSize: 30 });
|
||||||
|
const localFileHeaderLength = await readLocalFileHeader(headerStream);
|
||||||
|
headerStream.destroy(); //TODO
|
||||||
|
|
||||||
|
//read actual file
|
||||||
|
return getFullStream(disks, { diskStart, offset: offset + localFileHeaderLength, storedSize });
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ function waitReadableLength(inputStream: stream.Readable, minLength: number): Pr
|
||||||
* 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): Promise<number> {
|
export default async function readLocalFileHeader(inputStream: stream.Readable, skipAdditionalLength = false): Promise<number> {
|
||||||
let localFileHeader: Buffer = inputStream.read(30);
|
let localFileHeader: Buffer = inputStream.read(30);
|
||||||
if (localFileHeader === null) {
|
if (localFileHeader === null) {
|
||||||
//need to wait until data is ready for reading
|
//need to wait until data is ready for reading
|
||||||
|
@ -37,7 +37,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 (additionalLength > 0) {
|
if (skipAdditionalLength && additionalLength > 0) {
|
||||||
await waitReadableLength(inputStream, additionalLength);
|
await waitReadableLength(inputStream, additionalLength);
|
||||||
const tmpChunk = inputStream.read(additionalLength);
|
const tmpChunk = inputStream.read(additionalLength);
|
||||||
if (tmpChunk === null) {
|
if (tmpChunk === null) {
|
||||||
|
|
Loading…
Reference in a new issue