UNPKG

@capawesome/cli

Version:

The Capawesome Cloud Command Line Interface (CLI) to manage Live Updates and more.

137 lines (136 loc) 5.48 kB
import { MAX_CONCURRENT_UPLOADS } from '../config/index.js'; import authorizationService from '../services/authorization-service.js'; import httpClient from '../utils/http-client.js'; import FormData from 'form-data'; class AppBundleFilesServiceImpl { httpClient; constructor(httpClient) { this.httpClient = httpClient; } async create(dto) { const sizeInBytes = dto.buffer.byteLength; const useMultipartUpload = sizeInBytes >= 50 * 1024 * 1024; // 50 MB const formData = new FormData(); formData.append('checksum', dto.checksum); if (!useMultipartUpload) { formData.append('file', dto.buffer, { filename: dto.name }); } if (dto.href) { formData.append('href', dto.href); } formData.append('mimeType', dto.mimeType); formData.append('name', dto.name); if (dto.signature) { formData.append('signature', dto.signature); } formData.append('sizeInBytes', sizeInBytes.toString()); const response = await this.httpClient.post(`/v1/apps/${dto.appId}/bundles/${dto.appBundleId}/files`, formData, { headers: { Authorization: `Bearer ${authorizationService.getCurrentAuthorizationToken()}`, ...formData.getHeaders(), }, }); if (useMultipartUpload) { await this.upload({ appBundleFileId: response.data.id, appBundleId: dto.appBundleId, appId: dto.appId, buffer: dto.buffer, name: dto.name, checksum: dto.checksum, }); } return response.data; } async completeUpload(dto) { return this.httpClient .post(`/v1/apps/${dto.appId}/bundles/${dto.appBundleId}/files/${dto.appBundleFileId}/upload?action=mpu-complete&uploadId=${dto.uploadId}`, { parts: dto.parts, }, { headers: { Authorization: `Bearer ${authorizationService.getCurrentAuthorizationToken()}`, }, }) .then((response) => response.data); } async createUpload(dto) { const response = await this.httpClient.post(`/v1/apps/${dto.appId}/bundles/${dto.appBundleId}/files/${dto.appBundleFileId}/upload?action=mpu-create`, {}, { headers: { Authorization: `Bearer ${authorizationService.getCurrentAuthorizationToken()}`, }, }); return response.data; } async createUploadPart(dto) { const formData = new FormData(); formData.append('blob', dto.buffer, { filename: dto.name }); formData.append('partNumber', dto.partNumber.toString()); return this.httpClient .put(`/v1/apps/${dto.appId}/bundles/${dto.appBundleId}/files/${dto.appBundleFileId}/upload?action=mpu-uploadpart&uploadId=${dto.uploadId}`, formData, { headers: { Authorization: `Bearer ${authorizationService.getCurrentAuthorizationToken()}`, ...formData.getHeaders(), }, }) .then((response) => response.data); } async createUploadParts(dto) { const uploadedParts = []; const partSize = 10 * 1024 * 1024; // 10 MB. 5 MB is the minimum part size except for the last part. const totalParts = Math.ceil(dto.buffer.byteLength / partSize); let partNumber = 0; const uploadNextPart = async () => { if (partNumber >= totalParts) { return; } partNumber++; const start = (partNumber - 1) * partSize; const end = Math.min(start + partSize, dto.buffer.byteLength); const partBuffer = dto.buffer.subarray(start, end); const uploadedPart = await this.createUploadPart({ appBundleFileId: dto.appBundleFileId, appBundleId: dto.appBundleId, appId: dto.appId, buffer: partBuffer, name: dto.name, partNumber, uploadId: dto.uploadId, }); uploadedParts.push(uploadedPart); await uploadNextPart(); }; const uploadPartPromises = Array.from({ length: MAX_CONCURRENT_UPLOADS }); for (let i = 0; i < MAX_CONCURRENT_UPLOADS; i++) { uploadPartPromises[i] = uploadNextPart(); } await Promise.all(uploadPartPromises); return uploadedParts; } async upload(dto) { // 1. Create a multipart upload const { uploadId } = await this.createUpload({ appBundleFileId: dto.appBundleFileId, appBundleId: dto.appBundleId, appId: dto.appId, }); // 2. Upload the file in parts const parts = await this.createUploadParts({ appBundleFileId: dto.appBundleFileId, appBundleId: dto.appBundleId, appId: dto.appId, buffer: dto.buffer, name: dto.name, uploadId, }); // 3. Complete the upload await this.completeUpload({ appBundleFileId: dto.appBundleFileId, appBundleId: dto.appBundleId, appId: dto.appId, parts, uploadId, }); } } const appBundleFilesService = new AppBundleFilesServiceImpl(httpClient); export default appBundleFilesService;