Download files using Skipper with Sails.js v0.10 - how to get a new file name

I am Sails.js to Sails.js version 0.10 and now you need to use Skipper to control file downloads.

When I upload a file, I generate a new name for it using the UUID and save it in the public / files / folder (this will change when I succeed, but it's good for testing right now)

I save the original name and the loaded name + path to the Mongo database.

All this was pretty simple in Sails v0.9.x , but with Skipper I can’t figure out how to read the new name and file path. (Obviously, if I could read the name, I could build a path, although this is really only the name I need)

My controller is as follows

 var uuid = require('node-uuid'), path = require('path'), blobAdapter = require('skipper-disk'); module.exports = { upload: function(req, res) { var receiver = blobAdapter().receive({ dirname: sails.config.appPath + "/public/files/", saveAs: function(file) { var filename = file.filename, newName = uuid.v4() + path.extname(filename); return newName; } }), results = []; req.file('docs').upload(receiver, function (err, files) { if (err) return res.serverError(err); async.forEach(files, function(file, next) { Document.create({ name: file.filename, size: file.size, localName: // ***** how do I get the `saveAs()` value from the uploaded file *****, path: // *** and likewise how do i get the path ****** }).exec(function(err, savedFile){ if (err) { next(err); } else { results.push({ id: savedFile.id, url: '/files/' + savedFile.localName }); next(); } }); }, function(err){ if (err) { sails.log.error('caught error', err); return res.serverError({error: err}); } else { return res.json({ files: results }); } }); }); }, _config: {} }; 

How to do it?

+4
javascript file-upload multifile-uploader skipper
source share
2 answers

I now understood this and decided to share my decision for the benefit of others who are struggling with similar problems.

The solution was not to use skipper-disk at all, but to write your own receiver . I created this as a Sails Service object.

So, in the api/services/Uploader.js file

 // Uploader utilities and helper methods // designed to be relatively generic. var fs = require('fs'), Writable = require('stream').Writable; exports.documentReceiverStream = function(options) { var defaults = { dirname: '/dev/null', saveAs: function(file){ return file.filename; }, completed: function(file, done){ done(); } }; // I don't have access to jQuery here so this is the simplest way I // could think of to merge the options. opts = defaults; if (options.dirname) opts.dirname = options.dirname; if (options.saveAs) opts.saveAs = options.saveAs; if (options.completed) opts.completed = options.completed; var documentReceiver = Writable({objectMode: true}); // This `_write` method is invoked each time a new file is received // from the Readable stream (Upstream) which is pumping filestreams // into this receiver. (filename === `file.filename`). documentReceiver._write = function onFile(file, encoding, done) { var newFilename = opts.saveAs(file), fileSavePath = opts.dirname + newFilename, outputs = fs.createWriteStream(fileSavePath, encoding); file.pipe(outputs); // Garbage-collect the bytes that were already written for this file. // (called when a read or write error occurs) function gc(err) { sails.log.debug("Garbage collecting file '" + file.filename + "' located at '" + fileSavePath + "'"); fs.unlink(fileSavePath, function (gcErr) { if (gcErr) { return done([err].concat([gcErr])); } else { return done(err); } }); }; file.on('error', function (err) { sails.log.error('READ error on file ' + file.filename, '::', err); }); outputs.on('error', function failedToWriteFile (err) { sails.log.error('failed to write file', file.filename, 'with encoding', encoding, ': done =', done); gc(err); }); outputs.on('finish', function successfullyWroteFile () { sails.log.debug("file uploaded") opts.completed({ name: file.filename, size: file.size, localName: newFilename, path: fileSavePath }, done); }); }; return documentReceiver; } 

and then my controller just became (in api/controllers/DocumentController.js )

 var uuid = require('node-uuid'), path = require('path'); module.exports = { upload: function(req, res) { var results = [], streamOptions = { dirname: sails.config.appPath + "/public/files/", saveAs: function(file) { var filename = file.filename, newName = uuid.v4() + path.extname(filename); return newName; }, completed: function(fileData, next) { Document.create(fileData).exec(function(err, savedFile){ if (err) { next(err); } else { results.push({ id: savedFile.id, url: '/files/' + savedFile.localName }); next(); } }); } }; req.file('docs').upload(Uploader.documentReceiverStream(streamOptions), function (err, files) { if (err) return res.serverError(err); res.json({ message: files.length + ' file(s) uploaded successfully!', files: results }); } ); }, _config: {} }; 

I'm sure it can be improved, but it works great for me.

+10
source share

The loaded file object contains all the necessary data:

 req.file('fileTest').upload({ // You can apply a file upload limit (in bytes) maxBytes: maxUpload, adapter: require('skipper-disk') }, function whenDone(err, uploadedFiles) { if (err) { var error = { "status": 500, "error" : err }; res.status(500); return res.json(error); } else { for (var u in uploadedFiles) { //"fd" contains the actual file path (and name) of your file on disk fileOnDisk = uploadedFiles[u].fd; // I suggest you stringify the object to see what it contains and might be useful to you console.log(JSON.stringify(uploadedFiles[u])); } } }); 
+4
source share

All Articles