Issue when sending multiple images in a GET Method in Nodejs - node.js

I am facing issue with sending image in a GET Method in node.js. As you can see in the below code the file is saved in a folder called images and the path of that file is stored in the Object.
I tried searching for the file in the directory and then convert it to base64 to send the images but instead all the files in the directory are being converted to base64 and sent. Hence if you could please help me in resolving this issue.
Please let me know if you require any further information from my end.
Router.js
router.get("/users/data/expand/:nid", async (req, res) => {
var idselected = req.params.nid;
var dir = "images";
try {
const checkData = await user.findOne({ user_id: idselected });
let receivedFile = await Promise.all(
checkData.attachments.flatMap(async element => {
let files = await readDirectory(dir);
return await Promise.all(
files.map(filename => {
filename = element;
return readFile(filename)
})
);
})
);
const returnUser = new User({
user_id: checkData.user_id,
attachments: receivedFile
});
let savedUser = await returnUser.save();
res.status(201).send(savedUser);
} catch (e) {
res.status(500).send(e);
}
});
function readDirectory(dir) {
return new Promise((res, rej) => {
fs.readdir(dir, function(err, files) {
if (err) {
rej(err);
} else {
res(files);
}
});
});
}
function readFile(filename) {
return new Promise((res, rej) => {
fs.readFile(filename, "base64", (err, base64Data) => {
if (err) {
rej(err);
}
res(base64Data);
});
});
}

Related

When trying to write image file it moves ahead and write works late

