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});
});
});
});
Related
I use this code to show a response of an API request and wanted to seperate my two res.write() parts.
I tried a paragraph but VS is crying :)
app.post("/", function(req, res) {
var crypto = req.body.crypto;
var fiat = req.body.fiat;
var baseUrl = "https://apiv2.bitcoinaverage.com/indices/global/ticker/";
var url = baseUrl + crypto + fiat;
request(url, function(error, response, body) {
var data = JSON.parse(body);
var price = data.last;
var currentDate = data.display_timestamp;
res.write("<p>date: " + currentDate</p>);
res.write(
"Result: Price of " + crypto + " in " + fiat + " is " + price + "."
);
res.send();
});
});
I think you have a typo in this line:
res.write("<p>date: " + currentDate</p>);
It should be:
res.write("<p>date: " + currentDate + "</p>");
In the first version, it is having the closing tag as plain javascript, which is wrong. Should be inside a string (as you do with the opening tag).
I have an array of items:
var myArr = ['item1', 'item2', 'item3'];
I'm attempting to loop over these items and check if they exist in my database. If the item does not exist, then I add it to the database.
var sql = 'Select * from DB where item="' + myArr[i] + '"';
connection.query(sql, function(e, r, f) {
if(!e && r.length <= 0) {
performInsertOnDB(myArr[i]);
}
});
My trouble is, the reference to variable i will not stay as connnection.query is asynchronous. I need to wait until the first select finishes before I can continue. I'm trying to use the Async library to accomplish this, but I must not be fully grasping how to perform the task.
This is what I have so far:
async.each(lootArray, function(lootItem, addLootItem) {
var sql = "SELECT * FROM loot_history WHERE date = DATE('" + moment(lootItem[1]).format('YYYY-MM-DD') + "') AND time = '" + lootItem[2] + "' AND itemId = " + lootItem[4];
connection.query(sql, function(error, results, fields) {
if (error) {
sendDiscordMessage(loachannel, error + ', <#105094681141977088>');
return false;
} else {
if (results.length > 0) {
//duplicates.push(lootArray[i]);
} else {
addLootItem(lootItem);
}
}
});
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if (err) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
}
});
function addLootItem(lootItem) {
var sql = "INSERT INTO loot_history SET player = " + lootItem[0] + ", date = " + moment(lootItem[1]).format('YYYY-MM-DD') + ", time = '" + lootItem[2] + ", item = " + lootItem[3] + ", itemId = " + lootItem[4] + ", itemString=" + lootItem[5] + ", response= " + lootItem[6] + ", votes= " + lootItem[7] + ", class= " + lootItem[8] + ", instance=" + lootItem[9] + ", boss=" + lootItem[10] + ", gear1=" + lootItem[11] + ", gear2=" + lootItem[12] + ", reasponseId=" + lootItem[13] + ", isAwardReason=" + lootItem[14];
connection.query(sql, function(error, results, fields) {
if (error) {
sendDiscordMessage(loachannel, error + ', <#105094681141977088>');
}
});
}
EDIT: Everything works, except the callback AddLootItem is not firing. Why is this callback not getting called? I can set log events in that if statement that execute, but the function itself never fires.
The problem is that the name of async callback is the same as the function you want to be called when the item does not exist. Try to change the name in the function to something else let's say: callback, and call it in your if statement or pass it to addLootItem, and call it there once the item added.
async.each(lootArray, function(lootItem, callback) {
var sql = "SELECT * FROM loot_history WHERE date = DATE('" + moment(lootItem[1]).format('YYYY-MM-DD') + "') AND time = '" + lootItem[2] + "' AND itemId = " + lootItem[4];
connection.query(sql, function(error, results, fields) {
if (error) {
sendDiscordMessage(loachannel, error + ', <#105094681141977088>');
calback(err);
} else {
if (results.length > 0) {
//duplicates.push(lootArray[i]);
callback();
} else {
addLootItem(lootItem, callback);
}
}
});
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if (err) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
}
});
function addLootItem(lootItem, done) {
var sql = "INSERT INTO loot_history SET player = " + lootItem[0] + ", date = " + moment(lootItem[1]).format('YYYY-MM-DD') + ", time = '" + lootItem[2] + ", item = " + lootItem[3] + ", itemId = " + lootItem[4] + ", itemString=" + lootItem[5] + ", response= " + lootItem[6] + ", votes= " + lootItem[7] + ", class= " + lootItem[8] + ", instance=" + lootItem[9] + ", boss=" + lootItem[10] + ", gear1=" + lootItem[11] + ", gear2=" + lootItem[12] + ", reasponseId=" + lootItem[13] + ", isAwardReason=" + lootItem[14];
connection.query(sql, function(error, results, fields) {
if (error) {
sendDiscordMessage(loachannel, error + ', <#105094681141977088>');
}
done();
});
}
Not sure how to input the in_reply_to_status_id.
It's tweeting out fine, just not replying to the tweet with the mention in it.
The in_reply_to_status_id is part of the Twitter API, which Twit accesses, but can I use this in this context?
Any help would be greatly appreciated.
Here's the code:
var stream = T.stream('statuses/filter', { track: '#example'});
io.on('connection', function (socket) {
socket.on('chat message', function (msg) {
console.log('message: ' + msg);
P.post('statuses/update', { status: '#example' + ' ' + msg}, function (err, data, response) {
socket.emit('info', data.text);
socket.emit('userPic', data.user.profile_image_url);
console.log(data.user.profile_image_url);
});
});
stream.start();
stream.on('tweet', function (tweet) {
console.log(tweet);
// console.log('listening to tweets');
if (tweet.text.indexOf('#example') > -1) {
console.log("there is a tweet");
var number = Date.now();
var reply = replies[Math.floor(Math.random() * replies.length)];
var name = '#' + tweet.user.screen_name;
T.post('statuses/update', {in_reply_to_status_id: [name], status: reply + ' ' + number + ' ' + name}, function (err, data, response) {
console.log(reply + number);
socket.emit('reply', data.text);
});
}
});
});
The user name ID string was not being parsed correctly. The solution:
var nameID = tweet.id_str;
var name = tweet.user.screen_name;
T.post('statuses/update', {in_reply_to_status_id: nameID, status: reply + ' ' + number + ' #' + name}, function(err, data, response) {
In my project I am working with 2 async methods. The first method opens an Applescript which opens an After Effects project and loads a jsx file (to adjust items in the After Effects project). The second method renders the adjusted After Effects project and renders it to an .mp4 file.
The problem with the first method is that it can open After Effects well, but it can open only one instance of After Effects, because After Effects only allows to open 1 After Effects project at a time.
In case there are multiple HTTP request to the code, After Effects will throw an error. Because it has to open multiple After Effects project the same time, which is not allowed.
I am looking for a way to queue HTTP requests for this method, so that After Effects can be opened once, and after a couple of seconds the second request is performed and After Effects will be opened again, again, and again... Is there a way of doing this in NodeJS? Because my code won't do this, and I can't find a solution on the net/stackoverflow.
exports.renderProject = function (req, res) {
async.series([
function (callback) {
callback();
},
function (callback) {
var template = req.body[0].template; //project to render (.aep file)
//OSX editproject
var editProject = executablepathOSX + " " + template + " " + template + ".jsx" + " " + guid /*retValVacancyList[0].animation.template*/
var sys = require('sys');
var exec = require('child_process').exec;
var child;
// executes 'edit project'
child = exec(editProject, function (error, stdout, stderr) {
sys.print('stdout: ' + stdout);
sys.print('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
callback();
});
},
function (callback) {
var renderProject = shellscript + "renderMp4.sh " + guid + ".aep " + guid + ".mp4"//guid + ".avi" //animation.template .avi name(guid)
var sys = require('sys');
var exec = require('child_process').exec;
var child;
// executes 'render project'
child = exec(renderProject, function (error, stdout, stderr) {
sys.print('stdout: ' + stdout);
sys.print('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
callback();
});
}
You could use async.queue:
var exec = require('child_process').exec;
var aequeue = async.queue(function(template, callback) {
var editProject = executablepathOSX + ' ' + template + ' ' + template + '.jsx' + ' ' + guid /*retValVacancyList[0].animation.template*/
// executes 'edit project'
exec(editProject, function(error, stdout, stderr) {
callback(error);
});
}, 1);
async.series([
function (callback) {
callback();
},
function (callback) {
aequeue.push(req.body[0].template, callback);
},
function (callback) {
var renderProject = shellscript + "renderMp4.sh " + guid + ".aep " + guid + ".mp4"//guid + ".avi" //animation.template .avi name(guid)
// executes 'render project'
exec(renderProject, function(error, stdout, stderr) {
callback(error);
});
}
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).