So, I have been working on an upload script (code is below) that I have working on my windows machine, but on my Linux server it seems to fail with
Error: ENOENT, open 'uploads/da5ab67b48ea2deecd25127186017083'
I understand that the error is saying there is no path/file, but I do check to for file existence before I attempt the file rename.
exports.product_files_upload = function (req, res) {
if (req.files) {
var tmpArray = [];
for(var file in req.files){
console.log(file)
if (file){
var splitName = file.split('-');
if (splitName.length > 1) {
var username = splitName[0];
var productId = splitName[1];
var index = splitName[2];
} else {
return;
}
} else {
return;
}
//console.log(username)
//console.log(productId)
var tmp_path = req.files[file].path;
console.log(fs.existsSync(tmp_path))
createUserDir();
createProductDirs(username, productId);
//console.log(__dirname)
var target_path = './public/user_files/'+ username + '/products/'+productId+'/files/' + req.files[file].name,
save_path = 'user_files/'+ username + '/products/'+productId+'/files/' + req.files[file].name;
if (fs.existsSync(target_path)) {
tmpArray.push({exists:true, name:req.files[file].name});
} else {
tmpArray.push({
size: req.files[file].size,
type: req.files[file].type,
name: req.files[file].name,
path: save_path,
exists:false
});
if (fs.existsSync(tmp_path)) {
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
// delete the temporary file, so that the explicitly set temporary upload dir does not get filled with unwanted files
fs.unlink(tmp_path, function() {
if (err) throw err;
// res.send(save_path);
});
});
} else {
tmpArray.push({
size: req.files[file].size,
type: req.files[file].type,
name: req.files[file].name,
path: save_path,
exists:false
});
}
}
}
res.json(tmpArray);
}
};
UPDATE: I am using forever for running my express app, and when I stopped my app forever process and switched to just "node app.js" the problem was fixed. This is not an acceptable fix. I am thinking there might be a problem with forever.
Okay, I figured it out. I was using forever with an absolute path to launch my app on my linux box like
forever start /path/to/app.js
But when I cd into the app directory and then launch the app it works.
forever start app.js
Related
I have a NodeJS project that starts with server.js under /opt/battleship. If I cd to that dir and type node server, everything works correctly, but if I sit in /root and use an absolute path to start it up, such as node /opt/battleship/server, then everything I serve from its ./lib and ./public subdirs gets a 404 response. This is a problem in production because my /etc/init/battleship.conf script specifies starting the process on boot with
exec /usr/local/bin/node /opt/battleship/server.js >> /var/log/battleship.log 2>&1
It runs, but then I get the 404 errors. If I put the line
cd /opt/battleship
just above that in the battleship.conf file, I don't get 404 errors, I get all my files correctly, but it seems as if using cd in a .conf file is messy and prone to errors. Correct me if I'm wrong, this is my first handwritten .conf file. Is there a better way to have my server.js server up files correctly from its ./lib and ./public subdirectories? Below is my server.js file for reference:
var PORT = 3000;
var requirejs = require('requirejs');
var http = requirejs('http');
var fs = requirejs('fs');
var path = requirejs('path');
var mime = requirejs('mime');
var cache = {};
requirejs.config({
baseUrl: __dirname,
nodeRequire: require,
packages: [
{name: 'ship', location: 'public/js/lib/ship'},
{name: 'GameState', location: 'public/js/lib', main: 'GameState'}
]
});
requirejs(['./lib/battleship_server'], function(battleship_server) {
function send404(response) {
response.writeHead(404, {'Content-Type': 'text/plain'});
response.write('Error 404: response not found.');
response.end();
}
function sendFile(response, filePath, fileContents) {
response.writeHead(
200,
{'Content-Type': mime.lookup(path.basename(filePath))}
);
response.end(fileContents);
}
function serveStatic(response, cache, absPath) {
if (cache[absPath]) {
sendFile(response, absPath, cache[absPath]);
} else {
fs.exists(absPath, function(exists) {
if (exists) {
fs.readFile(absPath, function(err, data) {
if (err) {
send404(response);
} else {
cache[absPath] = data;
sendFile(response, absPath, data);
}
});
} else {
send404(response);
}
});
}
}
var server = http.createServer(function(request, response) {
var filePath = false;
if (request.url === '/') {
filePath = 'public/index.html';
} else {
filePath = 'public' + request.url;
}
var absPath = './' + filePath;
serveStatic(response, cache, absPath);
});
server.listen(PORT, function() {
console.log('Server listening on port ' + PORT + '.');
});
battleship_server(server);
});
Use __dirname to get the folder of the script.
For example, if you want to get index.html, and it's in the directory of the script, use this:
var path = require('path');
var pathOfIndex = path.join(__dirname, "index.html");
I have a file which I download to our desktop for all type of operating
system like windows, linux, mac etc. The below code I am using for download it from third server to my serve folder:
var fileticketID = req.params.fileticketID;
var download = function(uri, filename, callback){
BASE.request.head(uri, function(err, res, body){BASE.request(uri).pipe(BASE.FS.createWriteStream('public/images/'+filename)).on('close', function(err) {
var stats = BASE.FS.statSync('public/images/'+filename);
var fileSizeInBytes = stats["size"];
var fields = {filename : filename,size:fileSizeInBytes};
var fieldsData = new downloadFile(fields);
fieldsData.save(function(err, data){
if(!err)
{
if(fileSizeInBytes==0)
{
resMain.send('error');
}
else
{
resMain.send(filename);
}
//console.log('successfully saved -- ');
}
else
{
resMain.send('error');
//console.log('sorry error ', err);
}
});
});
Now I want to file is also downloaded in desktop
Question
Is there a simple way to move all the files in a directory up to its parent directory then delete the directory?
Use Case
I'm doing a zip extraction and the source zip contains a root folder called archive, so when I extract I get extract_path/archive/, but I'd like to just extract the contents of archive directly to extract_path.
I thought this would be simple rename, but the following is throwing a "There is a file in the way" error message.
fs.renameSync(extractPath + "/archive", extractPath)
use the mv npm module. mv first tries a fs.rename, and if it fails, uses copy then unlink :
mv('source/dir', 'dest/a/b/c/dir', {mkdirp: true}, function(err) {
// done. it first created all the necessary directories, and then
// tried fs.rename, then falls back to using ncp to copy the dir
// to dest and then rimraf to remove the source dir
});
or spawn a child process :
var spawn = require('child_process').spawn,
mv = spawn('mv', ['/dir1/dir2/*','dir1/']);
The selected answer does not work:
var mv = require('mv');
var extractPath = 'E:\\tmp\\dir';
mv(extractPath + "\\sub", extractPath, {mkdirp: true}, console.error);
It errors with:
{ Error: EPERM: operation not permitted, rename 'E:\tmp\dir\sub' -> 'E:\tmp\dir'
at Error (native)
errno: -4048,
code: 'EPERM',
syscall: 'rename',
path: 'E:\\tmp\\dir\\sub',
dest: 'E:\\tmp\\dir' }
Use fs-extra instead of mv:
var fs = require('fs-extra');
var extractPath = 'E:\\tmp\\dir';
fs.move(extractPath + "\\sub", extractPath, console.error);
My file structure is like this before the move:
E:\tmp\dir
> sub
> doc.txt
And like this after the move:
E:\tmp\dir
> doc.txt
UPDATE:
While the above works on Windows, on Linux I get the same error even when using fs-extra. The below is a manual fix for this, by individually moving each child of the subdirectory up to the parent. If a child move fails, then it will revert any other successful moves back to the original location in the subdirectory.
var fs = require('fs-extra')
var Promise = require('promise');
var path = require('path');
var promiseAllWait = function(promises) {
// this is the same as Promise.all(), except that it will wait for all promises to fulfill before rejecting
var all_promises = [];
for(var i_promise=0; i_promise < promises.length; i_promise++) {
all_promises.push(
promises[i_promise]
.then(function(res) {
return { res: res };
}).catch(function(err) {
return { err: err };
})
);
}
return Promise.all(all_promises)
.then(function(results) {
return new Promise(function(resolve, reject) {
var is_failure = false;
var i_result;
for(i_result=0; i_result < results.length; i_result++) {
if (results[i_result].err) {
is_failure = true;
break;
} else {
results[i_result] = results[i_result].res;
}
}
if (is_failure) {
reject( results[i_result].err );
} else {
resolve(results);
}
});
});
};
var movePromiser = function(from, to, records) {
return fs.move(from, to)
.then(function() {
records.push( {from: from, to: to} );
});
};
var moveDir = function(from_dir, to_dir) {
return fs.readdir(from_dir)
.then(function(children) {
return fs.ensureDir(to_dir)
.then(function() {
var move_promises = [];
var moved_records = [];
var child;
for(var i_child=0; i_child < children.length; i_child++) {
child = children[i_child];
move_promises.push(movePromiser(
path.join(from_dir, child),
path.join(to_dir, child),
moved_records
));
}
return promiseAllWait(move_promises)
.catch(function(err) {
var undo_move_promises = [];
for(var i_moved_record=0; i_moved_record < moved_records.length; i_moved_record++) {
undo_move_promises.push( fs.move(moved_records[i_moved_record].to, moved_records[i_moved_record].from) );
}
return promiseAllWait(undo_move_promises)
.then(function() {
throw err;
});
});
}).then(function() {
return fs.rmdir(from_dir);
});
});
};
Non of the answers work for me, I looked deep in mv's code and found my solution:
I move folder/subfolder to folder, so the folder already exists.
mv(oldPath, newPath, {mkdirp: false, clobber: false}, (err) => {
if (err) {
throw err;
}
});
Remember if the filename already exists in parent folder it will overwrite by file inside subfolder.
I get an error when I try to upload a file, it works in local but it doesn't work on my remote server...
My error :
[sbaf.fr.3005-53 (out) 2014-03-05T20:19:59] { [Error: ENOENT, rename '/tmp/1e426309d298d9ab1d099e1017584058']
[sbaf.fr.3005-53 (out) 2014-03-05T20:19:59] errno: 34,
[sbaf.fr.3005-53 (out) 2014-03-05T20:19:59] code: 'ENOENT',
[sbaf.fr.3005-53 (out) 2014-03-05T20:19:59] path: '/tmp/1e426309d298d9ab1d099e1017584058' }
My controller :
photoDAL.prototype.save = function(photo, file, callback) {
photo.file = file.name;
var photo = dbContext.photo.build(photo);
var file_tmp = file.path;
var file_name = file.name;
var file_type = file.type;
var file = './public/images/photo/'+file_name;
fs.rename(file_tmp, file, function(err){
if( err ) console.log(err);
});
photo.save().success(function(photo) {
callback(photo);
}).error(function(error) {
callback({message: error});
});
};
EDIT #1 :
Screenshots of my ExpressJS app...
Screenshot 1 : http://glui.me/?i=eweyq4ovennej50/2014-03-05_at_20.34_2x.png/
Screenshot 2 : http://glui.me/?i=1n2cjv57jd2fmwq/2014-03-05_at_20.33_2x.png/
EDIT #2 :
My code :
console.log(process.cwd());
console.log(__dirname);
The console :
[sbaf.fr.3005-71 (out) 2014-03-05T21:55:48] /home/anthoc/apps
[sbaf.fr.3005-71 (out) 2014-03-05T21:55:48] /home/anthoc/apps/sbaf.fr/app/dal
So this: var file = './public/images/photo/'+file_name; is a relative path based on process.cwd(). Presumably if your server process was started with your app repo root as the cwd, all should be well, but probably that is not the case. It's more robust to not rely on the cwd but use __dirname and construct paths relative to the location of the current javascript file. So give that a try and see if it fixes it. You can confirm one way or another with: console.log(process.cwd()) in your controller module to debug this.
You can try using __dirname. Here is how I would do it:
photoDAL.prototype.save = function(photo, file, callback) {
photo.file = file.name;
var photo = dbContext.photo.build(photo);
var file_tmp = file.path;
var file_name = file.name;
var file_type = file.type;
var file = __dirname + '/public/images/photo/'+file_name;
fs.rename(file_tmp, file, function(err){
if( err ) console.log(err);
});
photo.save().success(function(photo) {
callback(photo);
}).error(function(error) {
callback({message: error});
});
};
Now, if you're code is in a folder and your target is in the parent, like me:
-root
- public
-photos
-server
-upload.js
You can add a function to the string proto.
String.prototype.getParent = function () {
// Be cross-platform
var replaced = this.replace(new RegExp("\\\\", "g"), '/');
var index = replaced.lastIndexOf('/');
return replaced.substring(0, index);
};
Now call __dirname.getParent() as many time as needed (__dirname.getParent().getParent()...).
You can use formidable module. easy to use
https://www.npmjs.org/package/formidable
Tutorial: I want to open a file via localhost, but I don't know which path I have to type into the Browser. Is localhost, where my server.js is located? (sorry, I'm new to programming and node)
Tutorial-Code
var path = require('path'),
fs = require('fs');
require('http').createServer(function(req, res) {
var file = path.normalize(req.url);
console.log(file);
path.exists(file, function(exists) {
if (exists) {
fs.stat(file, function(err, stat) {
var rs;
if (err) { throw err; }
if (stat.isDirectory()) {
res.writeHead(403);
res.end('Forbidden');
} else {
rs = fs.createReadStream(file);
res.writeHead(200);
rs.pipe(res);
}
});
} else {
res.writeHead(404);
res.end('Not found');
}
})
}).listen(4000);
request.url is normally /something/like/an/absolute/path unless you get requests from a HTTP proxy client (which adds http://... prefix to request.url) or make some custom HTTP requests.
Anyways path.normalize only takes care of .. And .s.
Your code will let anybody access any file (accessible by the account in which node process is running) on your computer.
A better/safer practice is to join __dirname with decoded request.url and check if resolved path starts with the absolute path (with trailing path separator) of the directory you want to serve static content from:
var scriptDir = path.resolve(__dirname + path.sep + "static" + path.sep),
requestPath = decodeURIComponent(request.url);
requestPath = path.resolve(path.join(__dirname, "static", requestPath));
if (requestPath.indexOf(scriptDir) === 0) {
// serve the file
} else {
response.writeHead(403);
response.end(http.STATUS_CODES[403]);
}
Now if you request say, http://localhost:4000/index.html it should serve the file located in /path/to/your/node/app/dir/static/index.html