UNPKG

sfdx-hardis

Version:

Swiss-army-knife Toolbox for Salesforce. Allows you to define a complete CD/CD Pipeline. Orchestrate base commands and assist users with interactive wizards

86 lines 3.64 kB
import { SfError } from "@salesforce/core"; import fs from 'fs-extra'; import ora from "ora"; import * as path from "path"; import { createTempDir } from "./index.js"; import makeFetchHappen from 'make-fetch-happen'; export class FileDownloader { conn; downloadUrl; outputFile = null; fetchOptions = {}; label; constructor(downloadUrl, options) { this.conn = options.conn || null; this.downloadUrl = downloadUrl; this.outputFile = options.outputFile || null; this.label = options?.label === 'file' ? (path.relative(process.cwd(), this.outputFile || "")) || this.downloadUrl : options?.label === 'both' ? `${this.outputFile} from ${this.downloadUrl}` : this.downloadUrl; // Build fetch options for HTTP calls to retrieve document files this.fetchOptions = options.fetchOptions || { method: 'GET', headers: { Authorization: 'Bearer ' + this.conn.accessToken, 'Content-Type': 'blob', // "X-PrettyPrint": '1' }, retry: { retries: 20, factor: 3, randomize: true, }, }; } async download() { const spinnerCustom = ora({ text: `Downloading ${this.label}...`, spinner: 'moon', }).start(); if (this.outputFile == null) { const tempDir = await createTempDir(); this.outputFile = path.join(tempDir, Math.random().toString(36).substring(7)); } try { this.fetchOptions.onRetry = (cause) => { spinnerCustom.text = `Retrying ${this.label} (${cause})...`; }; const fetchRes = await makeFetchHappen(this.downloadUrl, this.fetchOptions); if (!fetchRes.ok) { throw new SfError(`Fetch error: ${JSON.stringify(fetchRes.body)}`); } const stream = fs.createWriteStream(this.outputFile); const totalSize = Number(fetchRes.headers.get('content-length')); let downloadedSize = 0; // Set up piping first fetchRes.body.pipe(stream); fetchRes.body.on('data', (chunk) => { downloadedSize += chunk.length; const percentComplete = totalSize ? (downloadedSize / totalSize * 100).toFixed(2) : null; spinnerCustom.text = totalSize ? `Downloaded ${downloadedSize} bytes of ${totalSize} bytes (${percentComplete}%) of ${this.label}` : `Downloaded ${downloadedSize} bytes of ${this.label}`; }); // Handle end of download, or error await new Promise((resolve, reject) => { fetchRes.body.on("error", () => reject()); stream.on("error", () => reject()); stream.on("finish", () => resolve()); }); const fileExists = await fs.exists(this.outputFile); if (!fileExists) { throw new SfError(`Download error: Download stream ok but no created file at ${this.outputFile}`); } spinnerCustom.succeed(`Downloaded ${this.label}`); stream.destroy(); } catch (err) { spinnerCustom.fail(`Error while downloading ${this.downloadUrl}: ${err.message}`); return { success: false, outputFile: this.outputFile, error: err }; } return { success: true, outputFile: this.outputFile }; } } //# sourceMappingURL=fileDownloader.js.map