Socket
Socket
Sign inDemoInstall

node-downloader-helper

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-downloader-helper - npm Package Compare versions

Comparing version 1.0.8 to 1.0.9

260

dist/index.js

@@ -65,8 +65,11 @@ 'use strict';

_this.url = url;
_this.url = _this.requestURL = url;
_this.state = DH_STATES.IDLE;
_this.__defaultOpts = {
method: 'GET',
headers: {},
fileName: '',
override: false,
fileName: ''
httpRequestOptions: {},
httpsRequestOptions: {}
};

@@ -91,4 +94,4 @@

_this.__filePath = '';
_this.__options = _this.__getOptions('GET', url, _this.__opts.headers);
_this.__protocol = url.indexOf('https://') > -1 ? https : http;
_this.__options = _this.__getOptions(_this.__opts.method, url, _this.__opts.headers);
_this.__initProtocol(url);
return _this;

@@ -103,3 +106,3 @@ }

return new Promise(function (resolve, reject) {
if (!_this2.__isRedirected) {
if (!_this2.__isRedirected && _this2.state !== _this2.__states.RESUMED) {
_this2.emit('start');

@@ -109,92 +112,5 @@ _this2.__setState(_this2.__states.STARTED);

_this2.__request = _this2.__protocol.request(_this2.__options, function (response) {
//Stats
if (!_this2.__isResumed) {
_this2.__total = parseInt(response.headers['content-length']);
_this2.__downloaded = 0;
_this2.__progress = 0;
}
// Start the Download
_this2.__request = _this2.__downloadRequest(resolve, reject);
// Handle Redirects
if (response.statusCode > 300 && response.statusCode < 400 && response.headers.hasOwnProperty('location') && response.headers.location) {
_this2.__isRedirected = true;
_this2.__initProtocol(response.headers.location);
return _this2.start().then(function () {
return resolve(true);
}).catch(function (err) {
_this2.__setState(_this2.__states.FAILED);
_this2.emit('error', err);
return reject(err);
});
}
// check if response is success
if (response.statusCode !== 200 && response.statusCode !== 206) {
var err = new Error('Response status was ' + response.statusCode);
_this2.emit('error', err);
return reject(err);
}
if (response.headers.hasOwnProperty('accept-ranges') && response.headers['accept-ranges'] !== 'none') {
_this2.__isResumable = true;
}
// Get Filename
if (response.headers.hasOwnProperty('content-disposition') && response.headers['content-disposition'].indexOf('filename=') > -1) {
var fileName = response.headers['content-disposition'];
fileName = fileName.trim();
fileName = fileName.substr(fileName.indexOf('filename=') + 9);
fileName = fileName.replace(new RegExp('"', 'g'), '');
_this2.__fileName = fileName;
} else {
_this2.__fileName = path.basename(URL.parse(_this2.url).pathname);
}
// Create File
_this2.__fileName = _this2.__opts.fileName ? _this2.__opts.fileName : _this2.__fileName;
_this2.__filePath = path.join(_this2.__destFolder, _this2.__fileName);
if (!_this2.__opts.override) {
_this2.__filePath = _this2.__uniqFileNameSync(_this2.__filePath);
}
_this2.__fileStream = fs.createWriteStream(_this2.__filePath, _this2.__isResumed ? { 'flags': 'a' } : {});
// Start Downloading
_this2.emit('download');
_this2.__isResumed = false;
_this2.__isRedirected = false;
_this2.__setState(_this2.__states.DOWNLOADING);
_this2.__statsEstimate.time = new Date();
response.pipe(_this2.__fileStream);
response.on('data', function (chunk) {
return _this2.__calculateStats(chunk.length);
});
_this2.__fileStream.on('finish', function () {
_this2.__fileStream.close(function (_err) {
if (_err) {
return reject(_err);
}
if (_this2.state !== _this2.__states.PAUSED && _this2.state !== _this2.__states.STOPPED) {
_this2.__setState(_this2.__states.FINISHED);
_this2.emit('end');
}
return resolve(true);
});
});
_this2.__fileStream.on('error', function (err) {
_this2.__fileStream.close(function () {
fs.unlink(_this2.__filePath, function () {
return reject(err);
});
});
_this2.__setState(_this2.__states.FAILED);
_this2.emit('error', err);
return reject(err);
});
});
// Error Handling

@@ -233,4 +149,2 @@ _this2.__request.on('error', function (err) {

value: function resume() {
var _this3 = this;
this.__setState(this.__states.RESUMED);

@@ -243,5 +157,3 @@ if (this.__isResumable) {

this.emit('resume');
return this.start().then(function () {
return _this3.__isResumable;
});
return this.start();
}

@@ -251,3 +163,3 @@ }, {

value: function stop() {
var _this4 = this;
var _this3 = this;

@@ -262,16 +174,16 @@ if (this.__request) {

return new Promise(function (resolve, reject) {
fs.access(_this4.__filePath, function (_accessErr) {
fs.access(_this3.__filePath, function (_accessErr) {
// if can't access, probably is not created yet
if (_accessErr) {
_this4.emit('stop');
_this3.emit('stop');
return resolve(true);
}
fs.unlink(_this4.__filePath, function (_err) {
fs.unlink(_this3.__filePath, function (_err) {
if (_err) {
_this4.__setState(_this4.__states.FAILED);
_this4.emit('error', _err);
_this3.__setState(_this3.__states.FAILED);
_this3.emit('error', _err);
return reject(_err);
}
_this4.emit('stop');
_this3.emit('stop');
resolve(true);

@@ -283,2 +195,125 @@ });

}, {
key: 'isResumable',
value: function isResumable() {
return this.__isResumable;
}
}, {
key: '__downloadRequest',
value: function __downloadRequest(resolve, reject) {
var _this4 = this;
return this.__protocol.request(this.__options, function (response) {
//Stats
if (!_this4.__isResumed) {
_this4.__total = parseInt(response.headers['content-length']);
_this4.__downloaded = 0;
_this4.__progress = 0;
}
// Handle Redirects
if (response.statusCode > 300 && response.statusCode < 400 && response.headers.hasOwnProperty('location') && response.headers.location) {
_this4.__isRedirected = true;
_this4.__initProtocol(response.headers.location);
return _this4.start().then(function () {
return resolve(true);
}).catch(function (err) {
_this4.__setState(_this4.__states.FAILED);
_this4.emit('error', err);
return reject(err);
});
}
// check if response is success
if (response.statusCode !== 200 && response.statusCode !== 206) {
var err = new Error('Response status was ' + response.statusCode);
_this4.emit('error', err);
return reject(err);
}
if (response.headers.hasOwnProperty('accept-ranges') && response.headers['accept-ranges'] !== 'none') {
_this4.__isResumable = true;
}
_this4.__startDownload(response, resolve, reject);
});
}
}, {
key: '__startDownload',
value: function __startDownload(response, resolve, reject) {
var _this5 = this;
this.__fileName = this.__getFileNameFromHeaders(response.headers);
this.__filePath = this.__getFilePath(this.__fileName);
this.__fileStream = fs.createWriteStream(this.__filePath, this.__isResumed ? { 'flags': 'a' } : {});
// Start Downloading
this.emit('download');
this.__isResumed = false;
this.__isRedirected = false;
this.__setState(this.__states.DOWNLOADING);
this.__statsEstimate.time = new Date();
response.pipe(this.__fileStream);
response.on('data', function (chunk) {
return _this5.__calculateStats(chunk.length);
});
this.__fileStream.on('finish', function () {
_this5.__fileStream.close(function (_err) {
if (_err) {
return reject(_err);
}
if (_this5.state !== _this5.__states.PAUSED && _this5.state !== _this5.__states.STOPPED) {
_this5.__setState(_this5.__states.FINISHED);
_this5.emit('end');
}
return resolve(true);
});
});
this.__fileStream.on('error', function (err) {
_this5.__fileStream.close(function () {
fs.unlink(_this5.__filePath, function () {
return reject(err);
});
});
_this5.__setState(_this5.__states.FAILED);
_this5.emit('error', err);
return reject(err);
});
}
}, {
key: '__getFileNameFromHeaders',
value: function __getFileNameFromHeaders(headers) {
var fileName = '';
if (this.__opts.fileName) {
return this.__opts.fileName;
}
// Get Filename
if (headers.hasOwnProperty('content-disposition') && headers['content-disposition'].indexOf('filename=') > -1) {
fileName = headers['content-disposition'];
fileName = fileName.trim();
fileName = fileName.substr(fileName.indexOf('filename=') + 9);
fileName = fileName.replace(new RegExp('"', 'g'), '');
} else {
fileName = path.basename(URL.parse(this.requestURL).pathname);
}
return fileName;
}
}, {
key: '__getFilePath',
value: function __getFilePath(fileName) {
var filePath = path.join(this.__destFolder, fileName);
if (!this.__opts.override && this.state !== this.__states.RESUMED) {
filePath = this.__uniqFileNameSync(filePath);
}
return filePath;
}
}, {
key: '__calculateStats',

@@ -369,5 +404,12 @@ value: function __calculateStats(receivedBytes) {

value: function __initProtocol(url) {
this.url = url;
this.__options = this.__getOptions('GET', url, this.__headers);
this.__protocol = url.indexOf('https://') > -1 ? https : http;
var defaultOpts = this.__getOptions(this.__opts.method, url, this.__headers);
this.requestURL = url;
if (url.indexOf('https://') > -1) {
this.__protocol = https;
this.__options = Object.assign({}, defaultOpts, this.__opts.httpsRequestOptions);
} else {
this.__protocol = http;
this.__options = Object.assign({}, defaultOpts, this.__opts.httpRequestOptions);
}
}

@@ -374,0 +416,0 @@ }, {

@@ -12,5 +12,4 @@ /*eslint no-console: ["error", { allow: ["log", "warn", "error"] }] */

module.exports.pauseTimer = function (_dl, wait) {
module.exports.pauseResumeTimer = function (_dl, wait) {
setTimeout(() => {
if (_dl.state === DH_STATES.FINISHED ||

@@ -24,8 +23,6 @@ _dl.state === DH_STATES.FAILED) {

.then(() => setTimeout(() => {
_dl.resume()
.then(isResumable => {
if (!isResumable) {
console.warn("This URL doesn't support resume, it will start from the beginning");
}
});
if (!_dl.isResumable()) {
console.warn("This URL doesn't support resume, it will start from the beginning");
}
return _dl.resume();
}, wait));

@@ -32,0 +29,0 @@

/*eslint no-console: ["error", { allow: ["log", "warn", "error"] }] */
const { DownloaderHelper } = require('../dist');
const { byteHelper, pauseTimer } = require('./helpers');
const { byteHelper, pauseResumeTimer } = require('./helpers');
const url = 'http://ipv4.download.thinkbroadband.com/1GB.zip';
// Options are optional
const pkg = require('../package.json');
// these are the default options
const options = {
headers : {}, // http headers ex: 'Authorization'
fileName: '', // custom filename when saved
override: false, //if true it will override the file, otherwise will append '(number)' to the end of file
method: 'GET', // Request Method Verb
// Custom HTTP Header ex: Authorization, User-Agent
headers: {
'user-agent': pkg.name + '@' + pkg.version
},
fileName: '', // Custom filename when saved
override: false, // if true it will override the file, otherwise will append '(number)' to the end of file
httpRequestOptions: {}, // Override the http request options
httpsRequestOptions: {} // Override the https request options, ex: to add SSL Certs
};
const dl = new DownloaderHelper(url, __dirname, options);

@@ -18,3 +26,3 @@

.on('stateChanged', state => console.log('State: ', state))
.once('download', () => pauseTimer(dl, 5000))
.once('download', () => pauseResumeTimer(dl, 5000))
.on('progress', stats => {

@@ -21,0 +29,0 @@ const progress = stats.progress.toFixed(1);

{
"name": "node-downloader-helper",
"version": "1.0.8",
"version": "1.0.9",
"description": "A simple http file downloader for node.js",

@@ -5,0 +5,0 @@ "main": "./dist/index.js",

@@ -15,2 +15,3 @@ # node-downloader-helper

- Supports http redirects
- Support custom native http request options
- Usable on vanilla nodejs, electron, nwjs

@@ -37,3 +38,23 @@ - Progress stats

## Options
Download Helper constructor also allow a 3rd parameter to set some options `constructor(url, destinationFolder, options)`,
these are the default values
```javascript
{
method: 'GET', // Request Method Verb
headers: {}, // Custom HTTP Header ex: Authorization, User-Agent
fileName: '', // Custom filename when saved
override: false, // if true it will override the file, otherwise will append '(number)' to the end of file
httpRequestOptions: {}, // Override the http request options
httpsRequestOptions: {} // Override the https request options, ex: to add SSL Certs
}
```
for `httpRequestOptions` the available options are detailed in here https://nodejs.org/api/http.html#http_http_request_options_callback
for `httpsRequestOptions` the available options are detailed in here https://nodejs.org/api/https.html#https_https_request_options_callback
## Methods

@@ -40,0 +61,0 @@

@@ -27,8 +27,11 @@ import { EventEmitter } from 'events';

this.url = url;
this.url = this.requestURL = url;
this.state = DH_STATES.IDLE;
this.__defaultOpts = {
method: 'GET',
headers: {},
fileName: '',
override: false,
fileName: ''
httpRequestOptions: {},
httpsRequestOptions: {}
};

@@ -53,6 +56,4 @@

this.__filePath = '';
this.__options = this.__getOptions('GET', url, this.__opts.headers);
this.__protocol = (url.indexOf('https://') > -1)
? https
: http;
this.__options = this.__getOptions(this.__opts.method, url, this.__opts.headers);
this.__initProtocol(url);
}

@@ -62,3 +63,4 @@

return new Promise((resolve, reject) => {
if (!this.__isRedirected) {
if (!this.__isRedirected &&
this.state !== this.__states.RESUMED) {
this.emit('start');

@@ -68,96 +70,5 @@ this.__setState(this.__states.STARTED);

this.__request = this.__protocol.request(this.__options, response => {
//Stats
if (!this.__isResumed) {
this.__total = parseInt(response.headers['content-length']);
this.__downloaded = 0;
this.__progress = 0;
}
// Start the Download
this.__request = this.__downloadRequest(resolve, reject);
// Handle Redirects
if (response.statusCode > 300 && response.statusCode < 400 &&
response.headers.hasOwnProperty('location') && response.headers.location) {
this.__isRedirected = true;
this.__initProtocol(response.headers.location);
return this.start()
.then(() => resolve(true))
.catch(err => {
this.__setState(this.__states.FAILED);
this.emit('error', err);
return reject(err);
});
}
// check if response is success
if (response.statusCode !== 200 && response.statusCode !== 206) {
const err = new Error('Response status was ' + response.statusCode);
this.emit('error', err);
return reject(err);
}
if (response.headers.hasOwnProperty('accept-ranges') &&
response.headers['accept-ranges'] !== 'none') {
this.__isResumable = true;
}
// Get Filename
if (response.headers.hasOwnProperty('content-disposition') &&
response.headers['content-disposition'].indexOf('filename=') > -1) {
let fileName = response.headers['content-disposition'];
fileName = fileName.trim();
fileName = fileName.substr(fileName.indexOf('filename=') + 9);
fileName = fileName.replace(new RegExp('"', 'g'), '');
this.__fileName = fileName;
} else {
this.__fileName = path.basename(URL.parse(this.url).pathname);
}
// Create File
this.__fileName = (this.__opts.fileName)
? this.__opts.fileName
: this.__fileName;
this.__filePath = path.join(this.__destFolder, this.__fileName);
if (!this.__opts.override) {
this.__filePath = this.__uniqFileNameSync(this.__filePath);
}
this.__fileStream = fs.createWriteStream(this.__filePath,
this.__isResumed ? { 'flags': 'a' } : {});
// Start Downloading
this.emit('download');
this.__isResumed = false;
this.__isRedirected = false;
this.__setState(this.__states.DOWNLOADING);
this.__statsEstimate.time = new Date();
response.pipe(this.__fileStream);
response.on('data', chunk => this.__calculateStats(chunk.length));
this.__fileStream.on('finish', () => {
this.__fileStream.close(_err => {
if (_err) {
return reject(_err);
}
if (this.state !== this.__states.PAUSED &&
this.state !== this.__states.STOPPED) {
this.__setState(this.__states.FINISHED);
this.emit('end');
}
return resolve(true);
});
});
this.__fileStream.on('error', err => {
this.__fileStream.close(() => {
fs.unlink(this.__filePath, () => reject(err));
});
this.__setState(this.__states.FAILED);
this.emit('error', err);
return reject(err);
});
});
// Error Handling

@@ -199,4 +110,3 @@ this.__request.on('error', err => {

this.emit('resume');
return this.start()
.then(() => this.__isResumable);
return this.start();
}

@@ -233,2 +143,117 @@

isResumable() {
return this.__isResumable;
}
__downloadRequest(resolve, reject) {
return this.__protocol.request(this.__options, response => {
//Stats
if (!this.__isResumed) {
this.__total = parseInt(response.headers['content-length']);
this.__downloaded = 0;
this.__progress = 0;
}
// Handle Redirects
if (response.statusCode > 300 && response.statusCode < 400 &&
response.headers.hasOwnProperty('location') && response.headers.location) {
this.__isRedirected = true;
this.__initProtocol(response.headers.location);
return this.start()
.then(() => resolve(true))
.catch(err => {
this.__setState(this.__states.FAILED);
this.emit('error', err);
return reject(err);
});
}
// check if response is success
if (response.statusCode !== 200 && response.statusCode !== 206) {
const err = new Error('Response status was ' + response.statusCode);
this.emit('error', err);
return reject(err);
}
if (response.headers.hasOwnProperty('accept-ranges') &&
response.headers['accept-ranges'] !== 'none') {
this.__isResumable = true;
}
this.__startDownload(response, resolve, reject);
});
}
__startDownload(response, resolve, reject) {
this.__fileName = this.__getFileNameFromHeaders(response.headers);
this.__filePath = this.__getFilePath(this.__fileName);
this.__fileStream = fs.createWriteStream(this.__filePath,
this.__isResumed ? { 'flags': 'a' } : {});
// Start Downloading
this.emit('download');
this.__isResumed = false;
this.__isRedirected = false;
this.__setState(this.__states.DOWNLOADING);
this.__statsEstimate.time = new Date();
response.pipe(this.__fileStream);
response.on('data', chunk => this.__calculateStats(chunk.length));
this.__fileStream.on('finish', () => {
this.__fileStream.close(_err => {
if (_err) {
return reject(_err);
}
if (this.state !== this.__states.PAUSED &&
this.state !== this.__states.STOPPED) {
this.__setState(this.__states.FINISHED);
this.emit('end');
}
return resolve(true);
});
});
this.__fileStream.on('error', err => {
this.__fileStream.close(() => {
fs.unlink(this.__filePath, () => reject(err));
});
this.__setState(this.__states.FAILED);
this.emit('error', err);
return reject(err);
});
}
__getFileNameFromHeaders(headers) {
let fileName = '';
if (this.__opts.fileName) {
return this.__opts.fileName;
}
// Get Filename
if (headers.hasOwnProperty('content-disposition') &&
headers['content-disposition'].indexOf('filename=') > -1) {
fileName = headers['content-disposition'];
fileName = fileName.trim();
fileName = fileName.substr(fileName.indexOf('filename=') + 9);
fileName = fileName.replace(new RegExp('"', 'g'), '');
} else {
fileName = path.basename(URL.parse(this.requestURL).pathname);
}
return fileName;
}
__getFilePath(fileName) {
let filePath = path.join(this.__destFolder, fileName);
if (!this.__opts.override && this.state !== this.__states.RESUMED) {
filePath = this.__uniqFileNameSync(filePath);
}
return filePath;
}
__calculateStats(receivedBytes) {

@@ -311,10 +336,15 @@ const currentTime = new Date();

__initProtocol(url) {
this.url = url;
this.__options = this.__getOptions('GET', url, this.__headers);
this.__protocol = (url.indexOf('https://') > -1)
? https
: http;
const defaultOpts = this.__getOptions(this.__opts.method, url, this.__headers);
this.requestURL = url;
if (url.indexOf('https://') > -1) {
this.__protocol = https;
this.__options = Object.assign({}, defaultOpts, this.__opts.httpsRequestOptions);
} else {
this.__protocol = http;
this.__options = Object.assign({}, defaultOpts, this.__opts.httpRequestOptions);
}
}
__uniqFileNameSync(path) {

@@ -321,0 +351,0 @@ if (typeof path !== 'string' || path === '') {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc