checking if busboy finish event has already occured or not - javascript

I have a form in which I am expected to do some file processing which takes some time, so I want that finish event executes only after the processing is complete, right now
node is processing the file and while it is processing the file and executes commands node if finds finish event it fires it. so, how do i make sure that the finish event is fired only after processing of all files.
busboy.on('file', function(fieldname, file, filename,transferEncoding,mimeType) {
var fName = uuid.v4();
var fileext = filename.substr(filename.lastIndexOf('.') + 1);
var filepath = path.normalize(__dirname + '/../../');
var fstream = fs.createWriteStream(filepath+'/server/uploads/'+fName+'.'+fileext);
var uploadFileCompletion = file.pipe(fstream);
uploadFileCompletion.on('finish',function(){
console.log('uploaded now');
var cmd = 'libreoffice --headless --convert-to pdf --outdir '+ filepath + 'server/uploads ' + filepath + 'server/uploads/' + fName + '.' + fileext;
exec(cmd, function(error,stdout,stderr){
sys.puts(stdout);
var encryptCmd = 'java -jar server/uploads/pdfbox-app-1.8.6.jar Encrypt -canAssemble false -canExtractContent false -canExtractForAccessibility false ' +
'-canModify false -canModifyAnnotations false -canPrint false -canPrintDegraded false server/uploads/' + fName + '.' + 'pdf'
+ ' ' + 'server/uploads/' +fName + '.' + 'pdf';
exec(encryptCmd, function(error,stdout,stderr){
fs.unlink(filepath+'server/uploads/'+fName + '.' + fileext, function(){
console.log("removed " +filepath+'server/uploads/'+fName + '.' + fileext);
actualFileName.push(filename);
storedFileName.push(fName+'.'+'pdf');
});
});
});
});
});
busboy.on('field', function(fieldname, val, valTruncated,keyTruncated) {
noteData = JSON.parse(val);
});
busboy.on('finish',function(){
noteData.uploader = req.user.username;
noteData.actualFileName = actualFileName;
noteData.storedFileName = storedFileName;
noteData.noteId = uuid.v4();
Campusnotes.create(noteData,function(err,note){
if(err){
res.status(400);
return res.send({reason:err.toString()});
}
console.log('finish');
res.status(200);
res.end();
})
});
now the console log for this is as follows -
finish
uploaded now
convert /home/unknown/public_html/campustop/server/uploads/8465f9a9-d6b7-4d53-8cb5-a8dbf3aed6a5.odt -> /home/unknown/public_html/campustop/server/uploads/8465f9a9-d6b7-4d53-8cb5-a8dbf3aed6a5.pdf using writer_pdf_Export
removed /home/unknown/public_html/campustop/server/uploads/8465f9a9-d6b7-4d53-8cb5-a8dbf3aed6a5.odt
indicating that the finish event is getting fired again and again

