Browse Source

Refactor File class to include download progress and error handling

node16
Onja 12 months ago
parent
commit
d1052f693a
  1. 45
      src/models/File.js

45
src/models/File.js

@ -7,7 +7,6 @@ const https = require('https');
const exec = util.promisify(require('child_process').exec); const exec = util.promisify(require('child_process').exec);
const EventEmitter = require('events'); const EventEmitter = require('events');
const csv = require('csv-parser');
const slugify = require('slugify'); const slugify = require('slugify');
const dest = path.join(appRoot, 'public/csv'); const dest = path.join(appRoot, 'public/csv');
@ -22,7 +21,10 @@ function generateFilePath(filename) {
// Create a class File that extends EventEmitter // Create a class File that extends EventEmitter
class File extends EventEmitter { class File extends EventEmitter {
// Create a constructor that takes a url as a parameter /**
* Create a new File instance
* @param {string} url
*/
constructor(url) { constructor(url) {
super(); super();
this.url = url; this.url = url;
@ -30,7 +32,10 @@ class File extends EventEmitter {
// Create a download method that downloads the file from the url /**
* Download a file from a url
* @returns {Promise<string>} filepath
*/
async download() { async download() {
const url = URL.parse(this.url); const url = URL.parse(this.url);
this.filename = slugify(url.hostname, { lower: true }); this.filename = slugify(url.hostname, { lower: true });
@ -46,13 +51,41 @@ class File extends EventEmitter {
file.on('error', (err) => { file.on('error', (err) => {
fs.unlink(filepath, () => { fs.unlink(filepath, () => {
// Emit a download.error event with the error // Emit a download.error event with the error
this.emit('download.error', { url: this.url, filepath: this.filepath, error: err, type: 'file' }); this.emit('download.error', { url: this.url, filepath: this.filepath, error: err.message, type: 'file' });
}); });
}); });
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request request
.get(url.href, (response) => { .get(url.href, (response) => {
// Check if response is valid
if (response.statusCode !== 200) {
// Emit a download.error event with the error
this.emit('download.error', { url: this.url, filepath: this.filepath, error: response.statusMessage, type: 'response' });
return reject(response.statusMessage);
}
// Get the content length and parse it to an integer
const contentLength = parseInt(response.headers['content-length'], 10);
const step = Math.floor(contentLength / 100);
let stepLimit = step;
// Create a variable to hold the downloaded size
let downloaded = 0;
// Handle response data
response.on('data', (chunk) => {
// Add the size of the chunk to the downloaded variable
downloaded += chunk.length;
// Check if the downloaded size is bigger than the step limit
if (downloaded > stepLimit) {
// Emit a download.progress event with the url, filepath and downloaded size
this.emit('download.progress', { url: this.url, filepath: this.filepath, percentage: Math.floor((downloaded / contentLength) * 100) });
stepLimit += step;
}
});
response.pipe(file); response.pipe(file);
file.on('finish', () => { file.on('finish', () => {
@ -66,10 +99,12 @@ class File extends EventEmitter {
.on('error', (err) => { .on('error', (err) => {
fs.unlink(filepath, () => { fs.unlink(filepath, () => {
// Emit a download.error event with the error // Emit a download.error event with the error
this.emit('download.error', { url: this.url, filepath: this.filepath, error: err, type: 'request' }); this.emit('download.error', { url: this.url, filepath: this.filepath, error: err.message, type: 'request' });
reject(err.message); reject(err.message);
}); });
}); });
}); });
} }
} }
module.exports = File;
Loading…
Cancel
Save