Node.js EXDEV rename error - javascript

I've been playing with some code I found in a book about Node.js. It is a simple app which uploads images.
It shows the EXDEV error (500 Error: EXDEV, rename).
Could someone give me a hint? Here's my code:
exports.submit = function(dir) {
return function(req, res, next) {
var img = req.files.photo.image;
var name = req.body.photo.name || img.name;
var path = join(dir, img.name);
fs.rename(img.path, path, function (err) {
if(err) return next(err);
Photo.create({
name: name,
path: img.name
}, function (err) {
if(err) return next(err);
res.redirect('/');
});
});
};
};

Renaming files cannot be done cross-device. My guess is that your upload directory (which by default is /tmp) is on another partition/drive as your target directory (contained in the dir variable).
Some solutions:
configure the upload directory to be on the same partition/drive as your target directory; this depends on which module you're using to handle file uploads, express.bodyParser (and the module it uses, connect.multipart) accepts an uploadDir option that you can use;
before starting your Node app, set the TMPDIR environment variable to point to a temporary directory on the same partition/drive as your target directory. If you're using a Unix-type OS:
env TMPDIR=/path/to/directory node app.js
instead of setting the environment variable from your shell, set it at the top of your Node app:
process.env.TMPDIR = '/path/to/directory';
instead of renaming, use a module like mv that can work cross-device;

Using Windows XP, I added to app.js:
process.env.TMPDIR = '.'; //new

Related

Fs file handler for api

So I want to make a routes folder that has subfolders that contain routes but I don't know how to use fs with it...
I only know how to get files in the routes folder and not in subfolders
here is my file handler code
const { readdirSync } = require('fs');
module.exports = function(app){
readdirSync(__dirname).forEach(function(file) {
if (file == "index.js") return;
var name = file.substr(0, file.indexOf('.'));
const route = require('./' + name)
app.get(`/${route.name}`, async (req, res) => {
route.run(req, res)
})
});
}
it gets the files from the routes folder
-routes
|__index.js
|__route.js
|__route.js
I want to make it so it gets routes from subfolders
-routes
|__index.js
|
|__image routes
|__route1.js
I can't find any help online...
If you do not mind using external libraries i recommend using glob
What you want to do can be achieved with one function call:
const glob = require("glob");
glob("**/*.js", {cwd: __dirname}, (error, matches) => {
if (error) return;
console.log(matches);
})
This uses glob patterns to much files in a given directory, returning the whole paths like: image-routes/route1.js or index.js etc.

How to resolve path issues while moving files in node.js?

