How to download big file & resume download after interuption in Node.js

Viewed 205

I wrote an app that downloads big zip files and extracts them using request and unzipper. I've also managed to show downloading progress but the requirement is that it has to be able to resume download after an interuption (internet goes down or the app closes, *for example how steam downloads games) and i cant figure it out, my code is kinda like this

const getInstallerFile = (installerfileURL, installerfilename, Possition, Directory) => {

// Variable to save downloading progress
var received_bytes = 0;
var total_bytes = 0;
percentage = 0;
var outStream = fs.createWriteStream(installerfilename);

request
    .get(installerfileURL)
    .on('error', function (err) {
        console.log("Download has stopped", err);
    })
    .on('response', function (data) {
        total_bytes = parseInt(data.headers['content-length']);
        console.log("download has started")

    })
    .on('data', function (chunk) {
  //gets percentage after every chunk
        received_bytes += chunk.length;
        showDownloadingProgress(received_bytes, total_bytes, Possition);
    })
    .pipe(outStream)
    outStream.on('finish', function () {
    console.log("download has completed")
//...codeblock for storing local data

    fs.createReadStream(installerfilename)
        .pipe(unzipper.Extract({ path: Directory }))
        .on('finish', function () {
            console.log("unzipper finished extracting")
    //deleting the zip after downloading
            fs.rmSync(installerfilename, { recursive: true, force: true });

        });


})

};

is it even possible to resume download using request or even node in general?

1 Answers

Yes, this is possible to do. When creating the subsequent request you will have to read the file size of the half-downloaded file and make a partial request for those missing bytes. But the server should be setup to handle partial requests as well.

To read the filesize of the half-downloaded file you can use node's fs.promise.stat(PATH), get the file size and inserted it as the startRange.

const startRange = 4000;
const endRange = Number.MAX_SAFE_INTEGER;

const response = await request(url, {
    method: 'GET',
    headers: {
        'Accept-Ranges': 'arraybuffer',
        "Response-Type": 'arraybuffer',
        "Range": `bytes=${startRange}-${endRange},`
    }
});

Related