Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Upload images from FileReader to Amazon s3, using meteor

Im trying to build an image uploader with meteor to Amazon S3. Thanks to Hubert OG, Ive found AWS-SDK which makes things easy.

My problem is that the data uploaded seems to be corrupt. When I download the file it says, the file may be corrupt. Probably it is.

Inserting the data into an image src, does work, and the preview of the image shows up as it supposed to, so the original file, and probably the data is correct.

I'm loading the file with FileReader, and than pass the result data to AWS-SDK putObject method.

        var file=template.find('[type=file]').files[0];
        var key="uploads/"+file.name;

        var reader=new FileReader();
        reader.onload=function(event){
            var data=event.target.result;
            template.find('img').src=data;
            Meteor.call("upload_to_s3",file,"uploads",reader.result);
        };

        reader.readAsDataURL(file);

and this is the method on the server:

    "upload_to_s3":function(file,folder,data){
        s3 = new AWS.S3({endpoint:ep});
        s3.putObject(
            {
                Bucket: "myportfoliositebucket",
                ACL:'public-read',
                Key: folder+"/"+file.name,
                ContentType: file.type,
                Body:data
            },
            function(err, data) {
                if(err){
                    console.log('upload error:',err);
                }else{
                    console.log('upload was succesfull',data);
                }
            }
        );
    }
like image 382
zalavari Avatar asked Oct 25 '13 15:10

zalavari


2 Answers

I wrapped an npm module as a smart package found here: https://atmosphere.meteor.com/package/s3policies

With it you can make a Meteor Method that returns a write policy, and with that policy you can upload to S3 using an ajax call.

Example:

Meteor.call('s3Upload', name, function (error, policy) {
    if(error)
        onFinished({error: error});
    var formData = new FormData();
    formData.append("AWSAccessKeyId", policy.s3Key);
    formData.append("policy", policy.s3PolicyBase64);
    formData.append("signature", policy.s3Signature);

    formData.append("key", policy.key);
    formData.append("Content-Type", policy.mimeType);
    formData.append("acl", "private");
    formData.append("file", file);

    $.ajax({
        url: 'https://s3.amazonaws.com/' + policy.bucket + '/',
        type: 'POST',
        xhr: function() {  // custom xhr
            var myXhr = $.ajaxSettings.xhr();
            if(myXhr.upload){ // check if upload property exists
                myXhr.upload.addEventListener('progress',
                    function (e){
                        if(e.lengthComputable)
                            onProgressUpdate(e.loaded / e.total * 100);

                }, false); // for handling the progress of the upload
            }
            return myXhr;
        },
        success: function () {
            // file finished uploading
        },
        error: function () { onFinished({error: arguments[1]}); },
        processData: false,
        contentType: false,
        // Form data
        data: formData,
        cache: false,
        xhrFields: { withCredentials: true },
        dataType: 'xml'
    });
});

EDIT:

The "file" variable in the line: formData.append("file", file); is from a line similar to this: var file = document.getElementById('fileUpload').files[0];

The server side code looks like this:

Meteor.methods({
    s3Upload: function (name) {
        var myS3 = new s3Policies('my key', 'my secret key');

        var location = Meteor.userId() + '/' + moment().format('MMM DD YYYY').replace(/\s+/g, '_') + '/' + name;
        if(Meteor.userId()) {
            var bucket = 'my bucket';
            var policy = myS3.writePolicy(location, bucket, 10, 4096);
            policy.key = location;
            policy.bucket = bucket;
            policy.mimeType = mime.lookup(name);
            return policy;
        }
    }
});
like image 125
Dave Avatar answered Nov 05 '22 07:11

Dave


The body should be converted to buffer – see the documentation.

So instead of Body: data you should have Body: new Buffer(data, 'binary').

like image 32
Hubert OG Avatar answered Nov 05 '22 07:11

Hubert OG