Skip to content

Instantly share code, notes, and snippets.

@fabien
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fabien/fb322d6af76ad5c5349a to your computer and use it in GitHub Desktop.
Save fabien/fb322d6af76ad5c5349a to your computer and use it in GitHub Desktop.
The flow of my code:
Model.beforeRemote('*.__create__' + rel, beforeCreateHandler(File, options));
var beforeCreateHandler = function(File, options) {
return function(ctx, result, next) {
File.httpCreate(ctx.req, ctx.res, options, next);
};
};
File.httpCreate = function(req, res, options, callback) { // handle multipart data
if (!isMultipartRequest(req)) return res.send(406);
if (_.isFunction(options)) callback = options, options = {};
// req.pause();
Storage.provider(sid, function(storage) {
// req.resume();
if (!storage) return callback(new Error('Invalid storage provider'));
storage.provider.extractAndProcess(req, options, function(err, files) {
if (err || !files[0]) return res.send(500);
handleFileCreation(req, res, storage, files[0], options, callback);
});
});
};
extract: function(req, options, callback) { // from http request
if (_.isFunction(options)) callback = options, options = {};
options = this.ensureOptions(options); // keeps ref, if any
var limits = _.extend({}, this.config.limits);
var self = this;
var files = {};
var fields = {};
var counter = 0;
var finished = -1;
var eventEmitter = new EventEmitter();
eventEmitter.on('done', function() {
counter++;
if (finished === counter) {
self.onStreamFinish(files, fields, options, callback);
}
});
var busboy = new Busboy(_.extend({
headers: req.headers,
limits: limits
}, options.busboy));
this.emit('stream:begin', busboy);
busboy.on('file', function(field, file, filename, encoding, mimetype) {
self.onStreamFile(files, field, file, filename, encoding, mimetype, options, eventEmitter);
});
busboy.on('field', function(field, value, valTruncated, keyTruncated) {
if (valTruncated || keyTruncated) return ;
self.onStreamField(fields, field, value, options);
});
busboy.on('error', function(err) {
self.onStreamError(files, fields, err, options, callback);
});
busboy.on('finish', function() {
var valid = _.filter(files, self.isValid.bind(self));
if (valid.length === 0 || limits.files === 1) {
self.onStreamFinish(files, fields, options, callback);
} else {
finished = valid.length;
}
});
if (_.isNumber(this.config.throttle) && this.config.throttle > 0) {
var stream = req.pipe(new Throttle(this.config.throttle));
return stream.pipe(busboy);
} else {
return req.pipe(busboy);
}
},
extractAndProcess: function(req, options, callback) {
if (_.isFunction(options)) callback = options, options = {};
this.extract(req, options, function(err, valid, files) {
if (_.isEmpty(files)) return callback(err, []);
this.process(files, options, callback);
}.bind(this));
},
var RestAdapter = require('loopback/node_modules/strong-remoting/lib/rest-adapter');
RestAdapter.prototype._createPrototypeMethodHandler = function(sharedMethod) {
var self = this;
var Context = this.Context;
return function restPrototypeMethodHandler(req, res, next) {
var isMultiPart = req.headers['content-type']
&& req.headers['content-type'].indexOf('multipart/form-data') > -1;
var ctx = new Context(req, res, sharedMethod);
if (isMultiPart) req.pause();
// invoke the shared constructor to get an instance
ctx.invoke(sharedMethod.ctor, sharedMethod.sharedCtor, function(err, inst) {
if (isMultiPart) req.resume();
if (err) return next(err);
ctx.instance = inst;
self._invokeMethod(ctx, sharedMethod, next);
}, true);
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment