Last active
March 4, 2021 07:23
-
-
Save hayesgm/af61cc65f2ade6552296a34c1c3fa976 to your computer and use it in GitHub Desktop.
Download File JS (No Deps)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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