Karl Bateman Karl Bateman - 1 month ago 7
Node.js Question

Callback on recursive function

The following code is used to fetch a

.zip
file from our web application. The file is generated by closing another application safely then zipping, finally sending it for download.

var dl = function() {
request({
method: 'GET',
uri: 'some_url',
headers: {
'User-Agent': 'Scripted-Download'
},
encoding: null,
jar: true
}, function(err, res, body) {
if (err) throw(err)
if (res.headers['content-type'] === 'application/zip;charset=utf-8') {
process.stdout.write('\rDownloading file ..')
var id = uuid.v4()
, file = path.resolve(__dirname, '../../' + id + '.zip')
fs.writeFile(file, body, function(err) {
if (err) throw(err)
process.stdout.write('\rFile downloaded ' + id + '.zip')
process.exit(0)
})
} else {
process.stdout.write('\rAwaiting file ..')
setTimeout(dl(), 30 * 1000)
}
})
}


This works as expected. However, I need to use this from another script. So the above code returns an
id
of the file downloaded, then from another script I can extract the
.zip
and place the extracted files into a directory with the same
id
. These files would then be made available to download.

EDIT Essentially I need to execute this script, extract the contents when it's downloaded then load a UI with
res.render()
when the previous two steps are complete. This needs to be done with an
id
so that two users don't create conflicting files.

Answer

As mentioned in the comments, promises should make this easy. First promisify the async functionality you need:

function makeRequest(parameters) {
    return new Promise(function (resolve, reject) {
        request(parameters,  function (err, res, body) {
            if (err) { reject (err); }
            else { resolve({ res: res, body: body }); }
        });
    });
}

function writeFile(file, body) {
    return new Promise(function (resolve, reject) {
        fs.writeFile(file, body, function(err) {
            if (err) { reject(err); }
            else { resolve(); }
        });
    });
}

function timeout(duration) {
    return new Promise(function (resolve) {
        setTimeout(resolve, duration);
    });
}

Then use them.

var dl = function () {
    return makeRequest({
        method: 'GET',
        uri: 'some_url',
        headers: {
            'User-Agent': 'Scripted-Download'
        },
        encoding: null,
        jar: true
    }).then(function (result) {
        if (result.res.headers['content-type'] === 'application/zip;charset=utf-8') {
            process.stdout.write('\rDownloading file ..')
            var id = uuid.v4()
            , file = path.resolve(__dirname, '../../' + id + '.zip');

            return writeFile(file, result.body)
                .then(function () { return id; });
        } else {
            process.stdout.write('\rAwaiting file ..');

            return timeout(30 * 1000).then(dl);
        }
    });
}

dl().then(function (id) { process.stdout.write('\rid is: ' + id); });
Comments