How to use a nested loop in request.head - Node JS - node.js

I am trying to move download images from parse and save it to my local. I have this piece of code that does the job for me. This works well when there is only one request but when I put in a loop, it doesn't hold good.
`for(var i = 0; i < 5; i++) {
console.log(i);//to debug
var filename = results_jsonObj[i].imageFile.name;
var uri = results_jsonObj[i].imageFile.url;
request.head(uri, function(err, res, body){
if (err){
console.log(err);
console.log(item);
return;
}else {
console.log(i); //to debug
var stream = request(uri);
stream.pipe(
fs.createWriteStream("images/"+filename)
.on('error', function(err){
callback(error, filename);
stream.read();
})
)
}
});
}`
Irrespective of the loop condition I have, only one image downloads to the mentioned directory.
Below is the op
The input is from a Json file and I have the request, fs, parse module included in the node js program.
Any help on how to go about this?

I have got this fixed now. As advised in the comments it was async which helped me do the trick.
for(var i = 0; i < 900; i++) {
async.forEachOf(results_jsonObj[i], function(value, key, callback){
var image = {};
image.key = key;
image.value = value;
if(image.key == 'imageFile')
{
var filename = image.value.name;
var uri = image.value.url;
// console.log(filename, uri);
}
request.head(uri, function(err, res, body){
if (err){
console.log(err);
// console.log(item);
return;
}else {
// console.log(i,res.headers['content-type']); //to debug
var stream = request(uri);
stream.pipe(
fs.createWriteStream("images/"+filename)
.on('error', function(err){
callback(error, filename);
stream.read();
})
)
}
});
callback();
}, function(err){
if (err) {
console.log('one of the api failed, the whole thing will fail now');
}
});
}

Related

Async series doesn't work in an order as expected

I have a function that downloads the user input(currently named app.json) from browser(client) to the server
function downloadUpload(callback){
//Using formidable node package for downloading user input to server
var form = new formidable.IncomingForm();
form.on('fileBegin', function(name, file) {
file.path = file.name;
});
form.parse(req, function(err, fields, files) {
res.writeHead(200, { 'content-type': 'text/plain' });
res.write('received upload:\n\n');
res.end(util.inspect({ fields: fields, files: files }));
});
callback(null);
}
I have another function that takes the file downloaded above and converts it into required format(final.json) something like this.
function UpdateCode(callback){
var obj = fs.readFileSync('app.json', 'utf8');
var object = JSON.parse(obj);
var data2 = [];
for (var j = 0; j < object.length; j++) {
if (object[j].value == "TEST") {
data2.push(object[j]);
}
}
console.log(data2);
fs.appendFile('final.json', JSON.stringify(data2), function(err) {
if (err) throw err;
console.log('Saved!');
});
callback(null);
}
I want them to run in an order, so I used async series method like this
async.series([
downloadUpload,
UpdateCode
],function(err,result){
if(err) throw err;
else{
console.log(result);
}
});
The problem is the file(app.json) is getting downloaded and an error is displayed saying that app.json doesn't exist in the current folder or directory. Where am I going wrong?
This is likely what you need.
function downloadUpload(callback) {
//Using formidable node package for downloading user input to server
var form = new formidable.IncomingForm();
form.on('fileBegin', function(name, file) {
file.path = "app.json";
});
form.parse(req, function(err, fields, files) {
res.writeHead(200, {
'content-type': 'text/plain'
});
res.write('received upload:\n\n');
res.end(util.inspect({
fields: fields,
files: files
}));
});
form.on('end', function() {
callback(null);
});
}
function UpdateCode(callback) {
var obj = fs.readFileSync('app.json', 'utf8');
var object = JSON.parse(obj);
var data2 = [];
for (var j = 0; j < object.length; j++) {
if (object[j].value == "TEST") {
data2.push(object[j]);
}
}
console.log(data2);
fs.appendFile('final.json', JSON.stringify(data2), function(err) {
if (err) throw err;
console.log('Saved!');
callback(null);
});
}
async.series([
downloadUpload,
UpdateCode
], function(err, result) {
if (err) throw err;
else {
console.log(result);
}
});
Also use nodemon -e js app.js. Otherwise nodemon will restart the program as soon as the json uploads.

Perform print operation on cups using Node.js