You could try something like:
var files = 0;
busboy.on('file', function(fieldname, file, filename,transferEncoding,mimeType) {
++files;
var fName = uuid.v4();
var fileext = filename.substr(filename.lastIndexOf('.') + 1);
var filepath = path.normalize(__dirname + '/../../');
var fstream = fs.createWriteStream(filepath+'/server/uploads/'+fName+'.'+fileext);
file.pipe(fstream).on('finish',function() {
console.log('uploaded now');
var cmd = 'libreoffice --headless --convert-to pdf --outdir '+ filepath + 'server/uploads ' + filepath + 'server/uploads/' + fName + '.' + fileext;
exec(cmd, function(error,stdout,stderr) {
console.log(stdout);
var encryptCmd = 'java -jar server/uploads/pdfbox-app-1.8.6.jar Encrypt -canAssemble false -canExtractContent false -canExtractForAccessibility false ' +
'-canModify false -canModifyAnnotations false -canPrint false -canPrintDegraded false server/uploads/' + fName + '.' + 'pdf'
+ ' ' + 'server/uploads/' +fName + '.' + 'pdf';
exec(encryptCmd, function(error,stdout,stderr) {
fs.unlink(filepath+'server/uploads/'+fName + '.' + fileext, function() {
console.log("removed " +filepath+'server/uploads/'+fName + '.' + fileext);
actualFileName.push(filename);
storedFileName.push(fName+'.'+'pdf');
});
});
--files;
onFinish();
});
});
});
busboy.on('field', function(fieldname, val, valTruncated,keyTruncated) {
noteData = JSON.parse(val);
});
busboy.on('finish', onFinish);
function onFinish() {
if (!busboy.writable && files === 0) {
noteData.uploader = req.user.username;
noteData.actualFileName = actualFileName;
noteData.storedFileName = storedFileName;
noteData.noteId = uuid.v4();
Campusnotes.create(noteData,function(err,note){
if (err){
res.status(400);
return res.send({reason:err.toString()});
}
console.log('finish');
res.status(200);
res.end();
});
}
}
On an unrelated note, you should probably do some sanitizing/checking of the filename, someone could be malicious and use something like '../../../../../../../../../etc/passwd' (I'm not sure if createWriteStream() resolves/normalizes the path given to it or not).

Related

Simple NodeJS minifier cli app - fs.writeFile only writes to 1 file from list over and over

As my first NodeJS app I made a simple CLI Minifier app for HTML, CSS and Javascript files. It works for the most part but one feature. The goal is to have the "all" command read all files in a folder, put the names in an array and write those files minified to a different folder. When I give the CLI "Command: all", console logs all files correctly but will only minify 1 file for as much times as there are files in the folder.
I tried to for...loop through fileArr[] to read and write files from there, after letting 'forEach' push all file names into fileArr[]. This gave the same output as now.
The full working code is added with all features below the code that does not work as intended.
To make the app work you need to have HTML-Minifier installed npm install html-minifier
https://www.npmjs.com/package/html-minifier
The piece of code that does not work as intended, I have added comments to try to make it clearer (some comments in the full working code I wrote for myself and dont necessarily need an answer in this thread):
} else if(answer === 'all'){
if (!fs.existsSync("./files/")){ //Checks if folder exists, if not it will create one
fs.mkdirSync("./files/");
}
//Code that reads the /files/ folder to make a list of all files in there.
fs.readdir(__dirname + '/files/', function (err, files){ //Files get listed correctly
if(err){
console.error(err)
setTimeout(askCommand, 250)
return;
}
let fileArr = []
//With forEach I want to minify->write new file->log for every item in the list.
//Console.log shows all seperate items correctly but only 1 item gets minified as much as there are items in the folder
files.forEach(function (file){
fileArr.push(file) //Files get listed correctly
//Part that reads the input file
codeIn = file;
console.log(codeIn + " - console.log()") //Files get listed correctly
const fileIn = fs.readFile(__dirname + `/files/${codeIn}`, 'utf8', (err, data) => { //For some reason something must go wrong somewhere here. Only 1 file gets minified over and over
if(err){
console.error(err)
setTimeout(askCommand, 250)
return;
}
codeOut = minify(data, { //Minifies input
collapseWhitespace: true,
removeEmptyElements: true,
removeEmptyAttributes: true,
minifyCSS: true,
minifyJS: true
});
//Part that writes the minified file
if (!fs.existsSync("./minified/")){ //Checks if folder 'minified' exists, this is the output folder
fs.mkdirSync("./minified/");
}
fs.writeFile(__dirname + `/minified/${codeIn}`, codeOut, err => {
if (err) {
console.error(err);
setTimeout(askCommand, 250)
return;
}
const sizeOutput = minified(codeIn) + ' Bytes - ' + (minified(codeIn) / 1024).toFixed(3) + 'Kb'; //Some calulations with the file sizes for the log file.
const sizeBefore = before(codeIn) + ' Bytes - ' + (before(codeIn) / 1024).toFixed(3) + 'Kb';
const sizeDifference = (before(codeIn) - minified(codeIn)) + " Bytes - " + ((before(codeIn) - minified(codeIn)) / 1024).toFixed(3) + 'Kb';
const outputMsg = codeIn + " | Before: " + sizeBefore + " | After: " + sizeOutput + " | Difference: " + sizeDifference
logArr.push(outputMsg)
console.log('File Sucessfully Minified!')
console.log(outputMsg)
setTimeout(askCommand, 250)
});
});
})
})
} else {
//Full Working Code
var minify = require('html-minifier').minify;
const rl = require('readline').createInterface({
input: process.stdin,
output: process.stdout,
});
const fs = require('fs');
let codeIn;
let codeOut;
let logArr = [];
function minified(filename) {
var stats = fs.statSync(`./minified/${filename}`);
var fileSizeInBytes = stats.size;
return fileSizeInBytes;
}
function before(filename, fIsTrue) {
if(fIsTrue === true){
var files = '';
} else {
var files = 'files/';
}
var stats = fs.statSync(`./${files}${filename}`);
var fileSizeInBytes = stats.size;
return fileSizeInBytes;
}
function createLog(){
const logTime = (new Date().getMinutes()).toString() + (new Date().getSeconds()).toString()
let logFile = ""
logFile = logFile + (logArr.toString()).replace(/,/g, "\n")
fs.writeFile(__dirname + `/log-${logTime}.txt`, logFile, err => {
if (err) {
console.error(err);
setTimeout(askCommand, 250)
return;
}
console.log(`File log-${logTime}.txt created!`)
logArr = []
});
}
function askCommand(){
rl.question('Command: ', (answer) => {
if(answer === 'log'){
createLog()
setTimeout(askCommand, 250)
} else if (answer === 'print') {
let logFile = ""
logFile = logFile + (logArr.toString()).replace(/,/g, "\n")
console.log(logFile)
setTimeout(askCommand, 250)
} else if(answer === 'log date'){
logArr.unshift(new Date())
createLog()
setTimeout(askCommand, 250)
} else if(answer === 'help'){
console.log(`\n \n By default the app will look for files in the './files/' folder \n Minified files will be put in a folder './minified/' \n \n LIST OF POSSIBLE COMMANDS: \n * 'myApp.js' - Enter the filename including extension to minify \n * 'index.html --f' - With ' --f' you can minify files from the same folder as app.js \n * 'print' - Will print the log to the console \n * 'log' - Will create a log.txt file with relevant file sizes. Log is cleared afterwards. \n * 'log date' - Will create a log file with current date time. Log is cleared afterwards. \n * 'help' - Shows the list of possible commands`)
setTimeout(askCommand, 250)
} else if(answer === 'all'){
if (!fs.existsSync("./files/")){ //Checks if folder exists, if not it will create one
fs.mkdirSync("./files/");
}
//Code that reads the /files/ folder to make a list of all files in there.
fs.readdir(__dirname + '/files/', function (err, files){ //Files get listed correctly
if(err){
console.error(err)
setTimeout(askCommand, 250)
return;
}
let fileArr = []
//With forEach I want to minify->write new file->log for every item in the list.
//Console.log shows all seperate items correctly but only 1 item gets minified as much as there are items in the folder
files.forEach(function (file){
fileArr.push(file) //Files get listed correctly
//Part that reads the input file
codeIn = file;
console.log(codeIn + " - console.log()") //Files get listed correctly
const fileIn = fs.readFile(__dirname + `/files/${codeIn}`, 'utf8', (err, data) => { //For some reason it will not get all items from the list. Only 1 file gets minified over and over
if(err){
console.error(err)
setTimeout(askCommand, 250)
return;
}
codeOut = minify(data, { //Minifies input
collapseWhitespace: true,
removeEmptyElements: true,
removeEmptyAttributes: true,
minifyCSS: true,
minifyJS: true
});
//Part that writes the minified file
if (!fs.existsSync("./minified/")){
fs.mkdirSync("./minified/");
}
fs.writeFile(__dirname + `/minified/${codeIn}`, codeOut, err => {
if (err) {
console.error(err);
setTimeout(askCommand, 250)
return;
}
const sizeOutput = minified(codeIn) + ' Bytes - ' + (minified(codeIn) / 1024).toFixed(3) + 'Kb'; //Some calulations with the file sizes for the log file.
const sizeBefore = before(codeIn) + ' Bytes - ' + (before(codeIn) / 1024).toFixed(3) + 'Kb';
const sizeDifference = (before(codeIn) - minified(codeIn)) + " Bytes - " + ((before(codeIn) - minified(codeIn)) / 1024).toFixed(3) + 'Kb';
const outputMsg = codeIn + " | Before: " + sizeBefore + " | After: " + sizeOutput + " | Difference: " + sizeDifference
logArr.push(outputMsg)
console.log('File Sucessfully Minified!')
console.log(outputMsg)
setTimeout(askCommand, 250)
});
});
})
})
} else {
var bol;
const answerSplit = answer.split(' --')
if(answerSplit[1] === 'f'){//In case command --f is given 'bol' is set to true and strPath to nothing. This way it will only look for files in the same folder as app.js. Answer is checked for command
const strPath = ''
bol = true;
miniFy(strPath)
} else {
bol = false;
const strPath = 'files/'
miniFy(strPath)
}
function miniFy(param){ //Function works inside the 'else if' statement but not outside, error is: TypeError [ERR_INVALID_ARG_TYPE]: The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received undefined
if (!fs.existsSync("./files/")){
fs.mkdirSync("./files/");
}
codeIn = answerSplit[0].toString();//Gets filename from splitted input
console.log(param + codeIn + " - console.log()")
const fileIn = fs.readFile(`./${param}${codeIn}`, 'utf8', (err, data) => {
if(err){
console.error(err)
setTimeout(askCommand, 250)
return;
}
codeOut = minify(data, {
collapseWhitespace: true,
removeEmptyElements: true,
removeEmptyAttributes: true,
minifyCSS: true,
minifyJS: true
});
wFile()
});
}
function wFile(){ //Function works inside the 'else if' statement but not outside, error is: TypeError [ERR_INVALID_ARG_TYPE]: The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received undefined
if (!fs.existsSync("./minified/")){
fs.mkdirSync("./minified/");
}
fs.writeFile(__dirname + `/minified/${codeIn}`, codeOut, err => {
if (err) {
console.error(err);
setTimeout(askCommand, 250)
return;
}
if(bol === true){
const sizeOutput = minified(codeIn) + ' Bytes - ' + (minified(codeIn) / 1024).toFixed(3) + 'Kb';
const sizeBefore = before(codeIn, true) + ' Bytes - ' + (before(codeIn, true) / 1024).toFixed(3) + 'Kb';
const sizeDifference = (before(codeIn, true) - minified(codeIn)) + " Bytes - " + ((before(codeIn, true) - minified(codeIn)) / 1024).toFixed(3) + 'Kb';
var outputMsg = codeIn + " | Before: " + sizeBefore + " | After: " + sizeOutput + " | Difference: " + sizeDifference
} else {
const sizeOutput = minified(codeIn) + ' Bytes - ' + (minified(codeIn) / 1024).toFixed(3) + 'Kb';
const sizeBefore = before(codeIn) + ' Bytes - ' + (before(codeIn) / 1024).toFixed(3) + 'Kb';
const sizeDifference = (before(codeIn) - minified(codeIn)) + " Bytes - " + ((before(codeIn) - minified(codeIn)) / 1024).toFixed(3) + 'Kb';
var outputMsg = codeIn + " | Before: " + sizeBefore + " | After: " + sizeOutput + " | Difference: " + sizeDifference
}
logArr.push(outputMsg)
console.log('File Sucessfully Minified!')
console.log(outputMsg)
setTimeout(askCommand, 250)
});
}
}
})
}
askCommand()

Have to wait for the second file upload request for the first one's data to send to AWS S3

Any help is greatly appreciated! I've spent so long searching but I haven't found a solution or a problem like mine...
I'm writing an Electron application, and as part of it, there is a section for the users to drag and drop files. I'm then taking that file and uploading it to AWS S3.
The first time I drag and drop it goes into my function but no request is sent out to AWS S3, I then drag and drop again and it sends out the expected request and saves the file however it's the first requests information (name, path & body), and from then on when I drag and drop the file it send outs the request every time but always with the previous request's info. It's like its one sequence behind....
This is the s3 code:
function submitNewFileS3(file, filepath) {
const AWS = require('aws-sdk');
AWS.config = new AWS.Config({
accessKeyId: localStorage.getItem("accessKeyId"),
secretAccessKey: localStorage.getItem("secretAccessKey"),
region: 'eu-west-2'
});
var upload = new AWS.S3.ManagedUpload({
params: {
Bucket: 'sampe-bucket',
Key: filepath, // File name you want to save as in S3
Body: file
}
});
return upload.promise();
}
How I call the function:
var reader = new FileReader();
reader.onload = function (e2) {
// finished reading file data.
finishUploading(e2.target.result);
}
function finishUploading(url) {
// strip off the data: url prefix to get just the base64-encoded bytes
var data;
if (url.indexOf('data:image') > -1) {
data = url.replace(/^data:image\/\w+;base64,/, "");
} else if (url.indexOf('data:application') > -1) {
data = url.replace(/^data:application\/\w+;base64,/, "");
}
//only firing after sencon upload
var buf = Buffer.from(data, 'base64');
var filePathS3 = directory + (fileName).replace(/\-/g, "_").replace(/ /g, "_");
submitNewFileS3(buf, filePathS3).then(function (response) {
console.log(response);
}).catch(function (response) {
console.log(response);
});
}
reader.readAsDataURL(f); // start reading the file data.
Does anyone have any suggestions - I'm going out of my mind...I've tried so many tutorials and solutions and they all work...on the second call...
I've double checked all the required data is ready before making the request.
Many thanks in advance!
EDIT - more of what's going on in my main before sending my file to be uploaded:
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
var directory;
if (e.target.id == 'drop_zone_overview') {
//placed in general area, check which folders are showing to get dir
console.log(e);
//get whats visible
var whatPath;
$(".icon").each(function () {
if (this.style.display != 'none') {
whatPath = this.id;
}
});
//pick one and check what root we're in
var pathArray = whatPath.split('-');
console.log(pathArray);
} else if (e.target.id == 'drop_zone_individual') {
//placed on top of folder, check dir
directory = (e.target).getAttribute('data-targetfolder');
console.log(directory);
}
var files = e.dataTransfer.files,
folder;
for (var i = 0, f; f = files[i]; i++) { // iterate in the files dropped
if (!f.type && f.size % 4096 == 0) {
// The file is a folder
folder = true;
} else {
// The file is not a folder
folder = false;
}
const fs = require('fs');
console.log(f);
var fileName = f.name;
var reader = new FileReader();
reader.onload = function (e2) {
// finished reading file data.
finishUploading(e2.target.result);
}
function finishUploading(url) {
// strip off the data: url prefix to get just the base64-encoded bytes
var data;
if (url.indexOf('data:image') > -1) {
data = url.replace(/^data:image\/\w+;base64,/, "");
} else if (url.indexOf('data:application') > -1) {
data = url.replace(/^data:application\/\w+;base64,/, "");
}
var buf = Buffer.from(data, 'base64');
var filePathS3 = directory + (fileName).replace(/\-/g, "_").replace(/ /g, "_");
submitNewFileS3(buf, filePathS3).then(function (response) {
console.log(response);
}).catch(function (response) {
console.log(response);
});
}
reader.readAsDataURL(f); // start reading the file data.
uploadedFiles.push(f);
}
uploadedFiles.forEach(function (file) {
var pathKey = directory + (file.name).replace(/\-/g, "_");
pathKey = pathKey.replace(/ /g, "_").replace(/\//g, '-').replace(/\./g, '__');
if ($('#' + pathKey).length) {
//filename already exists in directory
alert(file.name + ' already exists in folder ' + directory);
} else {
var displayDiv;
if (file.type == 'image/png') {
//image
//add to directory
displayDiv = '<img id="' + pathKey + '" class="fileInfo thumb file-type file-type-img" src="' + URL.createObjectURL(file) + '" ondblclick="preview_image(this)"/>'
} else if (file.type == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') {
//xlsx doc
displayDiv = '<div id="' + pathKey + '" class="fileInfo thumb file-type file-type-xlsx" data-downloadLink="' + URL.createObjectURL(file) + '" ></div>';
} else if (file.type == 'application/pdf') {
//pdf doc
displayDiv = '<div id="' + pathKey + '" class="fileInfo thumb file-type file-type-pdf" data-downloadLink="' + URL.createObjectURL(file) + '" ></div>';
} else if (file.type == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
//word doc
displayDiv = '<div id="' + pathKey + '" class="fileInfo thumb file-type file-type-docx" data-downloadLink="' + URL.createObjectURL(file) + '" </div>';
console.log('its a doc');
} else if (file.type == 'application/x-zip-compressed') {
//zip file doc
displayDiv = '<div id="' + pathKey + '" class="fileInfo thumb file-type file-type-zip" data-downloadLink="' + URL.createObjectURL(file) + '" </div>';
} else if (file.type == '') {
//folder
console.log('what typep is this~~~~~ ' + file.type);
file.name = file.name + '/';
}
//save to folder array
if (file.type == 'application/x-zip-compressed' || file.type == '') {
var htmlTemplate = [
getHtml([
'<li id=' + pathKey.replace(/ /g, "_").replace(/\//g, '-').replace(/\./g, '__') + ' class="icon folderItems fileInfo thumb" data-downloadLink="directory_' + pathKey + '" ondblclick="viewAlbum(this.id)" style="display:none">',
'<i id="drop_zone_individual" data-targetFolder="' + pathKey + '" class="folders fas fa-folder" style="font-size: 115px; color: rgb(13, 36, 60); cursor: pointer;"></i>',
'<div class="folderLabel" style="text-align:center">' + file.name + '</div>',
'</li>'
])
];
folders.push({
Key: directory + (file.name).replace(/\-/g, "_").replace(/ /g, "_"),
LastModified: file.lastModifiedDate,
Size: file.size,
});
} else {
//append to ui file list
var htmlTemplate = [
getHtml([
'<li id=' + pathKey + ' class="icon downloadableItem" style="display:none">',
'<span>',
'<div style="text-align:center">',
displayDiv,
'</div>',
'<div style="text-align:center">',
'<span>',
file.name,
'</span>',
'</div>',
'</span>',
'</li>'
])
];
//save to folder list
folders.push({
Key: directory + (file.name).replace(/\-/g, "_").replace(/ /g, "_"),
LastModified: file.lastModifiedDate,
Size: file.size,
signedUrl: URL.createObjectURL(file)
});
}
localStorage.setItem("s3Objects", JSON.stringify(folders));
$('#photoAlbumViewerList').append(htmlTemplate);
console.log(folders);
$("#" + pathKey).click(function (e) {
getAlbumInfo(this.id);
if (e.shiftKey) {
if ($(this).hasClass('thumb')) {
$(this).removeClass('thumb').addClass('thumbChecked');
$(this).css("border", "2px solid #c32032");
// $(this).attr("data-downloadLink");
links.push($(this).attr("data-downloadLink"));
if (links.length != 0) {
$('.download').css("display", "block");
}
} else if ($(this).hasClass('thumbChecked')) {
$(this).removeClass('thumbChecked').addClass('thumb');
$(this).css("border", "2px solid white");
var itemtoRemove = $(this).attr('src');
links.splice($.inArray(itemtoRemove, links), 1);
console.log(links);
if (links.length == 0) {
$('.download').css("display", "none");
}
}
}
});
}
});
uploadedFiles = [];
e.target.classList.remove('drop_zone_hovered');
$('#drop_zone_text').hide();
}
As an FYI - the issue lied where I reinitialised AWS and S3 variables, it wasn't needed as I set it at the start of launch and reinitialising it slowed it all down while it remade the connection!

Streaming to and from external programs expecting files with javascript nodejs

Problem:
I need to upload hundreds of PDF documents, convert them to HTML and then store the HTML in MongoDB. I am currently saving both the incoming PDF documents and converted HTML in the file system. Is there a way to use streams to avoid all the file I/O?
Current approach (which works but is slow):
I am using:
Busboy to read the uploaded PDF documents which I save to the file system.
I create an "exec" child process in node.js which invokes "'pdftohtml -c -s -noframes -nodrm ' + inputFileNamePDF + ' ' + outputFileNameHTML,". The HTML output files get saved to the file system.
I then iterate through all the HTML files to create a Bulk upsert to MongoDB.
Ideally I'd like to stream the uploaded PDF file directly to "inputFileNamePDF". Then stream the converted "outputFileNameHTML" to the bulk upsert.
Here's the Code:
var path = require("path"),
Busboy = require('busboy')
http = require('http'),
util = require('util'),
fs = require('fs-extra'),
pdftohtml = require('pdftohtmljs'),
exec =require('child_process').exec,
pdf_extract = require('pdf-extract'),
exports.postUpload = function (req, res) {
// parse a file upload
var fileName = "";
var uploadDir = '/tmp/' + res.locals.user._doc.email.replace(/[#\.]/g,"_");
var infiles = 0, outfiles = 0, done = false,
busboy = new Busboy({ headers: req.headers });
console.log('Start parsing form ...');
busboy.on('file', function (fieldname, file, filename) {
++infiles;
console.log("file event #" + infiles);
onFile(fieldname, file, filename, function () {
++outfiles;
console.log("file #" + infiles + " written.");
if (done) console.log(outfiles + '/' + infiles + ' parts written to disk');
if (done && infiles === outfiles) {
// ACTUAL EXIT CONDITION
console.log('All parts written to disk');
res.writeHead(200, { 'Connection': 'close' });
res.end("That's all folks!");
convertToHTMLTxt();
}
});
});
busboy.on('finish', function () {
console.log('Done parsing form!');
done = true;
});
req.pipe(busboy);
function onFile(fieldname, file, filename, next) {
// or save at some other location
var fileName = "";
fileName = filename.replace( /[^a-z0-9_\-]/gi,"_");
fileName = fileName.replace(/_(pdf|docx|doc)$/i,".$1");
var fstream = fs.createWriteStream(path.join(uploadDir, fileName));
file.on('end', function () {
console.log(fieldname + '(' + fileName + ') EOF');
});
fstream.on('close', function () {
console.log(fieldname + '(' + fileName + ') written to disk');
next();
});
console.log(fieldname + '(' + fileName + ') start saving');
file.pipe(fstream);
}
function convertToHTMLTxt () {
var execTxt, execHTML, execPDF;
var textDir = 'text';
var htmlDir = 'html';
console.log('Directory: ', uploadDir);
fs.readdir(uploadDir, function(err, files) {
if (err) {
console.log('error reading directory: ', uploadDir);
return;
}
files.forEach(function(fileName) {
var fileNameHTML = path.join(uploadDir, htmlDir,
fileName.replace(/(pdf|docx|doc)$/i,"html"));
var fileNamePDF = path.join(uploadDir, fileName);
if (fileName.match(/pdf$/i)) {
execPDF = exec('pdftohtml -c -s -noframes -nodrm '
+ fileNamePDF + ' ' + fileNameHTML,
function(error, stdout, stderr) {
console.log('stdout: ', stdout);
console.log('stderr: ', stderr);
if (error !== null) {
console.log('exec error: ', error);
}
});
execPDF.on('close', function (code) {
console.log('******** PDF to HTML Conversion complete - exit code '
+ code);
});
}
})
});
Once the conversion is done I iterate through all the HTML files and do a MongoDB bulk upsert:
fs.readFile(fileNameHTML, 'utf8', function (err, HTMLData) {
if (err) {
console.log('error reading file: ', fileNameHTML + '/nerror: ' + err);
callback(err);
return;
}
bulk.find({ userName: userName,
docName : fileName
}).upsert()
.updateOne({userName: userName,
docName : fileName,
HTMLData : HTMLData});

Busboy and GridFS won't save file to filesystem

When the following POST API is called, it should save the file to the file system. However, the file is not being saved. I can see the file in the console, but can't save/write it.
I have the following code:
router.post('/notes', function(req, res, next) {
var gfsstream, startFileWrite, endFileWriteTime;
var busboy = new Busboy({ headers: req.headers });
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
startFileWrite = new Date().getTime();
console.log('File [' + fieldname + ']: filename: ' + filename);
gfsstream = gfs.createWriteStream('/uploads');
file.on('data', function(data) {
gfsstream.write(data);
});
file.on('end', function() {
gfsstream.end();
req.pipe(gfsstream);
});
gfsstream.on('close', function (file) {
// do something with `file`
endFileWrite = new Date().getTime();
console.log('File [' + fieldname + '] Finished');
console.log("Time needed: " + (endFileWrite - startFileWrite) + " ms");
});
});
busboy.on('error', function(err) {
console.error(err);
res.sendStatus(500, 'ERROR', err);
});
busboy.on('finish', function end() {
res.sendStatus(200);
});
req.pipe(busboy);
});
req.pipe(gfsstream) might be the issue here, but I am not sure what is preventing the file from being saved.
Just do file.pipe(gfsstream) and use the finish event instead of the close event:
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
startFileWrite = new Date().getTime();
console.log('File [' + fieldname + ']: filename: ' + filename);
gfsstream = gfs.createWriteStream('/uploads');
file.pipe(gfsstream).on('finish', function() {
endFileWrite = new Date().getTime();
console.log('File [' + fieldname + '] Finished');
console.log("Time needed: " + (endFileWrite - startFileWrite) + " ms");
});
});

Express.js load file after page load

I'm working on a web app that reads and writes files. This is in my index.js route file. When I load the results page, it says that it cannot load the coverage file. I understand that this is because it hasn't finished writing before the requests page loads. My question is how can I load the file and update the page when it is done loading?
router.get('/results?', function(req, res) {
var id = req.query.id;
var sequence = fs.readFileSync(temppath + id + ".sequence");
var refseq = fs.readFileSync(temppath + id + ".refseq");
var coverage = fs.readFileSync(temppath + id + ".coverage.txt");
res.render('results', { title: 'Results', sequence: sequence, refseq:refseq, coverage: coverage});
});
router.post('/calculate-coverage', function(req, res) {
var id = crypto.randomBytes(20).toString('hex');
var sequence = req.body.sequence;
var sequence = ">" + temppath + id + "\n" + sequence.replace(/ /g,'');
var refseq = req.body.refseq;
var refseq = ">" + temppath + id + "\n" + refseq.replace(/ /g,'');
//display progress here
//write to files
var sequenceFile = temppath + id + ".sequence";
var refseqFile = temppath + id + ".refseq";
fs.writeFileSync(sequenceFile, sequence);
fs.writeFileSync(refseqFile, refseq);
//bamtools coverage script
var cmd = 'bash ./scripts/coverage.sh ' + sequenceFile + " " + refseqFile + " " + temppath + id;
console.log(cmd);
exec(cmd, function(error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
res.location("results?id="+id);
res.redirect("results?id="+id);
});
Never use synchronous function like this. Because if you have 100 concurrent requests and within one of them sync function is used, other 99 clients will wait till this function ends. Instead use async analogs:
fs.readFile(temppath + id + ".sequence", "utf8", function(err, sequence) {
fs.readFile(temppath + id + ".refseq", "utf8", function(err, refseq) {
fs.readFile(temppath + id + ".coverage.txt", "utf8", function(err, coverage) {
res.render('results', { title: 'Results', sequence: sequence, refseq:refseq, coverage: coverage});
});
});
});

Categories

Resources