PawsX-S3-Uploader
view release on metacpan or search on metacpan
lib/PawsX/S3/Uploader.pm view on Meta::CPAN
use v5.26; ## no critic(ProhibitVersionStrings)
package PawsX::S3::Uploader;
use strict;
use warnings;
use Feature::Compat::Class 0.07;
use Feature::Compat::Try 0.05;
use builtin::compat 0.003003 qw(true false);
use Carp ();
class PawsX::S3::Uploader;
our $VERSION = '0.0.3'; # VERSION
# ABSTRACT: upload to S3 from a streaming source
# aws doesn't want small multiparts
sub MULTIPART_MIN_SIZE { 5*1024*1024 }
field $s3 :param;
field $bucket :param;
field $key :param;
field $min_part_size :param = MULTIPART_MIN_SIZE;
field $_under_testing :param(_under_testing) = false;
field $extra_arguments :param = {};
field $always_multipart :param = false;
field $callback :param = undef;
field $output :reader;
field $upload_id;
field @parts;
field $part_body = '';
field $aborted = false;
## no critic(RequireEndWithOne) # critic gets confused
ADJUST {
if (!$_under_testing && $min_part_size < MULTIPART_MIN_SIZE) {
$min_part_size = MULTIPART_MIN_SIZE;
}
}
method _maybe_callback($op, $details) {
return unless $callback;
$callback->($op, $details);
}
method _start_multipart() {
my $upload = $s3->CreateMultipartUpload(
$extra_arguments->%*,
Bucket => $bucket,
Key => $key,
);
$upload_id = $upload->UploadId;
$self->_maybe_callback(start_multipart => { upload_id => $upload_id });
}
method _upload_part() {
my $part_number = 1+@parts;
try {
my $part_res = $s3->UploadPart(
Body => $part_body,
Bucket => $bucket,
Key => $key,
PartNumber => $part_number,
UploadId => $upload_id,
);
push @parts, {
PartNumber => $part_number,
lib/PawsX/S3/Uploader.pm view on Meta::CPAN
} else {
$self->_put_object();
}
$self->_maybe_callback(finish => { output => $output });
return $output;
}
method abort($details={}) {
Carp::croak('Upload already completed') if $output;
# pretend we can abort more than once
return if $aborted;
# if we haven't started the multipart upload, there's nothing to abort
if ($upload_id) {
$s3->AbortMultipartUpload(
Bucket => $bucket,
Key => $key,
UploadId => $upload_id,
);
}
$aborted = true;
$self->_maybe_callback(abort_multipart => $details);
}
method upload_fh($fh) {
my ($part, $done) = ('',false);
while (!$done) {
my $size = sysread $fh, $part, $min_part_size;
if (!defined $size) {
my $error = $!;
$self->abort({ error => $error });
Carp::croak("sysread failed: $error");
}
$self->add($part) if $size > 0;
$part='';
$done = $size==0;
}
return $self->finish;
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
PawsX::S3::Uploader - upload to S3 from a streaming source
=head1 VERSION
version 0.0.3
=head1 SYNOPSIS
use Paws;
use PawsX::S3::Uploader;
use Feature::Compat::Try; # or a recent perl
my $s3 = Paws->service(S3 => ( region => 'eu-west-1' ));
my $uploader = PawsX::S3::Uploader->new(
s3 => $s3,
bucket => 'my-bucket',
key => 'my-object-key',
# optional, anything that PutObject and CreateMultipartUpload
# can understand
extra_arguments => {
ServerSideEncryption => 'aws:kms',
SSEKMSKeyId => 'the-secret-key-id',
Metadata => { foo => 'bar' },
Tagging => 'foo=bar&baz=3',
}
);
try {
while (my $block = read_data_from_somewhere()) {
$uploader->add($block);
}
$uploader->finish;
}
catch ($error) {
# if `read_data_from_somewhere` can throw, you need to abort
# the upload yourself
$uploader->abort();
warn $error;
}
=head1 DESCRIPTION
This class automates uploading objects to AWS S3 via L<Paws>, for the
cases where you can't keep the whole data in memory, or you can't even
generate it all ahead of time.
Underneath, it uses L<< C<PutObject>|Paws::S3::PutObject >> for
objects smaller than 5MB, and L<<
C<CreateMultipartUpload>|Paws::S3::CreateMultipartUpload >> / L<<
C<UploadPart>|Paws::S3::UploadPart >> / L<<
C<CompleteMultipartUpload>|Paws::S3::CompleteMultipartUpload >> for
larger objects.
Exceptions in C<UploadPart> cause the upload to be L<aborted|/abort>,
and the exception is re-thrown (so you can trap it yourself if you
need to). You should also explicitly L<abort|/abort> the upload if
something goes wrong in your own code.
( run in 0.798 second using v1.01-cache-2.11-cpan-140bd7fdf52 )