UNPKG

@agoric/deploy-script-support

Version:

Helpers and other support for writing deploy scripts

75 lines (64 loc) 2.54 kB
// @ts-check import { E } from '@endo/far'; import { ZipReader } from '@endo/zip'; import { encodeBase64, decodeBase64 } from '@endo/base64'; import crypto from 'crypto'; const computeSha512 = bytes => { const hash = crypto.createHash('sha512'); hash.update(bytes); return hash.digest().toString('hex'); }; export const installInPieces = async ( bundle, bundlerOrGetter, { maxBytesInFlight = 800_000, log = console.log, persist = false } = {}, ) => { const bundler = typeof bundlerOrGetter === 'function' ? bundlerOrGetter() : bundlerOrGetter; // It would be nice to detect evaluation errors early like this: // await importBundle(bundle, { endowments }); // but importBundle only works inside SwingSet; checking here // may run into stuff like VatData not being available. const { endoZipBase64, ...bundleShell } = bundle; const zip = new ZipReader(new Uint8Array(decodeBase64(endoZipBase64))); const candidates = []; for await (const [_name, entry] of zip.files.entries()) { const hash = computeSha512(entry.content); candidates.push(hash); } const preloaded = await E(bundler).preFilter(candidates); log('preloaded', preloaded.length, 'out of', candidates.length); const preloadSet = new Set(preloaded); let approxBytesInFlight = 0; let inFlightAdditions = []; for await (const [name, entry] of zip.files.entries()) { if (approxBytesInFlight >= maxBytesInFlight) { log( `waiting for ${inFlightAdditions.length} (~${approxBytesInFlight}B) additions...`, ); await Promise.all(inFlightAdditions); approxBytesInFlight = 0; inFlightAdditions = []; } const hash = computeSha512(entry.content); if (preloadSet.has(hash)) { // log('preloaded', name, entry.content.length, '...'); approxBytesInFlight += name.length + hash.length; inFlightAdditions.push(E(bundler).addByRef(name, hash)); } else { log('adding', name, entry.content.length, '...'); const encodedContent = encodeBase64(entry.content); approxBytesInFlight += name.length + encodedContent.length; inFlightAdditions.push(E(bundler).add(name, encodedContent, hash)); } } log( `waiting for ${inFlightAdditions.length} (~${approxBytesInFlight}B) final additions...`, ); await Promise.all(inFlightAdditions); await (persist && E(bundler).persist()); log('installing...'); const installation = await E(bundler).install(bundleShell); // console.log({ installation }); return installation; };