UNPKG

zephyr-agent

Version:
154 lines (153 loc) • 5.84 kB
import "node:module"; import { forEachLimit } from "zephyr-edge-contract"; import { zeUploadSnapshot } from "../edge-actions/index.mjs"; import { update_hash_list } from "../edge-hash-list/distributed-hash-control.mjs"; import { getApplicationConfiguration } from "../edge-requests/get-application-configuration.mjs"; import { ZeErrors, ZephyrError } from "../errors/index.mjs"; import { makeRequest } from "../http/http-request.mjs"; import { ze_log } from "../logging/index.mjs"; import { white, whiteBright } from "../logging/picocolor.mjs"; import { uploadAssets, uploadBuildStatsAndEnableEnvs } from "./upload-base/index.mjs"; const AWS_MAX_BODY_SIZE = 20971520; const AWS_UPLOAD_CONCURRENCY = 6; async function awsUploadStrategy(zephyr_engine, { snapshot, getDashData, assets: { assetsMap, missingAssets } }) { const snapshotSize = Buffer.byteLength(JSON.stringify(snapshot), 'utf8'); if (snapshotSize > AWS_MAX_BODY_SIZE) { const opts = { entity_name: 'snapshot', entity_size: snapshotSize, max_allowed_size: AWS_MAX_BODY_SIZE }; throw new ZephyrError(ZeErrors.ERR_MAX_PAYLOAD_SIZE_EXCEEDED, opts); } for (const missingAsset of missingAssets)if (missingAsset.size > AWS_MAX_BODY_SIZE) { const opts = { entity_name: missingAsset.path, entity_size: missingAsset.size, max_allowed_size: AWS_MAX_BODY_SIZE }; throw new ZephyrError(ZeErrors.ERR_MAX_PAYLOAD_SIZE_EXCEEDED, opts); } await createBucket(zephyr_engine.application_uid); await aws_upload_strategy_uploadAssets(zephyr_engine, { assetsMap, missingAssets }).catch((error)=>{ if (error.cause?.template?.content === 'Not Implemented') return uploadAssets(zephyr_engine, { assetsMap, missingAssets }); throw error; }); const versionUrl = await zeUploadSnapshot(zephyr_engine, { snapshot }); await uploadBuildStatsAndEnableEnvs(zephyr_engine, { getDashData, versionUrl }); return versionUrl; } async function createBucket(application_uid) { const { EDGE_URL, jwt } = await getApplicationConfiguration({ application_uid }); const options = { method: 'POST', headers: { can_write_jwt: jwt } }; const url = new URL('/upload', EDGE_URL); url.searchParams.append('type', 'bucket'); const [ok, cause] = await makeRequest(url, options); if (!ok) throw new ZephyrError(ZeErrors.ERR_FAILED_UPLOAD, { type: 'bucket', cause }); ze_log.snapshot('Done: bucket initialized...'); } async function aws_upload_strategy_uploadAssets(zephyr_engine, { assetsMap, missingAssets }) { const upload_success = await zeUploadAssets(zephyr_engine, { missingAssets, assetsMap }); if (upload_success && missingAssets.length) { const application_uid = zephyr_engine.application_uid; await update_hash_list(application_uid, assetsMap); } return upload_success; } async function zeUploadAssets(zephyr_engine, { missingAssets, assetsMap }) { const count = Object.keys(assetsMap).length; const logger = await zephyr_engine.logger; const appConfig = await zephyr_engine.application_configuration; if (0 === missingAssets.length) { logger({ level: 'info', action: 'snapshot:assets:upload:empty', message: `No assets to upload, ${white('skipping')}...` }); return true; } const start = Date.now(); let totalSize = 0; await forEachLimit(missingAssets.map((asset)=>()=>upload_missing_asset(asset)), AWS_UPLOAD_CONCURRENCY); logger({ level: 'info', action: 'snapshot:assets:upload:done', message: white(`(${whiteBright(missingAssets.length.toString())}/${white(count.toString())} assets uploaded in ${whiteBright((Date.now() - start).toString())}ms, ${whiteBright(totalSize.toFixed(2))}kb)`) }); return true; async function upload_missing_asset(asset) { const start = Date.now(); const assetWithBuffer = assetsMap[asset.hash]; const assetSize = assetWithBuffer?.buffer?.length / 1024; const result = await getUploadUrl({ hash: asset.hash, asset: assetWithBuffer }, appConfig); if (result.message) return; const [ok, cause] = await makeRequest(result.url, { method: 'PUT', headers: { 'Content-Type': result.contentType } }, asset.buffer); if (!ok) throw new ZephyrError(ZeErrors.ERR_FAILED_UPLOAD, { type: 'file', cause }); const fileUploaded = Date.now() - start; totalSize += assetSize; ze_log.upload(`file ${asset.path} uploaded in ${fileUploaded}ms (${assetSize.toFixed(2)}kb)`); } async function getUploadUrl({ hash, asset }, { EDGE_URL, jwt }) { const type = 'uploadUrl'; const options = { method: 'POST', headers: { 'x-file-size': asset.size.toString(), 'x-file-path': asset.path, can_write_jwt: jwt, 'Content-Type': 'application/octet-stream' } }; const [ok, cause, data] = await makeRequest({ path: '/upload', base: EDGE_URL, query: { type, hash, filename: asset.path } }, options); if (!ok) throw new ZephyrError(ZeErrors.ERR_FAILED_UPLOAD, { type, cause }); return data; } } export { awsUploadStrategy, createBucket }; //# sourceMappingURL=aws-upload.strategy.mjs.map