I'm creating a temporary JSON file in my NodeJS backend which holds the information the user has filled in a form. At the end of the form when user clicks on the download button, I run some Python script in NodeJS to validate the data and then create a temporary file of this JSON data and return it to user as a HTTP GET response.
Right now I'm using a timer to delete this temporary file after 10 seconds, which is bad. I want to know how to detect when the user has fully downloaded the file to their local disk from the browser so I can delete this temporary file in backend.
The client Angular code:
$scope.downloadForm = function() {
var data = formDataFactory.getDataForSubmission();
var url = '/FormSubmission/DownloadData';
// Below POST call will invoke NodeJS to write the temporary file
$http.post(url, data)
.success(function(data, status) {
$scope.downloadPath = data.filePath;
$scope.downloadFile = data.fileName;
url = '/tmp/forms/' + $scope.downloadFile;
// If the temporary file writing is successful, then I get it with a GET method
$http.get(url)
.success(function(data, status) {
$log.debug("Successfully got download data");
$window.location = $scope.downloadPath;
})
.error(function(data, status) {
$log.error("The get data FAILED");
});
})
.error(function(data, status) {
$log.error("The post data FAILED");
});
}
$scope.download = function() {
$scope.downloadForm();
setTimeout(function() { //BAD idea
$scope.deleteForm($scope.downloadPath);
}, 10000);
}
The server NodeJS code:
// POST method for creating temporary JSON file
router.post('/FormSubmission/DownloadData', function(req, res) {
if (!req.body) return res.sendStatus(400); // Failed to get data, return error
var templateString = formTmpPath + 'form-XXXXXX.json';
var tmpName = tmp.tmpNameSync({template: templateString});
fs.writeFile(tmpName, JSON.stringify(req.body, null, 4), function(err) {
if (err) {
res.sendStatus(400);
} else {
res.json({ fileName: path.basename(tmpName), filePath: tmpName, out: ''});
}
});
});
// Get method for downloading the temporary form JSON file
router.get('/tmp/forms/:file', function(req, res) {
var file = req.params.file;
file = formTmpPath + file;
res.download(file, downloadFileName, function(err) {
if (err) debug("Failed to download file");
});
});
Update: I'm trying to use a stream now to send the data back, but for some reason this get method is called twice!? Can't understand why!!
// Get method for downloading the temporary form JSON file
router.get('/tmp/forms/:file', function(req, res) {
var filename = "ipMetaData.json";
var file = req.params.file;
file = formTmpPath + file;
var mimetype = mime.lookup(file);
const stats = fs.statSync(file);
res.setHeader('Content-disposition', 'attachment; filename=' + filename);
res.setHeader('Content-type', mimetype);
res.setHeader('Content-Length', stats.size);
console.log("Will send the download response for file: ", file);
//var path = __dirname + "\\..\\tmp\\forms\\form-auSD9X.json";
console.log("Creating read stream for path: " + file);
var stream = fs.createReadStream(file);
// This will wait until we know the readable stream is actually valid before piping
stream.on('open', function () {
// This just pipes the read stream to the response object (which goes to the client)
stream.pipe(res);
});
// This catches any errors that happen while creating the readable stream (usually invalid names)
stream.on('error', function(err) {
console.log("Caught an error in stream"); console.log(err);
res.end(err);
});
stream.on('end', () => {
console.log("Finished streaming");
res.end();
//fs.unlink(file);
});
});