File Coverage

blib/lib/AWS/S3/File.pm
Criterion Covered Total %
statement 16 51 31.3
branch 0 10 0.0
condition 0 3 0.0
subroutine 5 10 50.0
pod 3 4 75.0
total 24 78 30.7


line stmt bran cond sub pod time code
1              
2             package AWS::S3::File;
3              
4 2     2   1878 use Moose;
  2         3  
  2         29  
5 2     2   7964 use Carp 'confess';
  2         3  
  2         115  
6              
7 2     2   1004 use MooseX::Types -declare => [qw/fileContents/];
  2         66570  
  2         11  
8 2     2   6642 use MooseX::Types::Moose qw/Str ScalarRef CodeRef/;
  2         19640  
  2         15  
9              
10             subtype fileContents, as ScalarRef;
11             coerce fileContents,
12             from CodeRef,
13             via {
14             my $ref = $_[0];
15             my $v = $ref->();
16             ref $v ? $v : \$v
17             }
18             ;
19              
20             has 'key' => (
21             is => 'ro',
22             isa => 'Str',
23             required => 1,
24             );
25              
26             has 'bucket' => (
27             is => 'ro',
28             isa => 'AWS::S3::Bucket',
29             required => 1,
30             weak_ref => 0,
31             );
32              
33             has 'size' => (
34             is => 'ro',
35             isa => 'Int',
36             required => 0,
37             default => sub {
38             my $self = shift;
39             return length ${$self->contents};
40             }
41             );
42              
43             has 'etag' => (
44             is => 'ro',
45             isa => 'Str',
46             required => 0,
47             );
48              
49             has 'owner' => (
50             is => 'ro',
51             isa => 'AWS::S3::Owner',
52             required => 0,
53             weak_ref => 1,
54             );
55              
56             has 'storage_class' => (
57             is => 'ro',
58             isa => 'Str',
59             default => 'STANDARD',
60             required => 1,
61             );
62              
63             has 'lastmodified' => (
64             is => 'ro',
65             isa => 'Str',
66             required => 0,
67             );
68              
69             has 'contenttype' => (
70             is => 'rw',
71             isa => 'Str',
72             required => 0,
73             default => 'binary/octet-stream'
74             );
75              
76             has 'is_encrypted' => (
77             is => 'rw',
78             isa => 'Bool',
79             required => 1,
80             lazy => 1,
81             default => sub {
82             my $s = shift;
83              
84             my $type = 'GetFileInfo';
85             my $req = $s->bucket->s3->request(
86             $type,
87             bucket => $s->bucket->name,
88             key => $s->key,
89             );
90              
91             return $req->request->response->header( 'x-amz-server-side-encryption' ) ? 1 : 0;
92             },
93             );
94              
95             has 'contents' => (
96             is => 'rw',
97             isa => fileContents,
98             required => 0,
99             lazy => 1,
100             coerce => 1,
101             default => \&_get_contents,
102             trigger => \&_set_contents
103             );
104              
105             sub BUILD {
106 0     0 0 0 my $s = shift;
107              
108 0 0       0 return unless $s->etag;
109 0         0 ( my $etag = $s->etag ) =~ s{^"}{};
110 0         0 $etag =~ s{"$}{};
111 0         0 $s->{etag} = $etag;
112             } # end BUILD()
113              
114             sub update {
115 0     0 1 0 my $s = shift;
116 0         0 my %args = @_;
117 0         0 my @args_ok = grep { /^content(?:s|type)$/ } keys %args;
  0         0  
118 0 0       0 if ( @args_ok ) {
119 0         0 $s->{$_} = $args{$_} for @args_ok;
120 0         0 $s->_set_contents();
121 0         0 return 1;
122             }
123 0         0 return;
124             } # end update()
125              
126             sub _get_contents {
127 0     0   0 my $s = shift;
128              
129 0         0 my $type = 'GetFileContents';
130 0         0 my $req = $s->bucket->s3->request(
131             $type,
132             bucket => $s->bucket->name,
133             key => $s->key,
134             );
135              
136 0         0 return \$req->request->response->decoded_content;
137             } # end contents()
138              
139             sub _set_contents {
140 1     1   2 my ( $s, $ref ) = @_;
141              
142 1         1 my $type = 'SetFileContents';
143 1         2 my %args = ();
144 1 0       22 my $response = $s->bucket->s3->request(
145             $type,
146             bucket => $s->bucket->name,
147             file => $s,
148             contents => $ref,
149             content_type => $s->contenttype,
150             server_side_encryption => $s->is_encrypted ? 'AES256' : undef,
151             )->request();
152              
153 0           ( my $etag = $response->response->header( 'etag' ) ) =~ s{^"}{};
154 0           $etag =~ s{"$}{};
155 0           $s->{etag} = $etag;
156              
157 0 0         if ( my $msg = $response->friendly_error() ) {
158 0           die $msg;
159             } # end if()
160             } # end _set_contents()
161              
162             sub signed_url {
163 0     0 1   my $s = shift;
164 0   0       my $expires = shift || time + 3600;
165              
166 0           my $type = "GetPreSignedUrl";
167 0           my $uri = $s->bucket->s3->request(
168             $type,
169             bucket => $s->bucket->name,
170             key => $s->key,
171             expires => $expires,
172             )->request;
173              
174 0           return $uri;
175             }
176              
177             sub delete {
178 0     0 1   my $s = shift;
179              
180 0           my $type = 'DeleteFile';
181 0           my $req = $s->bucket->s3->request(
182             $type,
183             bucket => $s->bucket->name,
184             key => $s->key,
185             );
186 0           my $response = $req->request();
187              
188 0 0         if ( my $msg = $response->friendly_error() ) {
189 0           die $msg;
190             } # end if()
191              
192 0           return 1;
193             } # end delete()
194              
195             __PACKAGE__->meta->make_immutable;
196              
197             __END__
198              
199             =pod
200              
201             =head1 NAME
202              
203             AWS::S3::File - A single file in Amazon S3
204              
205             =head1 SYNOPSIS
206              
207             my $file = $bucket->file('foo/bar.txt');
208            
209             # contents is a scalarref:
210             print @{ $file->contents };
211             print $file->size;
212             print $file->key;
213             print $file->etag;
214             print $file->lastmodified;
215            
216             print $file->owner->display_name;
217            
218             print $file->bucket->name;
219            
220             # Set the contents with a scalarref:
221             my $new_contents = "This is the new contents of the file.";
222             $file->contents( \$new_contents );
223            
224             # Set the contents with a coderef:
225             $file->contents( sub {
226             return \$new_contents;
227             });
228            
229             # Alternative update
230             $file->update(
231             contents => \'New contents', # optional
232             contenttype => 'text/plain' # optional
233             );
234              
235             # Get signed URL for the file for public access
236             print $file->signed_url( $expiry_time );
237            
238             # Delete the file:
239             $file->delete();
240              
241             =head1 DESCRIPTION
242              
243             AWS::S3::File provides a convenience wrapper for dealing with files stored in S3.
244              
245             =head1 PUBLIC PROPERTIES
246              
247             =head2 bucket
248              
249             L<AWS::S3::Bucket> - read-only.
250              
251             The L<AWS::S3::Bucket> that contains the file.
252              
253             =head2 key
254              
255             String - read-only.
256              
257             The 'filename' (for all intents and purposes) of the file.
258              
259             =head2 size
260              
261             Integer - read-only.
262              
263             The size in bytes of the file.
264              
265             =head2 etag
266              
267             String - read-only.
268              
269             The Amazon S3 'ETag' header for the file.
270              
271             =head2 owner
272              
273             L<ASW::S3::Owner> - read-only.
274              
275             The L<ASW::S3::Owner> that the file belongs to.
276              
277             =head2 storage_class
278              
279             String - read-only.
280              
281             The type of storage used by the file.
282              
283             =head2 lastmodified
284              
285             String - read-only.
286              
287             A date in this format:
288              
289             2009-10-28T22:32:00
290              
291             =head2 contents
292              
293             ScalarRef|CodeRef - read-write.
294              
295             Returns a scalar-reference of the file's contents.
296              
297             Accepts either a scalar-ref or a code-ref (which would return a scalar-ref).
298              
299             Once given a new value, the file is instantly updated on Amazon S3.
300              
301             # GOOD: (uses scalarrefs)
302             my $value = "A string";
303             $file->contents( \$value );
304             $file->contents( sub { return \$value } );
305            
306             # BAD: (not scalarrefs)
307             $file->contents( $value );
308             $file->contents( sub { return $value } );
309              
310             =head1 PUBLIC METHODS
311              
312             =head2 delete()
313              
314             Deletes the file from Amazon S3.
315              
316             =head2 update()
317              
318             Update contents and/or contenttype of the file.
319              
320             =head2 signed_url( $expiry_time )
321              
322             Will return a signed URL for public access to the file. $expiry_time should be a
323             Unix seconds since epoch, and will default to now + 1 hour is not passed.
324              
325             Note that the Signature parameter value will be URI encoded to prevent reserved
326             characters (+, =, etc) causing a bad request.
327              
328             =head1 SEE ALSO
329              
330             L<The Amazon S3 API Documentation|http://docs.amazonwebservices.com/AmazonS3/latest/API/>
331              
332             L<AWS::S3>
333              
334             L<AWS::S3::Bucket>
335              
336             L<AWS::S3::FileIterator>
337              
338             L<AWS::S3::Owner>
339              
340             =cut
341