Skip to content
This repository has been archived by the owner on Oct 25, 2023. It is now read-only.

Commit

Permalink
feat: Add helper for files download (#184)
Browse files Browse the repository at this point in the history
  • Loading branch information
mykola-mokhnach committed May 3, 2020
1 parent 92b20fb commit d76b3ae
Showing 1 changed file with 89 additions and 5 deletions.
94 changes: 89 additions & 5 deletions lib/net.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
import { createReadStream } from 'fs';
import _ from 'lodash';
import fs from './fs';
import url from 'url';
import B from 'bluebird';
import { toReadableSizeString } from './util';
import log from './logger';
import request from 'request-promise';
import Ftp from 'jsftp';
import Timer from './timing';
import axios from 'axios';
import request from 'request-promise';


function toAxiosAuth (auth) {
if (!_.isPlainObject(auth)) {
return null;
}

const axiosAuth = {
username: auth.username || auth.user,
password: auth.password || auth.pass,
};
return (axiosAuth.username && axiosAuth.password) ? axiosAuth : null;
}


async function uploadFileToHttp (remoteUrl, uploadOptions = {}) {
Expand All @@ -16,7 +30,7 @@ async function uploadFileToHttp (remoteUrl, uploadOptions = {}) {
`Response body: ${JSON.stringify(response.body)}`;
log.debug(responseDebugMsg);
if (response.statusCode >= 400) {
throw new Error(`Cannot upload the recorded media to '${remoteUrl.href}'. ${responseDebugMsg}`);
throw new Error(`Cannot upload the file to '${remoteUrl.href}'. ${responseDebugMsg}`);
}
}

Expand Down Expand Up @@ -53,7 +67,7 @@ async function uploadFile (localPath, remotePath, uploadOptions = {}) {
if (['http:', 'https:'].includes(remoteUrl.protocol)) {
await uploadFileToHttp(remoteUrl, uploadOptions);
} else if (remoteUrl.protocol === 'ftp:') {
await uploadFileToFtp(createReadStream(localPath), remoteUrl, uploadOptions);
await uploadFileToFtp(fs.createReadStream(localPath), remoteUrl, uploadOptions);
} else {
throw new Error(`Cannot upload the file at '${localPath}' to '${remotePath}'. ` +
`Unsupported remote protocol '${remoteUrl.protocol}'. ` +
Expand All @@ -62,4 +76,74 @@ async function uploadFile (localPath, remotePath, uploadOptions = {}) {
log.info(`Uploaded '${localPath}' of ${toReadableSizeString(size)} size in ${timer.getDuration().asSeconds.toFixed(3)}s`);
}

export { uploadFile };
/**
* @typedef {Object} DownloadOptions
* @property {boolean} isMetered [true] - Whether to log the actual download performance
* (e.g. timings and speed)
* @property {Object} auth - An object containing optional HTTP basic auth
* credentials. Possible properties: `user`/`username` and `pass`/`password`
* @property {number} timeout [5000] - The actual request timeout in milliseconds
* @property {Object} headers - Request headers mapping
*/

/**
* Downloads the given file via HTTP(S)
*
* @param {string} remoteUrl - The remote url
* @param {string} dstPath - The local path to download the file to
* @param {?DownloadOptions} downloadOptions
* @throws {Error} If download operation fails
*/
async function downloadFile (remoteUrl, dstPath, downloadOptions = {}) {
const {
isMetered = true,
auth,
timeout = 5000,
headers,
} = downloadOptions;

const requestOpts = {
url: remoteUrl,
responseType: 'stream',
timeout,
};
const axiosAuth = toAxiosAuth(auth);
if (axiosAuth) {
requestOpts.auth = axiosAuth;
}
if (_.isPlainObject(headers)) {
requestOpts.headers = headers;
}

const timer = new Timer().start();
try {
const writer = fs.createWriteStream(dstPath);
const responseStream = (await axios(requestOpts)).data;
responseStream.pipe(writer);

await new B((resolve, reject) => {
responseStream.once('error', reject);
writer.once('finish', resolve);
writer.once('error', (e) => {
responseStream.unpipe(writer);
reject(e);
});
});
} catch (err) {
throw new Error(`Cannot download the file from ${remoteUrl}: ${err.message}`);
}
if (!isMetered) {
return;
}

const secondsElapsed = timer.getDuration().asSeconds;
const {size} = await fs.stat(dstPath);
log.debug(`${remoteUrl} (${toReadableSizeString(size)}) ` +
`has been downloaded to '${dstPath}' in ${secondsElapsed.toFixed(3)}s`);
if (secondsElapsed >= 2) {
const bytesPerSec = Math.floor(size / secondsElapsed);
log.debug(`Approximate download speed: ${toReadableSizeString(bytesPerSec)}/s`);
}
}

export { uploadFile, downloadFile };

0 comments on commit d76b3ae

Please sign in to comment.