From 7febbbd89da92aa4dfcf84eab69023e3b3b6337b Mon Sep 17 00:00:00 2001 From: calebboyd Date: Sun, 2 Apr 2023 12:06:26 -0500 Subject: [PATCH] feat: stream zip files to destination binary --- src/compiler.ts | 43 +++++++++++++++++++++++++--------------- src/fs/bundle.ts | 17 ++++------------ src/patches/boot-nexe.ts | 7 ++++--- 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index cc9cc47..65c96cb 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -16,9 +16,11 @@ import { } from './util' import { NexeOptions, version } from './options' import { NexeTarget } from './target' +import { PassThrough, Readable, Stream, Transform } from 'stream' import MultiStream = require('multistream') import { Bundle, toStream } from './fs/bundle' import { File } from 'resolve-dependencies' +import { FactoryStream, LazyStream } from 'multistream' const isBsd = Boolean(~process.platform.indexOf('bsd')) const make = isWindows ? 'vcbuild.bat' : isBsd ? 'gmake' : 'make' @@ -287,25 +289,34 @@ export class NexeCompiler { return [this.shims.join(''), this.startup].join(';') } - private async _assembleDeliverable(binary: NodeJS.ReadableStream) { + private async _assembleDeliverable(binary: Readable) { if (!this.options.mangle) { return binary } + const launchCode = this.code() + const vfsStream = await this.bundle.toStream() + let vfsSize = 0 + const vfsSum = new Transform({ + transform(chunk, _enc, cb) { + chunk && (vfsSize += chunk.length) + cb(null, chunk) + }, + }) + const onEnd = new Promise((resolve) => vfsSum.once('end', resolve)) + const streams = [binary, toStream(launchCode), vfsStream.pipe(vfsSum)] - const code = this.code(), - codeSize = Buffer.byteLength(code), - lengths = Buffer.from(Array(16)) - - const bundleBuffer = await this.bundle.toBuffer() - - lengths.writeDoubleLE(codeSize, 0) - lengths.writeDoubleLE(bundleBuffer.length, 8) - - return new (MultiStream as any)([ - binary, - toStream(code), - toStream(bundleBuffer), - toStream(Buffer.concat([Buffer.from(''), lengths])), - ]) + let done = false + return new MultiStream(async (cb) => { + if (done) cb(null, null) + else if (streams.length) cb(null, streams.shift() as Readable) + else { + done = true + await onEnd + const trailers = Buffer.alloc(16) + trailers.writeDoubleLE(Buffer.byteLength(launchCode), 0) + trailers.writeDoubleLE(vfsSize, 8) + cb(null, toStream(Buffer.concat([Buffer.from(''), trailers]))) + } + }) } } diff --git a/src/fs/bundle.ts b/src/fs/bundle.ts index 74588d7..f206b6e 100644 --- a/src/fs/bundle.ts +++ b/src/fs/bundle.ts @@ -1,11 +1,7 @@ -import * as fs from 'fs' -import { promisify } from 'util' import { relative } from 'path' import { Readable } from 'stream' -import { argv } from '../options' import { File } from 'resolve-dependencies' -import MultiStream = require('multistream') -const archiver: any = require('archiver') +import archiver from 'archiver' function makeRelativeToZip(cwd: string, path: string) { return '/snapshot/' + relative(cwd, path) @@ -45,13 +41,8 @@ export class Bundle { } } - public async toBuffer(): Promise { - this.zip.finalize() - const zipData: Buffer[] = [] - this.zip.on('data', (data: Buffer) => zipData.push(data)) - return await new Promise((resolve, reject) => { - this.zip.on('error', (error: Error) => reject(error)) - this.zip.on('end', () => resolve(Buffer.concat(zipData))) - }) + public async toStream(): Promise { + await this.zip.finalize() + return this.zip } } diff --git a/src/patches/boot-nexe.ts b/src/patches/boot-nexe.ts index 06f8f4e..bbc3110 100644 --- a/src/patches/boot-nexe.ts +++ b/src/patches/boot-nexe.ts @@ -1,14 +1,15 @@ const fs = require('fs'), fd = fs.openSync(process.execPath, 'r'), stat = fs.statSync(process.execPath), - tailSize = Math.min(stat.size, 16000), + tailSize = Math.min(stat.size, 4096), tailWindow = Buffer.from(Array(tailSize)) fs.readSync(fd, tailWindow, 0, tailSize, stat.size - tailSize) const footerPosition = tailWindow.indexOf('') -if (footerPosition == -1) { - throw 'Invalid Nexe binary' +if (footerPosition === -1) { + process.stderr.write('Invalid Nexe binary') + process.exit(1) } const footer = tailWindow.slice(footerPosition, footerPosition + 32),