I would like to print documents through http requests on Node.js. Is there any way to send print jobs and query CUPS server using Node.js. I found this project while exploring around, is it the only/correct way to do that??
You could use the shell to do so. I built a project some time ago where I needed to read certain hashtag from instagram and print the photos uploaded to IG with that hashtag using a raspberry pi and a photo printer.
var fs = require('fs'),
exec = require('child_process').exec;
exec("lp /path/to/somepic.jpg");
// get printer jobs
exec("lpq",function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
The command lp /path/to/somepic.jpg sends /path/to/somepic.jpg to the default printer. The command lpq displays the printer queue. For better use, read the CUPS documentation.
Following snippet seems useful. Not tried it as I am no longer working on this problem!
It may be helpful for others. Original source: https://gist.github.com/vodolaz095/5325917
var ipp = require('ipp'); //get it from there - https://npmjs.org/package/ipp - $npm install ipp
var request = require('request'); //get it from there - https://npmjs.org/package/request - $npm install request
var fs = require('fs');
function getPrinterUrls(callback) {
var CUPSurl = 'http://localhost:631/printers';//todo - change of you have CUPS running on other host
request(CUPSurl, function (error, response, body) {
if (!error && response.statusCode == 200) {
var printersMatches = body.match(/<TR><TD><A HREF="\/printers\/([a-zA-Z0-9-^"]+)">/gm);//i know, this is terrible, sorry(
var printersUrls = [];
var i;
if (printersMatches) {
for (i = 0; i < printersMatches.length; i++) {
var a = (/"\/printers\/([a-zA-Z0-9-^"]+)"/).exec(printersMatches[i]);
if (a) {
printersUrls.push(CUPSurl + '/' + a[1]);
}
}
}
}
callback(error, printersUrls);
});
};
function doPrintOnSelectedPrinter(printer, bufferToBePrinted, callback) {
printer.execute("Get-Printer-Attributes", null, function(err, printerStatus){
if(printerStatus['printer-attributes-tag']['printer-state']=='idle'){
//printer ready to work
//*/
printer.execute("Print-Job",
{
"operation-attributes-tag":{
"requesting-user-name":"nap",
"job-name":"testing"
},
"job-attributes-tag":{},
data:bufferToBePrinted
},
function (err, res) {
if (res.statusCode == 'successful-ok') {
var jobUri = res['job-attributes-tag']['job-uri'];
var tries = 0;
var t = setInterval(function () {
printer.execute("Get-Job-Attributes",
{"operation-attributes-tag":{'job-uri':jobUri}},
function (err2, job) {
// console.log(job);
if (err2) throw err2;
tries++;
if (job && job["job-attributes-tag"]["job-state"] == 'completed') {
clearInterval(t);
// console.log('Testins if job is ready. Try N '+tries);
callback(null, job);//job is succesefully printed!
}
if (tries > 50) {//todo - change it to what you need!
clearInterval(t);
printer.execute("Cancel-Job", {
"operation-attributes-tag":{
//"job-uri":jobUri, //uncomment this
//*/
"printer-uri":printer.uri, //or uncomment this two lines - one of variants should work!!!
"job-id":job["job-attributes-tag"]["job-id"]
//*/
}
}, function (err, res) {
if (err) throw err;
console.log('Job with id '+job["job-attributes-tag"]["job-id"]+'is being canceled');
});
callback(new Error('Job is canceled - too many tries and job is not printed!'), null);
}
});
}, 2000);
} else {
callback(new Error('Error sending job to printer!'), null);
}
});
//*/
} else {
callback(new Error('Printer '+printerStatus['printer-attributes-tag']['printer-name']+' is not ready!'),null);
}
});
}
function doPrintOnAllPrinters(data, callback) {
var b = new Buffer(data, 'binary');
getPrinterUrls(function (err, printers) {
if (err) throw err;
if (printers) {
for (var i = 0; i < printers.length; i++) {
var printer = ipp.Printer(printers[i]);
doPrintOnSelectedPrinter(printer, b, callback);
}
} else {
throw new Error('Unable to find printer. Do you have printer installed and accessible via CUPS?');
}
});
}
/*
Example of usage
*/
fs.readFile('package.json', function (err, data) {
doPrintOnAllPrinters(data, function (err, job) {
if (err) {
console.error('Error printing');
console.error(err);
} else {
console.log('Printed. Job parameters are: ');
console.log(job);
}
}
);
});

Unable to send a response while multipart form is being streamed

