| var http = require('http') |
| var util = require('util') |
| var path = require('path') |
| var fs = require('fs') |
| |
| var express = require('express') |
| var validator = require('express-validator') |
| var bodyParser = require('body-parser') |
| var formidable = require('formidable') |
| var Promise = require('bluebird') |
| var uuid = require('node-uuid') |
| var AWS = require('aws-sdk') |
| |
| var logger = require('../../util/logger') |
| |
| module.exports = function(options) { |
| var log = logger.createLogger('storage:s3') |
| var app = express() |
| var server = http.createServer(app) |
| |
| var s3 = new AWS.S3({ |
| credentials: new AWS.SharedIniFileCredentials({ |
| profile: options.profile |
| }) |
| , endpoint: options.endpoint |
| }) |
| |
| app.set('strict routing', true) |
| app.set('case sensitive routing', true) |
| app.set('trust proxy', true) |
| |
| app.use(bodyParser.json()) |
| app.use(validator()) |
| |
| function putObject(plugin, file) { |
| return new Promise(function(resolve, reject) { |
| var id = uuid.v4() |
| s3.putObject({ |
| Key: id |
| , Body: fs.createReadStream(file.path) |
| , Bucket: options.bucket |
| , Metadata: { |
| plugin: plugin |
| , name: file.name |
| } |
| }, function(err) { |
| if (err) { |
| log.error( |
| 'Unable to store "%s" as "%s/%s"' |
| , file.temppath |
| , options.bucket |
| , id |
| , err.stack |
| ) |
| reject(err) |
| } |
| else { |
| log.info('Stored "%s" as "%s/%s"', file.name, options.bucket, id) |
| resolve(id) |
| } |
| }) |
| }) |
| } |
| |
| function getHref(plugin, id, name) { |
| return util.format( |
| '/s/%s/%s%s' |
| , plugin |
| , id |
| , name ? '/' + path.basename(name) : '' |
| ) |
| } |
| |
| app.post('/s/upload/:plugin', function(req, res) { |
| var form = new formidable.IncomingForm() |
| var plugin = req.params.plugin |
| Promise.promisify(form.parse, form)(req) |
| .spread(function(fields, files) { |
| var requests = Object.keys(files).map(function(field) { |
| var file = files[field] |
| log.info('Uploaded "%s" to "%s"', file.name, file.path) |
| return putObject(plugin, file) |
| .then(function(id) { |
| return { |
| field: field |
| , id: id |
| , name: file.name |
| , temppath: file.path |
| } |
| }) |
| }) |
| return Promise.all(requests) |
| }) |
| .then(function(storedFiles) { |
| res.status(201).json({ |
| success: true |
| , resources: (function() { |
| var mapped = Object.create(null) |
| storedFiles.forEach(function(file) { |
| mapped[file.field] = { |
| date: new Date() |
| , plugin: plugin |
| , id: file.id |
| , name: file.name |
| , href: getHref(plugin, file.id, file.name) |
| } |
| }) |
| return mapped |
| })() |
| }) |
| return storedFiles |
| }) |
| .then(function(storedFiles) { |
| return Promise.all(storedFiles.map(function(file) { |
| return Promise.promisify(fs.unlink, fs)(file.temppath) |
| .catch(function(err) { |
| log.warn('Unable to clean up "%s"', file.temppath, err.stack) |
| return true |
| }) |
| })) |
| }) |
| .catch(function(err) { |
| log.error('Error storing resource', err.stack) |
| res.status(500) |
| .json({ |
| success: false |
| , error: 'ServerError' |
| }) |
| }) |
| }) |
| |
| app.get('/s/blob/:id/:name', function(req, res) { |
| var params = { |
| Key: req.params.id |
| , Bucket: options.bucket |
| } |
| |
| s3.getObject(params, function(err, data) { |
| if (err) { |
| log.error('Unable to retrieve "%s"', path, err.stack) |
| res.sendStatus(404) |
| return |
| } |
| |
| res.set({ |
| 'Content-Type': data.ContentType |
| }) |
| |
| res.send(data.Body) |
| }) |
| }) |
| |
| server.listen(options.port) |
| log.info('Listening on port %d', options.port) |
| } |