What i am trying to do here is i am writing a image file after resizing it with node and after that i will use it to upload it. but when i am writing it my uploading code started at that time and file is still not written.
async function getdataFromJimpSmall(image,filePath,FILE_NAME){
try{
var isSucess = false ;
const im = await Jimp.read(image);
return new Promise((resolve, reject) => {
try{
im.resize(150, 215, Jimp.RESIZE_BEZIER, function(err){
if (err) throw err;
});
im.write(filePath+FILE_NAME)
resolve(true)
}
catch(err){
console.log(err);
reject(false);
}
})
}
catch(err){
console.log('getdataFromJimpSmall Err====>'+err)
return false
}
}
I tried to use this but it is getting ahead of my code
it started from here and it is getting called from here.
isThumbnailUrlavailable = await jimpController.imageCoverJimpAndUploadToS3small(getISBNBook, "-#gmail.com", "SaleIsbn")
isThumbnailUrlavailableMedium = await jimpController.imageCoverJimpAndUploadToS3medium(getISBNBook, "-#gmail.com", "SaleIsbn")
And the first function imageCoverJimpAndUploadToS3small() is this:
exports.imageCoverJimpAndUploadToS3small = async (getContent,email,file) =>{
try{
var elementType = 15;
var filePath = path.join(__dirname, '../../uploads/t/')
var FILE_NAME = `${getContent.contentMetaDataRef.isbn}_s.jpg`
var image = getContent.thumbnail
let tempdata = await getdataFromJimpSmall(image,filePath,FILE_NAME)
console.log('temp - ', tempdata);
if(tempdata==true)
{
var data = await commonController.uploadthumbnailTOPublicS3(filePath, FILE_NAME)
console.log('s3', data);
requestImageSize(data.url).then(size =>
{
console.log(size);
if(size.height>0&&size.width>0)
{
tempdata=true;
const getContentElement = ContentElement.findOne({contentId: getContent._id,elementType,elementData: data.keyName}).lean()
if(getContentElement){
ContentElement.findByIdAndUpdate(getContentElement._id, {
createdOn: Date(), modifiedOn: Date(),
}, { new: true })
}
else
{
return tempdata;
}else
{
tempdata=false;
return tempdata;
}
}).catch(err =>
{
console.error(err);
tempdata=false;
return tempdata;
});
}
}
catch(error){
console.log(error)
tempdata=false;
return tempdata;
}
}
But it is not working...
Again i am calling imageCoverJimpAndUploadToS3small() and it starts after that.
as per docs https://www.npmjs.com/package/jimp#writing-to-files-and-buffers, .write runs asynchronously and takes a callback, which is why the promise resolves before image is written
so, you need to use callback, and resolve from there:
im.write(filePath+FILE_NAME, (err)=>{
if(err) throw err;
resolve(true);
});
or, as the docs say, you might use and await .writeAsync, which is promise-based:
await im.writeAsync(filePath+FILE_NAME);
resolve(true);

how to send response only after mv library on nodejs completes. Wrapping in promise doesn't work

I'm trying to setup an endpoint that takes a file through a multipart post request, and saves it into a specific directory using formidable and https://github.com/andrewrk/node-mv. And then upon completion of saving all of the files, I want to respond with a list of all of the files in that directory for rendering. the thing is the response seems to be sent before the directory listing is updated. I tried wrapping the mv operations into a promise and then responding in a then block to no avail. Any help would be much appreciated!
app.post("/api/v1/vendor/:id/menu", (req, res, next) => {
const id = req.params.id;
const form = formidable({ multiples: true, keepExtensions: true });
form.parse(req, (err, fields, files) => {
if (err) {
next(err);
return;
}
if (!Array.isArray(files.image)) {
files = [files.image];
}
let filelist;
const proms = files.map((file) => {
const dst = `pics/${id}/${file.name}`;
new Promise((resolve, reject) => {
mv(file.path, dst, { mkdirp: true }, (err) => {
if (err) {
console.error("error: ", err.status);
reject(err);
}
console.log("done moving");
resolve();
});
});
});
Promise.all(proms).then(() => {
console.log('now reading dir...');
filelist = fs.readdirSync("pics/" + id);
res.send(filelist);
});
});
});
I think we're missing the return keywork before new Promise. You can check the proms variable if it contains the list of promises or not.
const proms = files.map((file) => {
const dst = `pics/${id}/${file.name}`;
new Promise((resolve, reject) => {
mv(file.path, dst, { mkdirp: true }, (err) => {
if (err) {
console.error("error: ", err.status);
reject(err);
}
console.log("done moving");
resolve();
});
});
});
For me, it should be :
const proms = files.map((file) => {
const dst = `pics/${id}/${file.name}`;
return new Promise((resolve, reject) => {
mv(file.path, dst, { mkdirp: true }, (err) => {
if (err) {
console.error("error: ", err.status);
reject(err);
}
console.log("done moving");
resolve();
});
});
});

problem in sending base64 data in GET request

Hi I am facing issues sending base64 data in GET request.
I was successful in converting the image into base64 data and inserting it in receivedFile
but during response the attachments come as an empty array while the rest of the data i.e user_id is flowing successfully.
Hence if you could please help me to resolve this issue.
Below is the code
router.js
router.get('/users/data/expand/:nid',async (req,res) => {
var idselected = req.params.nid;
var dir = '\images';
var receivedFile = [];
try {
const checkData = await user.find({"user_id": idselected});
await checkData[0].attachments.forEach (element => {
fs.readdir(dir,function(err,files) {
if(err) {
console.log(err)
}else {
files.forEach((filename) => {
filename = element;
fs.readFile(filename,'base64', (err,base64Data) => {
if(err) {
console.log(err);
}
receivedFile.push(base64Data);
})
})
}
})
})
//issue is here the attachments is coming as empty instead of base64 data
const returnUser = new User({
user_id: checkData.user_id,
attachments: receivedFile
})
res.status(201).send(returnUser);
}
catch(e) {
res.status(500).send(e)
}
})
Well its always good to create helper functions and to promisfy it so you can use async / await syntax.
I have changed your code. I didnt tested it but i guess it should work:#
router.get("/users/data/expand/:nid", async (req, res) => {
var idselected = req.params.nid;
var dir = "images";
try {
const checkData = await user.findOne({ user_id: idselected });
let receivedFile = await Promise.all(
checkData.attachments.flatMap(async element => {
let files = await readDirectory(dir);
return await Promise.all(
files.map(filename => {
filename = element;
return readFile(filename)
})
);
})
);
const returnUser = new User({
user_id: checkData.user_id,
attachments: receivedFile
});
let savedUser = await returnUser.save();
res.status(201).send(savedUser);
} catch (e) {
res.status(500).send(e);
}
});
function readDirectory(dir) {
return new Promise((res, rej) => {
fs.readdir(dir, function(err, files) {
if (err) {
rej(err);
} else {
res(files);
}
});
});
}
function readFile(filename) {
return new Promise((res, rej) => {
fs.readFile(filename, "base64", (err, base64Data) => {
if (err) {
rej(err);
}
res(base64Data);
});
});
}
I guess you use mongoose.
There is an method called findOne and also you forgot to save your model with returnUser.save()

upload files to aws s3 from node js

I am using aws sdk to uplod user input image and then get the image link from aws and i will store the link in mongoDB. In that case when i run .upload() it is async.
const imgSRC = [];
for (let img of image) {
console.log(img);
const params = {
Bucket: process.env.AWS_BUCKET,
Key: `${img.originalname}_${userID}`,
Body: img.buffer,
};
s3.upload(params, (error, data) => {
if (error) {
console.log(error);
res.status(500).json({ msg: "server error" });
}
imgSRC.push(data.Location);
console.log(imgSRC);
});
}
const newPost = new Post({
userID: userID,
contentID: contentID,
posts: [
{
caption: caption,
data: imgSRC,
},
],
});
const post = await newPost.save();
in that case when the .save to mongodb run, there is no imgLinks from aws yet. How can i fix that things.
I've already tried async and it didn't work
You need to use Promise.all() in this manner
const uploadImage = (obj) => {
return new Promise((resolve, reject) => {
const params = {
Bucket: process.env.AWS_BUCKET,
Key: obj.key,
Body: obj.body,
}
s3.upload(params, (error, data) => {
if (error) {
console.log(error);
return reject(error);
}
return data;
});
})
}
const mainFunction = async () => {
const promises = [];
for (let img of image) {
const options = {
key: `${img.originalname}_${userID}`,
body: img.buffer
};
promises.push(uploadImage(options));
}
const result = await Promise.all(promises);
const imgSRC = result.map((r) => { return r.Location });
return imgSRC;
}
If you use await on s3.upload method you should remove the callback for this method.
try {
const data = await s3.upload(params);
imgSRC.push(data.Location);
console.log(imgSRC);
} catch(e) {
console.log(error);
res.status(500).json({ msg: "server error" });
}
Let me know if it works.

convert Base64 Image with expressjs

I have error convert image from FTP Server into Base64. For example :
router.get('/getPhoto', async function (req, res) {
const ftp = new PromiseFtp();
data='';
try {
await ftp.connect({ host: varFtp.host, user: varFtp.username, password: varFtp.password })
const stream = await ftp.get('store/photo1.jpeg');
data += stream.read().toString('base64');
console.log(data) -> this is erorr
await new Promise((resolve, reject) => {
res.on('finish', resolve);
stream.once('error', reject);
stream.pipe(res)
});
} catch(e) {
console.error(e);
} finally {
await ftp.end();
}
});
I have error TypeError: Cannot read property 'toString' of null. My end goal i will send Base64 to client with json format
You just need to pipe the base64 encode before sending it over. something like this using base64-stream can simplify this
const {Base64Encode} = require("base64-stream");
app.get("/getPhoto", async function (req, res) {
const ftp = new PromiseFtp();
data = "";
try {
await ftp.connect({ host: varFtp.host, user: varFtp.username, password: varFtp.password })
const stream = await ftp.get('store/photo1.jpeg');
await new Promise((resolve, reject) => {
res.on("finish", resolve);
stream.once("error", reject);
stream.pipe(new Base64Encode()).pipe(res); // see here
});
} catch (e) {
console.error(e);
} finally {
await ftp.end();
}
});
function getImage(imageUrl) {
var options = {
url: `${imageUrl}`,
encoding: "binary"
};
return new Promise(function (resolve, reject) {
request.get(options, function (err, resp, body) {
if (err) {
reject(err);
} else {
var prefix = "data:" + resp.headers["content-type"] + ";base64,";
var img = new Buffer(body.toString(), "binary").toString("base64");
// var img = new Buffer.from(body.toString(), "binary").toString("base64");
var dataUri = prefix + img;
resolve(dataUri);
}
})
})
}

Resources