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
JavaScript
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