I am trying to get a file from html form and store it in another folder. It's basically cloud function, and I am new to both node.js and firebase so don't know what I am doing wrong. What I manage to do is:
const fileMiddleware = require('express-multipart-file-parser');
app.post("/sendMail", (req, res) => {
const {
fieldname,
filename,
encoding,
mimetype,
buffer,
} = req.files[0];
console.log(req.files[0].originalname);
var fs = require('fs')
var oldPath = req.files[0].originalname;
var newPath = '/functions/'+oldPath;
fs.rename(oldPath, newPath, function (err) {
if (err) throw err
console.log('Successfully renamed - AKA moved!')
});
});
Whenever I try to move file, I got path issues. The error is as follows:
[Error: ENOENT: no such file or directory, rename 'C:\Users\Maisum Abbas\now\functions\sendMail.txt'
> 'C:\functions\sendMail.txt'] {
> errno: -4058,
> code: 'ENOENT',
> syscall: 'rename',
> path: 'C:\\Users\\Maisum Abbas\\now\\functions\\sendMail.txt',
> dest: 'C:\\functions\\sendMail.txt'
> }
Also, this is the path where I want to actually move the file but oldpath is already setup like this.
C:\Users\Maisum Abbas\now\functions\sendMail.txt
Since I needed to attach a file with email, it was causing path issues. I tried it with multer and it works. What I did:
//call libraries here
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, 'resume/');
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now());
}
});
var upload = multer({ storage : storage}).single('filetoupload');
app.post("/careerMail", (req, res) => {
const { name } = req.body;
const { email } = req.body;
const { phone } = req.body;
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
});
const dest = 'mymail';
const mailOptions = {
from: email, // Something like: Jane Doe <janedoe#gmail.com>
to: dest,
subject: 'Candidate Application', // email subject
html: `<div>
<strong>From:</strong> ` +
name +
`<br /><br />
<strong>Email:</strong> ` +
email +
`<br /><br />
<strong>Phone:</strong> ` +
phone +
`<br /><br />
</div>
`,// email content in HTML
attachments: [
{
filename: req.files[0].originalname,
content: req.files[0].buffer.toString("base64"),
encoding: "base64"
}
]
and rest of the code...
I suggest rethinking this approach altogether. You won't be able to move files around in a deployed function. The nodejs runtime filesystem doesn't allow any files to be written anywhere in the filesystem, except for os.tmpdir() (which is /tmp on Linux).
If you need to write a file temporarily, you should definitely only use that tmp space. Be aware that files written there occupy memory and should be deleted before the function terminates, or you could leak memory.
You can read files that you deployed with your code, but you should do that through relative paths.
I ran into same problem while moving file. I sort this problem by using a function to get the application root folder and then concatenate rest of the location.
//place this file on application root.
//import where you need to get the root path.
const path = require('path');
module.exports = (function(){
return path.dirname(require.main.filename || process.mainModule.filename);
})();
//taking your case move location.
const rootPath = //require the above module.
const newPath = rootPath + /functions/' +oldPath;
fs.rename(oldPath, newPath, function (err) {
if (err) throw err
console.log('Successfully renamed - AKA moved!')
});

Node.js raises error when trying to make directory using mkdirp

I am trying to download and later serve images using Node.js. I need to save each image in a directory specified by the url. My code for downloading images gets stuck because there is no directory to save them to. I am trying to create one using mkdirp but keep getting the error [Error: EACCES: permission denied, mkdir '/20110'] errno: -13, code: 'EACCES', syscall: 'mkdir', path: '/20110'. Here is my full code:
controller.serveImages = function(req, res, connection) {
var file = "/" + req.params.attachmentId + "/" + req.params.attachmentFileName;
console.log("serve called", file);
var fs = require('fs'),
request = require('request');
var mkdirp = require('mkdirp');
mkdirp( "/" + req.params.attachmentId, function (err) {
if (err) console.error(err)
else console.log('Directory made!')
});
fs.readFile(file, function(error, data) {
console.log("reading");
if(error){
if (error.code === 'ENOENT') { //File not downloaded
var download = function(uri, filename, callback){
request.head(uri, function(err, res, body){
console.log('content-type:', res.headers['content-type']);
console.log('content-length:', res.headers['content-length']);
request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
});
};
download('https://www.google.com/images/srpr/logo3w.png', file, function(){
console.log('done');
});
}
else{
console.log(error)
}
}
else{
console.log("Found locally", data, file);
res.sendFile(file);
}
});
};
The code is adapted from here. An example request would be /20110/TNCA+PB.png. With that I would want to create a directory /20110 and save TNCA+PB.png there.
Seems that you're trying to create the folder at File System root level. Have you tried to create the folder under the application folder instead? Writing to root level is never a good idea.
Here are some suggestions to get the app running path Determine project root from a running node.js application , then you can append that to your mkdirp function.
Regards

Wildcards in ServiceWorker / Cache API

I am using ServiceWorker and in dev mode works perfectly, my problem is that in production mode my bundle name is generated using hash, e.g. 1234das3123ad5.bundle.js, so the service worker is not caching it. My sw code looks like:
self.addEventListener('install', function(event) {
// pre cache a load of stuff:
event.waitUntil(
caches.open('mycache').then(function(cache) {
return cache.addAll([
'/dist/bundle.js',
'/dist/app.css',
'/dist/index.html',
'https://cdnjs.cloudflare.com/ajax/libs/antd/2.7.2/antd.css'
]);
})
)
});
In the docs of Cache API I dont see any example on how I can achieve that.
Obviously I could cache everything under the dist folder, having something like:
self.addEventListener('install', function(event) {
// pre cache a load of stuff:
event.waitUntil(
caches.open('mycache').then(function(cache) {
return cache.addAll([
'/dist/',
]);
})
)
});
But I dont find it an elegant, good in long term, solution. Is it a way to have wild cards in the Cache? Something like '/dist/*.bundle.js' ?
The web doesn't have the concept of folders, specifically there isn't a way for a browser to know all the valid URLs starting with a prefix.
The rest of your site must be handling the URL changes for revisioning assets somehow, so why not use the same solution in your service worker?
That's what I did for my blog - Django's static file manager adds the correct URLs https://jakearchibald.com/sw.js
here's a simple Node script that will create the array of filenames for you, provided you want a list of every file in your web/public directory. NOTE: you want to run this from a terminal at your public directory.
var fs = require('fs');
var path = require('path');
var util = require('util');
var walk = function(dir, done) {
var results = [];
fs.readdir(dir, function(err, list) {
if (err) return done(err);
var i = 0;
(function next() {
var file = list[i++];
if (!file) return done(null, results);
//file = dir + '/' + file;
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
results = results.concat(res);
next();
});
}
else {
file = file.replace('/home/ubuntu/workspace/public', '');
results.push(file);
next();
}
});
})();
});
};
var mydir = path.resolve(__dirname);
walk(mydir, function(err, results) {
if (err) throw err;
console.log(util.inspect(results, { maxArrayLength: null }));
});
I was experiencing some issues with this, with a vue3 pwa.
So this is not a true answer, but rather a hopefully valuable reply.
With vue3, the service worker file that is generated, includes:
importScripts(
"/precache-manifest.\<something-something\>.js"
);
and the precache-manifest.js file that is generated, lists all the js, css and font stuff that is built when doing a "vue-cli-serve build", e.g. something like:
self.__precacheManifest = (self.__precacheManifest || []).concat([
{
"revision": "f715169493da60af08a445c4f7990905",
"url": "/.htaccess"
},
{
"revision": "87260e830ed912c46685c0a5432addf2",
"url": "/.well-known/web-app-origin-association"
},
<snip>
The workbox script then takes this list and caches the mentioned files.

NodeJs : modules.export : Cannot find one of my own custom module

I am trying to include my own users.js module to my router file. It keeps throwing the error:
Cannot find module './router/users.js'
My directory structure is as follows:
nodejs (Main folder on my drive)
-- expressserver.js (My server file)
-- package.json
-- router (folder containing main.js router and users.js user details file)
----- main.js
----- users.js
----- orders.js
Here my users module is in the same folder as my router (main.js)
My code for router is:
var url = require('url');
var users = require('./router/users.js');
module.exports = function (app) {
app.get('/', function (req, res) {
res.render('index.html');
console.log("Home page displayed");
});
app.get('/login', function (req, res) {
res.render('login.html');
console.log("Log in page displayed");
});
app.get('/api/orders/:id', function (req, res) {
console.log(req.params.id);
res.json(ORDER.orders[req.params.id]);
});
app.get('/api/orders/', function (req, res) {
console.log(ORDER);
res.json(ORDER);
});
app.get('/api/users/:id', function (req, res) {
console.log(req.params.id);
res.json(USERS.users[req.params.id]);
});
app.get('/api/users/', function (req, res) {
console.log(USERS);
res.json(USERS);
});
My code for users.js:
module.exports = function () {
// Create User prototype and objects
var USERS = { users: [] };
function User(type, useremail, password) {
this.type = type;
this.useremail = useremail;
this.password = password;
}
var Bob = new User("rep", "bob#bob.com", "qwerty");
USERS.users.push(Bob);
var Helen = new User("rep", "helen#helen.com", "test");
USERS.users.push(Helen);
var Dominic = new User("customer", "dom#dom.com", "1234");
USERS.users.push(Dominic);
var James = new User("grower", "james#james.com", "pass1");
USERS.users.push(James);
};
I'm pretty new to this are but have been reading up alot on modules but still can't figure it out. Any suggestions on where I have gone wrong? or what I need to do to rectify the problem?
Note: Previously I did the same thing for including router into the server file using module.exports = function (app) { around my router and in my server as: require('./router/main')(app);
Since you have specified a relative path to the module, that path is relative to the directory of the source file where require is performed. In your case, it is already relative to the 'router' directory. This will work:
var users = require('./users.js');
Or even just the following, since the extension is automatically resolved:
var users = require('./users');
The path for require(), is set for node_modules folder by default.
That is why you are able to require all modules such as var url = require('url'); in your case.
If the module is not found there in your current project, the module will be searched globally(if there are path variables set on machine).
Now when you define custom modules , you can either keep them within the folder node_modules, OR you can give a path relative to your current JS file within which you are requiring the module.
For example,
var users = require('./users');
If there is another folder, in your current working directory, say modules,
then you can do require it like this:
router
----- main.js
----- orders.js
----------------modules(folder)
-----------------------users.js
var users = require('./modules/users');
So the path for require always starts from node_modules folder

Categories

Resources