I'm using nodejs combined with sailsjs and skipper to upload files to a server.
I have a use case where I need to check the file length and send a 413 error if the upload exceeds A certain file size. However when I try send any kind of response nothing happens. What exactly is happening here? Does the form upload need to be completed before a response can be sent?
var getReceiver = function () {
var receiver = new Writable({objectMode: true});
receiver._write = function (file, enc, done) {
file.fd = directory + file.fd;
var fileStream = fs.createWriteStream(file.fd);
fileStream.on('error', function (err) {
done(err);
}).once('finish', function () {
done();
});
var fileLength = 0;
file.on('data', function (chunk) {
fileLength = fileLength + chunk.length;
if (fileLength > maxFileSize) {
var err = new Error('upload exceeds maxFileSize.');
file.unpipe();
fs.unlink(file.fd, function (fsErr) {
if (fsErr && (typeof fsErr !== 'object' || fsErr.code !== 'ENOENT')) {
return done([err].concat([fsErr]));
}
});
return done(err);
}
});
file.pipe(fileStream);
};
return receiver;
};
req.file('file').upload(getReceiver(), function (err, uploadedFiles) {
if (err) {
return res.badRequest(err);
}
// Do stuff
}
});
});
});

Node.js : show process while copying files

I wrote a function to copy a directory to another... But there's a problem : I use callback function to send the copied size. This callback comes too early (before the end of the copy). I think the problem is that the process is asynchronous. Can you help me?
var fs=require('fs');
var copyDir=function copyDir(from, to, callback){
if(!fs.existsSync(to)){
fs.mkdirSync(to);
}
console.log(from+" ==> "+to);
var count = 0;
fs.readdir(from, function(err,files){
for(var i=0;i<files.length;i++){
var f = from+"/"+files[i];
var d = f.replace(from, to);
console.log(f+" ("+i+")"+ " : "+d);
if(!fs.existsSync(d)){
if(!fs.statSync(f).isFile()){
//fs.mkdirSync(f.replace(from, to));
count += fs.statSync(f).size;
console.log(f + " will make an inception!")
copyDir(f, f.replace(from, to), function(err, cp){callback(err, cp)});
}else{
var size = fs.statSync(f).size;
copyFile(f, f.replace(from, to), function(err){
if(err) callback(err, count)
});
count += size;
callback(null, count);
}
}
}
});
}
function copyFile(source, target, cb) {
fs.readFile(source, function (err, data) {
if (err) throw err;
fs.writeFileSync(target, data, function (err, data){
if(err) throw err;
cb(null, fs.statSync(source).size); //This callback comes before the copy end.
});
});
}
exports.copyDir = copyDir;
copyDir is called by:
io.sockets.on('connection', function(socket){
console.log('connection');
socket.on('startCopy', function(data){
sizeDir('templates', function(e, r){
copyDir('templates', 'tmp', function(err, cp){
console.log("copy % " + Math.round(100*cp/r));
socket.emit('copy', {prog: Math.round(100*cp/r)});
});
});
});
});
You can rewrite your else code with following:
(function() {
var size = fs.statSync(f).size;
copyFile(f, f.replace(from, to), function(err){
if(err) {
callback(err, count);
return;
}
count += size;
callback(null, count);
});
})();
But, you have a lot of synchronous function in your code. You should know about all caveats of this approach. This article may be helpful

Nodejs asynchronus callbacks and recursion

I would like to do something like this
function scan(apath){
var files = fs.readdirSync(apath);
for(var i=0; i<files.length;i++){
var stats = fs.statSync(path.join(apath,files[i]))
if(stats.isDirectory()){
results.push(path.join(apath, files[i]))
scan(path.join(apath,files[i]))
}
if(stats.isFile()){
results.push(path.join(apath,files[i]))
}
}
}
but asynchronously.
Trying this with asynchronous functions led me to a nightmare with something like this.
function scan(apath){
fs.readdir(apath, function(err, files)){
var counter = files.length;
files.forEach(function(file){
var newpath = path.join(apath, file)
fs.stat(newpath, function(err, stat){
if(err) return callback(err)
if(stat.isFile())
results.push(newpath)
if(stat.isDirectory()){
results.push(newpath)
scan(newpath)
}
if(--counter <=0) return
})
})
}
}
All hell breaks loose in node's stack because things don't happen in logical succession as they do in synchronous methods.
you can try async module, and use like this:
function scan(apath, callback) {
fs.readdir(apath, function(err, files) {
var counter = 0;
async.whilst(
function() {
return counter < files.length;
},
function(cb) {
var file = files[counter++];
var newpath = path.join(apath, file);
fs.stat(newpath, function(err, stat) {
if (err) return cb(err);
if (stat.isFile()) {
results.push(newpath);
cb(); // asynchronously call the loop
}
if (stat.isDirectory()) {
results.push(newpath);
scan(newpath, cb); // recursion loop
}
});
},
function(err) {
callback(err); // loop over, come out
}
);
});
}
look for more about async.whilst

Resources