Skip to content

Instantly share code, notes, and snippets.

@hayesgm
Last active March 4, 2021 07:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hayesgm/af61cc65f2ade6552296a34c1c3fa976 to your computer and use it in GitHub Desktop.
Save hayesgm/af61cc65f2ade6552296a34c1c3fa976 to your computer and use it in GitHub Desktop.
Download File JS (No Deps)
const fs = require('fs').promises;
const path = require('path');
const http = require('http');
const https = require('https');
const { URL } = require('url');
function getOptions(url) {
let u = new URL(url);
return {
host: u.hostname,
path: u.pathname + u.search,
port: u.port || (u.protocol === 'https:' ? 443 : 80),
};
}
function download(url, path, options = {}, handle = null) {
let requestOptions = {
...getOptions(url),
...options,
};
return new Promise(async (resolve, reject) => {
let bail = false;
let f_;
let writeF = async (chunk) => {
if (!f_) {
f_ = handle ? await handle : await fs.open(path, 'w');
}
await f_.write(chunk);
}
let closeF = async () => {
if (f_) {
await f_.close();
}
}
let err = async (error) => {
bail = true;
await closeF();
reject(error);
};
let callback = (response) => {
if (response.statusCode === 301 || response.statusCode === 302) {
let location = response.headers['location'];
if (!location) {
err(new Error(`Redirect response does not include \`Location\` header`))
} else {
bail = true; // Nuts to you.
download(location, path, options, f_).then(() => resolve());
}
} else if (response.statusCode !== 200) {
err(new Error(`Server Response: ${JSON.stringify(response.statusCode)} retreiving ${url}`));
}
let promises = [];
response.on('data', async (chunk) => {
if (!bail) {
let promise = new Promise((resolve, reject) => {
Promise.all(promises).then(() => {
writeF(chunk).then(() => resolve());
});
});
promises.push(promise);
}
});
response.on('end', async () => {
if (!bail) {
await Promise.all(promises);
await closeF();
resolve(null);
}
});
}
let req = (options.port === 80 ? http : https).request(requestOptions, callback).end();
req.on('error', (e) => {
reject(e);
});
});
}
module.exports = {
download
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment