wmakeev
6/26/2016 - 3:08 PM

AWS S3 #aws

AWS S3 #aws

/**
 * index
 * Date: 12.09.14
 * Vitaliy V. Makeev (w.makeev@gmail.com)
 */

var _       = require('lodash')
  , AWS     = require('aws-sdk')
  , path    = require('path')
  , url     = require('url');

function encodeSpecialCharacters(filename) {
    // Note: these characters are valid in URIs, but S3 does not like them for
    // some reason.
    return encodeURI(filename).replace(/[!'()* ]/g, function (char) {
        return '%' + char.charCodeAt(0).toString(16);
    });
}

function getPublicUrl(bucket, key, bucketLocation) {
    var nonStandardBucketLocation = (bucketLocation && bucketLocation !== 'us-east-1');
    var hostnamePrefix = nonStandardBucketLocation ? ("s3-" + bucketLocation) : "s3";
    var parts = {
        protocol: "https:",
        hostname: hostnamePrefix + ".amazonaws.com",
        pathname: "/" + bucket + "/" + encodeSpecialCharacters(key)
    };
    return url.format(parts);
}

function getPublicUrlHttp(bucket, key) {
    var parts = {
        protocol: "http:",
        hostname: bucket + ".s3.amazonaws.com",
        pathname: "/" + encodeSpecialCharacters(key)
    };
    return url.format(parts);
}

var awsStorage = function (sb) {
    var log = sb.log;

    /**
     * Local file upload
     * @param data
     * @param options
     * @param cb
     */
    var upload = function (data, options, cb) {
        var s3 = new AWS.S3(options.config);
        // http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property
        var response = s3.putObject(_.extend({}, options.params, {
            Key         : data.key,
            Body        : data.body,
            ContentType : data.contentType
        }), function (err, result) {
            if (err) return cb(err);
            result.url = getPublicUrlHttp(options.params.Bucket, data.key);
            cb(null, result);
        });

        // http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Request.html
        // AWS S3 limitation - https://github.com/aws/aws-sdk-js/issues/94
        response.on('httpUploadProgress', function(progress) {
            sb.emit('upload/progress', {
                key: data.key,
                loaded: progress.loaded,
                total: progress.total,
                progress: Math.round(progress.loaded / (progress.total / 100))
            });
        });
    };

    return {
        init: function (options) {
            AWS.config.apiVersions.s3 = options.apiVersion || '2006-03-01';

            sb.on('upload/file', function (data, channel, reply) {
                upload(data, options, reply);
            });
        }
    }
};

module.exports = awsStorage;