zephyr-agent
Version:
Zephyr plugin agent
154 lines (153 loc) • 5.84 kB
JavaScript
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