0

This feels like an obvious question but it's perplexing me: I want a Node function that downloads a resource at a URI. I need it to work for several different content types without the user needing to specify which type it is.

I know how to pipe request to fs.createWriteStream when you know it's going to be an image, but not how to handle it when you've already invoked the callback from request. Here's where I am:

var request = require('request'),
    fs = require('graceful-fs');

function cacheURI(uri, cache_path, cb) {
    request(uri, function(err, resp, body) {
        var content_type = resp.headers['content-type'].toLowerCase().split("; ")[0],
            type = content_type.split("/")[0],
            sub_type = content_type.split("/")[1];

        if (sub_type == "json") {
            body = JSON.parse(body);
        }

        if (type == "image") {
            // this is where the trouble starts
            var ws = fs.createWriteStream(cache_path);
            ws.write(body);
            ws.on('close', function() {
                console.log('image done');
                console.log(resp.socket.bytesRead);
                ws.end();
                cb()
            });         
        } else {
            // this works fine for text resources
            fs.writeFile(cache_path, body, cb);     
        }


    });
}

This answer to a previous question suggests the following:

request.get({url: 'https://someurl/somefile.torrent', encoding: 'binary'}, function (err, response, body) {
  fs.writeFile("/tmp/test.torrent", body, 'binary', function(err) {
    if(err)
      console.log(err);
    else
      console.log("The file was saved!");
  }); 
});

But I can't pass "binary" to request if I don't yet know the type of response I'll get.

UPDATE

Per the suggested answer, changing "close" to "finish" in the event handler does fire the callback:

        if (opts.image) {
            var ws = fs.createWriteStream(opts.path);
            ws.on('finish', function() {
                console.log('image done');
                console.log(resp.socket.bytesRead);
            });
            //tried as buffer as well
            //ws.write(new Buffer(body));
            ws.write(body);
            ws.end();
        }

This does write the image file, but not correctly:

enter image description here

Community
  • 1
  • 1
Chris Wilson
  • 6,599
  • 8
  • 35
  • 71

1 Answers1

0

As suggested in here, try using the finish event (if you have node >= v0.10)

ws.on('finish', function() {
    console.log('image done');
    console.log(resp.socket.bytesRead);
    ws.end();
    cb()
});
Vsevolod Goloviznin
  • 12,074
  • 1
  • 49
  • 50