I am using Multer for uploading images in my fs. Multer doesn't allow you to set dynamically the position in the fs, so I am uploading always in the same folder and then I am changing the name of the folder using fs.renamesynch.
I am using the synch version because I think that I have to wait for the end of the task, otherwise, I will have problems in the following task that need synchronization with the renaming function.
However, I have intermittent errors and I don't know how to solve it
Here is my code:
router.post("/changeprofile", ensureAuthenticated, (req, res) => {
upload(req, res, err => {
if (err) {
res.render("changeprofile", { msg: err });
} else {
if (req.file == undefined) {
res.render("changeprofile", { msg: "Error: No file Selected!" });
} else {
res.render("changeprofile", {
msg: "File Uploaded!",
file: `uploads/${req.file.filename}`
});
fsextra.removeSync("./public/profile" + id);
if (err) console.log(err);
else console.log("Deleted old folder");
glob("./public/uploads/profile.*", (err, matches) => {
if (err) console.log(err);
else {
console.log("renaming folder...");
fs.renameSync("./public/uploads", "./public/profile/" + id);
if (err) console.log(err);
else {
fs.mkdir("./public/uploads", err => {
if (err) console.log(err);
else
console.log(
"------------------FOLDER RECREATED---------------------------"
);
});
}
}
});
}
}
});
});
Here is the error that I get:
Error: EPERM: operation not permitted, rename './public/uploads' -> './public/profile/21'
at Object.renameSync (fs.js:593:3)
at glob (C:\Users\Andrea\Desktop\LinkedinLikeSocialNetwork\routes\users.js:558:19)
at f (C:\Users\Andrea\Desktop\LinkedinLikeSocialNetwork\node_modules\once\once.js:25:25)
at Glob. (C:\Users\Andrea\Desktop\LinkedinLikeSocialNetwork\node_modules\glob\glob.js:151:7)
at Glob.emit (events.js:189:13)
at Glob._finish (C:\Users\Andrea\Desktop\LinkedinLikeSocialNetwork\node_modules\glob\glob.js:197:8)
at done (C:\Users\Andrea\Desktop\LinkedinLikeSocialNetwork\node_modules\glob\glob.js:182:14)
at Glob._processReaddir2 (C:\Users\Andrea\Desktop\LinkedinLikeSocialNetwork\node_modules\glob\glob.js:434:12)
at C:\Users\Andrea\Desktop\LinkedinLikeSocialNetwork\node_modules\glob\glob.js:371:17
at RES (C:\Users\Andrea\Desktop\LinkedinLikeSocialNetwork\node_modules\inflight\inflight.js:31:16)
at f (C:\Users\Andrea\Desktop\LinkedinLikeSocialNetwork\node_modules\once\once.js:25:25)
at Glob._readdirEntries (C:\Users\Andrea\Desktop\LinkedinLikeSocialNetwork\node_modules\glob\glob.js:578:10) at C:\Users\Andrea\Desktop\LinkedinLikeSocialNetwork\node_modules\glob\glob.js:555:12
at go$readdir$cb (C:\Users\Andrea\Desktop\LinkedinLikeSocialNetwork\node_modules\graceful-fs\graceful-fs.js:162:14)
at FSReqWrap.args [as oncomplete] (fs.js:140:20)
Even if I didn't get an answer I think that I arrived at a solution:
I think that the problem is this. When you are using the sync method you probably think that node will be synchronized also with the operating system in deleting and renaming your folder inside the file system. But it seems like it is not: it will call the operative system with some kernel function but then the management of the fs is made by the os and node doesn't wait for the return of the function, even if you are using the synchronous mode. It could happen for example that all the I/O operation will be buffered and then executed all together to improve the performance of the os.
The right idea would be to flush the os caches after that you have executed the fs operation. However, using fs-extra and graceful-fs I think that it is now working:
var fs = require("graceful-fs");
const fsextra = require("fs-extra");
fs.gracefulify(realfs);
router.post("/changeprofile", ensureAuthenticated, (req, res) => {
upload(req, res, err => {
if (err) {
res.render("changeprofile", { msg: err });
} else {
if (req.file == undefined) {
res.render("changeprofile", { msg: "Error: No file Selected!" });
} else {
res.render("changeprofile", {
msg: "File Uploaded!",
file: `uploads/${req.file.filename}`
});
var path = "./public/profile/" + id;
if (fsextra.existsSync(path)){
fsextra.removeSync(path);
}
if (err) console.log(err);
else console.log("Deleted old folder");
glob("./public/uploads/profile.*", (err, matches) => {
if (err) console.log(err);
else {
console.log("renaming folder...");
fs.renameSync("./public/uploads", "./public/profile/" + id);
if (err) console.log(err);
else {
fs.mkdir("./public/uploads", err => {
if (err) console.log(err);
else
console.log(
"------------------FOLDER RECREATED---------------------------"
);
});
}
}
});
}
}
});
});
Related
class gameInfo {
static async gameeee(req, res) {
try {
console.log(req.body);
await db.adb
.collection("game")
.findOne({ req.body.gameID}, async (err, result) => {
console.log("a");
if (err) {
console.log("b");
res.status(400);
} else if (result === null) {
console.log("c"); <------- this is called
res.status(404); <------ not happening
} else if (result !== null) {
res.json({ result });
}
});
} catch (err) {
console.log(err);
res.status(400);
}
}
}
console result is
a
c
I am trying to simulate the response failure due to no data. However, res.status(404) is not working. How can I send the error?
Also, I am super confused with among res.send, res.status and res.sendStatus. What are the differences using these three?
You still need to send or end the response, see https://expressjs.com/en/api.html#res.status:
res.status(404).end();
And yes, as the documentation says, you could just use sendStatus instead.
res.sendStatus(404) // equivalent to res.status(404).send('Not Found')
I've been trying to add a use case to my code in which I try to unzip a zip that is too large to fit in the disk space and I expect my code to throw ENOSPC. I've tried multiple libraries but none of them throw error rather fail silently without completing the zipping. I'd expect them to throw ENOSPC error but all the packages seem to log the first info statement which states that the unzipping has been started but nothing after that. Most of them create incomplete folders, whatever they could write before disk went out of space. Here is how my code looks like for each of the libraries.
My code using adm-zip:
exports.unzip = function(source, destination) {
console.info("Started un-zipping from source: %s to destination: %s", source, destination);
try {
const zip = new AdmZip(source);
zip.extractAllTo(destination, true);
console.info("done unzipping");
} catch (error) {
console.error("Unzipping failed. Reason: %s", error)
throw new Error(error)
}
};
Code using yauzl:
exports.extractZip = function(source, destination) {
return new Promise(function(resolve, reject) {
console.log("Extracting zip: '" + source + "' to '" + destination + "'");
yauzl.open(source, {
lazyEntries: true
}, function(err, zipfile) {
if (err) throw err;
zipfile.readEntry();
zipfile.on("error", function (err) {
console.error("Something went wrong while extracting!");
reject(new Error(err));
});
zipfile.on("end", function () {
console.log("Completed extracting zip!");
resolve();
});
zipfile.on("entry", function(entry) {
if (/\/$/.test(entry.fileName)) {
// directory file names end with '/'
mkdirp(destination + '/' + entry.fileName, function(err) {
if (err) {
console.error("Something went wrong while extracting!");
throw err;
}
zipfile.readEntry();
});
} else {
// file entry
zipfile.openReadStream(entry, function(err, readStream) {
if (err) {
console.error("Something went wrong while extracting!");
throw err;
}
// ensure parent directory exists
mkdirp(destination + '/' + path.dirname(entry.fileName), function(err) {
if (err) throw err;
readStream.pipe(fs.createWriteStream(destination + '/' + entry.fileName));
readStream.on("end", function() {
zipfile.readEntry();
});
});
});
}
});
});
});
}
Code using Unzipper:
exports.unzip2 = function(source, destination) {
console.info("Started un-zipping from source: %s to destination: %s", source, destination);
try {
fs.createReadStream(source)
.pipe(unzipper.Extract({ path: destination }))
.on('error',function (err){
console.error("something went wrong", err.code);
throw err;
});
} catch (error) {
console.error("Unzipping failed. Reason: %s", error)
throw new Error(error)
}
};
Code Using extract-zip:
exports.extractArchive = async function(source, destination) {
try {
extract(source, { dir: destination }, function (err) {
if (err) {
console.error("Something went wrong!", err.code);
throw err;
}
});
console.log('Extraction complete')
} catch (err) {
// handle any errors
}
};
Is there something wrong with my code ? Is there any special event that I need to listen on ?
After some trail and error on both Yauzl and unzipper, unzipper seemed to work (throw ENOSPC when ran out of disk space during unzipping) with the following code.
exports.unzip2 = function(source, destination) {
return new Promise(function(resolve, reject) {
console.info("Started un-zipping from source: %s to destination: %s", source, destination);
try {
var sourceStream = fs.createReadStream(source);
sourceStream.on('error',function (err){
console.error("something went wrong", err.code);
reject(new Error(err));
});
var destinationStream = unzipper.Extract({ path: destination });
destinationStream.on('error',function (err){
console.error("something went wrong", err.code);
reject(new Error(err));
});
destinationStream.on('close',function (){
console.log("Completed extract!");
resolve();
});
sourceStream.pipe(destinationStream).on('error',function (err){
console.error("something went wrong", err.code);
reject(new Error(err));
});;
} catch (error) {
console.error("something went wrong", err.code);
reject(new Error(err));
}
});
};
Here is my code that tries to update a record in the db.
But if the record is not there then I want to insert it.
Is it OK to call client.query again? Or what's the best way to do it?
const {Pool} = require('pg');
const pool = new Pool(POSTGRES_CONFIG);
pool.connect((err, client, release) => {
if (err) {
return console.error('Error acquiring client', err.stack)
}
………
client.query(query, queryValues, (err, result) => {
release();
if(result.rowCount<=0){
//**** CAN I CALL IT AGAIN WITH OTHER PARAMETERS TO INSERT? ****
client.query(....... => {
release();
if (err) {
if(err.code === POSTGRES_ERRORS.UNIQUE_VIOLATION){
return console.error('KEY ALREADY EXISTS');
} else {
return console.error('query error', err);
}
}
}
}
});
});
It is perfectly OK as long as you call release after you're done with the client. From the docs:
You must call the releaseCallback or client.release (which points to
the releaseCallback) when you are finished with a client.
So, you could do this:
client.query(query, queryValues, (err, result) => {
// don't release just yet
if(result.rowCount<=0){
//**** CAN I CALL IT AGAIN WITH OTHER PARAMETERS TO INSERT? ****
client.query(....... => {
release(); // now you're done with the client so you can release it
if (err) {
if(err.code === POSTGRES_ERRORS.UNIQUE_VIOLATION){
return console.error('KEY ALREADY EXISTS');
} else {
return console.error('query error', err);
}
}
}
}
});
I am new to nodejs and trying to cat multiple css files on-the-fly while coding. The package chokidar allow me to call a function when a file is modified, however I have a problem with the execution.
var goconcat =
fs.readdir(paths, function (err, files) {
if (err) {console.log(err);}
fs.unlink(paths + 'concat.css', function (err) {
if (err) throw err;
var list = files.map(function (files) {
return path.join(paths, files);
});
concat(list, paths + 'concat.css', function(err) {
if (err) throw err
});
});
});
I want to first delete the previous file, then read the directory and then write a new "concat.css". However I have an error;
Error: ENOENT: no such file or directory, open 'public/css/concat.css'
at error (native)
It appears that the function concat() is executed before the directory update and not after, and therefore it is trying to cat a file that just have been deleted. Why ?
I know that nodejs is executing functions in a synchronous way but I can't find a way to solve this problem. I tried async but I can't declare a variable between two functions and I couldn't manage to make it work.
If it cannot exist in a callback, using the setTimeout(fn, 0) trick may help make sure it's executed after the variable assignment.
var goconcat =
fs.readdir(paths, function (err, files) {
if (err) {console.log(err);}
fs.unlink(paths + 'concat.css', function (err) {
if (err) throw err;
var list = files.map(function (files) {
return path.join(paths, files);
});
setTimeout(function() {
concat(list, paths + 'concat.css', function(err) {
if (err) throw err
})}, 0);
});
});
The problem you're having is that your concat function is being invoked before the file is deleted by invoking unlink. You can prevent this by having nested callbacks; however, you can probably have better control flow if you use a module like async, and prevent yourself from dealing with Callback Hell.
Below is an example on how you can use the async module.
var fs = require('fs');
var async = require('async');
var myDir = __dirname + '/data';
async.waterfall([function(callback) {
fs.readdir(myDir, 'utf-8', function(error, files) {
if (error) {
return callback(error);
}
return callback(null, files);
});
}, function(files, callback) {
fs.open(myDir + '/myFile', 'wx', function(error, f) {
if (error && error.code === 'EEXIST') {
return callback(null, 'EEXIST');
}
return callback(null, 'CREATE');
});
}, function(fileStatus, callback) {
if (fileStatus === 'EEXIST') {
console.log('File exists. Deleting file...');
fs.unlink(myDir + '/myFile', function(error) {
if (error) {
return callback(error);
} else {
return callback(null);
}
});
} else {
console.log('File does not exist...');
return callback(null);
}
}, function(callback) {
fs.writeFile(myDir + '/myFile', "Hello World", function(err) {
if(err) {
return callback(error);
}
return callback(null, 'File Created');
});
}], function(error, results) {
console.error(error);
console.log(results);
});
The waterfall function runs the tasks array of functions in series,
each passing their results to the next in the array. However, if any
of the tasks pass an error to their own callback, the next function is
not executed, and the main callback is immediately called with the
error.
With this as a URL:
'api/support-tag/name/myTagName'
This function works properly:
getByName: function (req, res) {
model.Shared_SupportTag.findOne({name: req.params.name}).exec(function (err, results) {
if (err) {
return res.status(400).send({
message: errMsg.Util_ErrorMsg.getErrorMessage(err)
});
}
res.send(results);
})
}
But when I try to call a similar function from within the node server:
supportDoc.category = GetById(item.category);
function GetById(name){
model.Shared_SupportTag.findOne({name: name}).exec(function(err, result){
if(err){
console.log(err)
}else{
console.log(result);
}
})
}
The function does not execute, nor does the error catch, intellisense shows:
err= Reference error; err is not defined
result = Reference error; result is not defined
All I am trying to accomplish is a function call from within the server and not via a URL.
Any solution here? Thanks in advance
In the case of the findOne() method, the positive response (sans error) will either hold a mongoose object or null.
If the same query had been sent using just find(), the result would have been an empty array.
function GetById(name){
model.Shared_SupportTag.findOne({name: name}).exec(function(err, result){
if(err){
console.log(err)
}else{
if (result) console.log(result); //Check whether object exists.
else console.log('Not found!');
}
})
}
Solved:
model.Shared_SupportDoc.find({}).exec(function (err, collection) {
var supportDocs = require('../../data/_seed/support/supportDocs.json');
if (collection.length === 0) {
supportDocs.forEach(function (item) {
var supportDoc = new model.Shared_SupportDoc;
supportDoc.title = item.title;
supportDoc.created = item.date;
supportDoc.icon = item.icon;
supportDoc.likeCount = item.likeCount || 7;
-----> // requires callback - ie asynchronous
GetByName(item.category, function(tagId) {
supportDoc.categoryId = tagId;
-----> // must put save in the callback
supportDoc.save(function (err) {
if (err) {
console.log(supportDoc.categoryId)
console.log('Error: ' + err);
} else {
console.log('Support Doc Seed Complete');
}
});
});
})
}
});}
function GetByName(name, next) {
model.Shared_SupportTag.findOne({name : name}).exec(function (err, result) {
if (!result) {
console.log('Not Found');
next();
} else {
console.log(result._id);
next(result._id);
}
});}