Why it is needed to invoke close after finish in nodejs stream? - node.js

Here is a source:
var http = require('http');
var fs = require('fs');
var download = function(url, dest, cb) {
var file = fs.createWriteStream(dest);
var request = http.get(url, function(response) {
response.pipe(file);
file.on('finish', function() {
file.close(cb); // close() is async, call cb after close completes.
});
}).on('error', function(err) { // Handle errors
fs.unlink(dest); // Delete the file async. (But we don't check the result)
if (cb) cb(err.message);
});
};
Why file.close(cb) is called on finish event? Does not finish close a stream? Look strange.

Before NodeJS version 5.5.0 it was the application's responsibility to close the file descriptor and make sure there's no file descriptor leak.
In v5.5 they introduced the autoClose attribute for the method createWriteStream with a default value of true which means on error or finish the file descriptor will be closed automatically.
The source you're looking at was before v5.5.0 (2016-01-21)

Related

Couldn't serve a file after deleting with unlink() [duplicate]

I'm using Node.js and I need to delete a file after user download it. Is there any way to call a callback method after pipe process ends, or any event for that purpose?
exports.downloadZipFile = function(req, res){
var fileName = req.params['fileName'];
res.attachment(fileName);
fs.createReadStream(fileName).pipe(res);
//delete file after download
};
You can call fs.unlink() on the finish event of res.
Or you could use the end event of the file stream:
var file = fs.createReadStream(fileName);
file.on('end', function() {
fs.unlink(fileName, function() {
// file deleted
});
});
file.pipe(res);

Node pipe stops working

My client sends an image file to the server. It works 5 times and then it suddenly stops. I am pretty new using streams and pipe so I am not sure what I am doing wrong.
Server Code
http.createServer(function(req, res) {
console.log("File received");
// This opens up the writeable stream to `output`
var name = "./test"+i+".jpg";
var writeStream = fs.createWriteStream(name);
// This pipes the POST data to the file
req.pipe(writeStream);
req.on('end', function () {
console.log("File saved");
i++;
});
// This is here incase any errors occur
writeStream.on('error', function (err) {
console.log(err);
});
}).listen(3000);
Client code
var request = require('request');
var fs = require('fs');
setInterval(function () {
var readStream = fs.createReadStream('./test.jpg');
readStream.on('open', function () {
// This just pipes the read stream to the response object (which goes to the client)
readStream.pipe(request.post('http://192.168.1.100:3000/test'));
console.log("Send file to server");
});
}, 1000);
Behaves like a resource exhaustion issue. Not sure which calls throw errors and which just return. Does the server connect on the 6th call? Does the write stream open? Does the pipe open?
Try ending the connection and closing the pipe after the image is saved. Maybe close the write stream too, don't remember if node garbage collects file descriptors.
I had to do the following on the server side to make this work :
res.statusCode = 200;
res.end();

Proper way to pipe buffers in Node JS

Take a look:
var Client = require('ftp');
var fs = require('fs');
var c = new Client();
c.on('ready', function() {
c.get('foo.txt', function(err, stream) {
if (err) throw err;
stream.once('close', function() { c.end(); });
stream.pipe(fs.createWriteStream('foo.local-copy.txt'));
});
});
// connect to localhost:21 as anonymous
c.connect();
This piece of code is from https://www.npmjs.org/package/ftp. Basically it opens a read stream and pipes it into a write stream. At the end It closes the connection from the source.
Does the pipe method close the target stream after the piped stream (source) is closed? I couldn't find it on the API Documentation.
I made some test that from witch I can conclude it does it but I am no sure.
The destination stream is closed when the source emits an end event. This is documented in Stream.pipe:
By default end() is called on the destination when the source stream
emits end, so that destination is no longer writable.
This allows calls of the form:
var http = require('http'),
fs = require('fs');
http.createServer(function (req, res) {
fs.createReadStream('path/to/file').pipe(res);
}).listen(3000);
If end wasn't called on the response object, the request would time out.
This would make the request time out:
fs.createReadStream('path/to/file').pipe(res, {end: false});

Protractor config onPrepare method makes asynchronous call. How can do I block test starting?

My protractor config file needs to perform some asynchronous work (e.g., downloading libraries and extra filesystem preparation). How can I force protractor to block until all this asynchronous work is complete.
Here is a simplification of what I have and what I need:
var fs = require('fs');
var http = require('http');
exports.config = {
onPrepare: function () {
if (noPreparationNeeded()) {
return;
}
http.get('http://mydriver.company.com', function(res) {
res.on('data', function(data) {
file.write(data);
}).on('end', function() {
file.end();
console.log('Driver download complete');
});
})
}
};
As it currently is, tests will start before the download is complete. How do I prevent that?
You are going to need q to return a promise. Here is an example:
https://github.com/angular/protractor/blob/953faf7ebee345f686bfedff61ebcb29c5170083/spec/onPreparePromiseConf.js

Download File, save it and read it again --> Error

I would like to download a file, write it to a temporary file, read it and give the readFileSync Buffer to a function. I tried this:
var file = fs.createWriteStream("temp.pdf")
var request = http.get(linkArray[1], function(response) {
response.on('data', function(data){
file.write(data)
}).on('end', function(){
postData(fs.readFileSync('temp.pdf'))
})
});
Sometimes it works, but sometimes it doesn't - my guess is that the file isn't written completely, when it is read. (But than the 'end' event shouldn't be fired ?!
As you can see, I would like to download a bunch of files and do this. Do you have any advise how to solve this? Maybe this isn't the best way to solve this...
You shouldn't link streams with on('data' you should use pipe. Pipe will link the streams data events to writes and end events to ends.
var file = fs.createWriteStream("temp.pdf");
var request = http.get(linkArray[1], function(response) {
response.pipe(file).on('close', function(){
postData(fs.readFileSync('temp.pdf'));
});
});
also you should use https://github.com/mikeal/request
var request = require('request');
request.get(linkArray[i], function (err, response, body) {
postData(body);
});
or
var request = require('request');
var file = fs.createWriteStream("temp.pdf");
request.get(linkArray[i]).pipe(file).on('close', function () {
postData(fs.readFileSync('temp.pdf'));
});
You need to call file.end(); at the top of your .on('end', ...) handler. The end() method itself is asynchronous, though, so you'll want to read the file once that's complete. E.g.,
var file = fs.createWriteStream("temp.pdf")
var request = http.get(linkArray[1], function(response) {
response.on('data', function(data){
file.write(data)
}).on('end', function(){
file.end(function() {
postData(fs.readFileSync('temp.pdf'))
});
})
});

Resources