ipfs storage for images and other nontext items. for use with etica - runs on etica network and currencys
https://collect.etica-stats.org
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
5.1 KiB
175 lines
5.1 KiB
var is = require('type-is') |
|
var Busboy = require('busboy') |
|
var extend = require('xtend') |
|
var appendField = require('append-field') |
|
|
|
var Counter = require('./counter') |
|
var MulterError = require('./multer-error') |
|
var FileAppender = require('./file-appender') |
|
var removeUploadedFiles = require('./remove-uploaded-files') |
|
|
|
function makeMiddleware (setup) { |
|
return function multerMiddleware (req, res, next) { |
|
if (!is(req, ['multipart'])) return next() |
|
|
|
var options = setup() |
|
|
|
var limits = options.limits |
|
var storage = options.storage |
|
var fileFilter = options.fileFilter |
|
var fileStrategy = options.fileStrategy |
|
var preservePath = options.preservePath |
|
|
|
req.body = Object.create(null) |
|
|
|
var busboy |
|
|
|
try { |
|
busboy = Busboy({ headers: req.headers, limits: limits, preservePath: preservePath }) |
|
} catch (err) { |
|
return next(err) |
|
} |
|
|
|
var appender = new FileAppender(fileStrategy, req) |
|
var isDone = false |
|
var readFinished = false |
|
var errorOccured = false |
|
var pendingWrites = new Counter() |
|
var uploadedFiles = [] |
|
|
|
function done (err) { |
|
if (isDone) return |
|
isDone = true |
|
req.unpipe(busboy) |
|
process.nextTick(() => { |
|
busboy.removeAllListeners() |
|
}) |
|
next(err) |
|
} |
|
|
|
function indicateDone () { |
|
if (readFinished && pendingWrites.isZero() && !errorOccured) done() |
|
} |
|
|
|
function abortWithError (uploadError) { |
|
if (errorOccured) return |
|
errorOccured = true |
|
|
|
pendingWrites.onceZero(function () { |
|
function remove (file, cb) { |
|
storage._removeFile(req, file, cb) |
|
} |
|
|
|
removeUploadedFiles(uploadedFiles, remove, function (err, storageErrors) { |
|
if (err) return done(err) |
|
|
|
uploadError.storageErrors = storageErrors |
|
done(uploadError) |
|
}) |
|
}) |
|
} |
|
|
|
function abortWithCode (code, optionalField) { |
|
abortWithError(new MulterError(code, optionalField)) |
|
} |
|
|
|
// handle text field data |
|
busboy.on('field', function (fieldname, value, { nameTruncated, valueTruncated }) { |
|
if (fieldname == null) return abortWithCode('MISSING_FIELD_NAME') |
|
if (nameTruncated) return abortWithCode('LIMIT_FIELD_KEY') |
|
if (valueTruncated) return abortWithCode('LIMIT_FIELD_VALUE', fieldname) |
|
|
|
// Work around bug in Busboy (https://github.com/mscdex/busboy/issues/6) |
|
if (limits && Object.prototype.hasOwnProperty.call(limits, 'fieldNameSize')) { |
|
if (fieldname.length > limits.fieldNameSize) return abortWithCode('LIMIT_FIELD_KEY') |
|
} |
|
|
|
appendField(req.body, fieldname, value) |
|
}) |
|
|
|
// handle files |
|
busboy.on('file', function (fieldname, fileStream, { filename, encoding, mimeType }) { |
|
// don't attach to the files object, if there is no file |
|
if (!filename) return fileStream.resume() |
|
|
|
// Work around bug in Busboy (https://github.com/mscdex/busboy/issues/6) |
|
if (limits && Object.prototype.hasOwnProperty.call(limits, 'fieldNameSize')) { |
|
if (fieldname.length > limits.fieldNameSize) return abortWithCode('LIMIT_FIELD_KEY') |
|
} |
|
|
|
var file = { |
|
fieldname: fieldname, |
|
originalname: filename, |
|
encoding: encoding, |
|
mimetype: mimeType |
|
} |
|
|
|
var placeholder = appender.insertPlaceholder(file) |
|
|
|
fileFilter(req, file, function (err, includeFile) { |
|
if (err) { |
|
appender.removePlaceholder(placeholder) |
|
return abortWithError(err) |
|
} |
|
|
|
if (!includeFile) { |
|
appender.removePlaceholder(placeholder) |
|
return fileStream.resume() |
|
} |
|
|
|
var aborting = false |
|
pendingWrites.increment() |
|
|
|
Object.defineProperty(file, 'stream', { |
|
configurable: true, |
|
enumerable: false, |
|
value: fileStream |
|
}) |
|
|
|
fileStream.on('error', function (err) { |
|
pendingWrites.decrement() |
|
abortWithError(err) |
|
}) |
|
|
|
fileStream.on('limit', function () { |
|
aborting = true |
|
abortWithCode('LIMIT_FILE_SIZE', fieldname) |
|
}) |
|
|
|
storage._handleFile(req, file, function (err, info) { |
|
if (aborting) { |
|
appender.removePlaceholder(placeholder) |
|
uploadedFiles.push(extend(file, info)) |
|
return pendingWrites.decrement() |
|
} |
|
|
|
if (err) { |
|
appender.removePlaceholder(placeholder) |
|
pendingWrites.decrement() |
|
return abortWithError(err) |
|
} |
|
|
|
var fileInfo = extend(file, info) |
|
|
|
appender.replacePlaceholder(placeholder, fileInfo) |
|
uploadedFiles.push(fileInfo) |
|
pendingWrites.decrement() |
|
indicateDone() |
|
}) |
|
}) |
|
}) |
|
|
|
busboy.on('error', function (err) { abortWithError(err) }) |
|
busboy.on('partsLimit', function () { abortWithCode('LIMIT_PART_COUNT') }) |
|
busboy.on('filesLimit', function () { abortWithCode('LIMIT_FILE_COUNT') }) |
|
busboy.on('fieldsLimit', function () { abortWithCode('LIMIT_FIELD_COUNT') }) |
|
busboy.on('close', function () { |
|
readFinished = true |
|
indicateDone() |
|
}) |
|
|
|
req.pipe(busboy) |
|
} |
|
} |
|
|
|
module.exports = makeMiddleware
|
|
|