cmeiklejohn-aws 2.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1101 @@
1
+ #
2
+ # Copyright (c) 2007-2008 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+
24
+ module Aws
25
+
26
+ # = Aws::S3 -- RightScale's Amazon S3 interface
27
+ # The Aws::S3 class provides a complete interface to Amazon's Simple
28
+ # Storage Service.
29
+ # For explanations of the semantics
30
+ # of each call, please refer to Amazon's documentation at
31
+ # http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=48
32
+ #
33
+ # See examples below for the bucket and buckets methods.
34
+ #
35
+ # Error handling: all operations raise an Aws::AwsError in case
36
+ # of problems. Note that transient errors are automatically retried.
37
+ #
38
+ # It is a good way to use domain naming style getting a name for the buckets.
39
+ # See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingBucket.html
40
+ # about the naming convention for the buckets. This case they can be accessed using a virtual domains.
41
+ #
42
+ # Let assume you have 3 buckets: 'awesome-bucket', 'awesome_bucket' and 'AWEsomE-bucket'.
43
+ # The first ones objects can be accessed as: http:// awesome-bucket.s3.amazonaws.com/key/object
44
+ #
45
+ # But the rest have to be accessed as:
46
+ # http:// s3.amazonaws.com/awesome_bucket/key/object and http:// s3.amazonaws.com/AWEsomE-bucket/key/object
47
+ #
48
+ # See: http://docs.amazonwebservices.com/AmazonS3/2006-03-01/VirtualHosting.html for better explanation.
49
+ #
50
+ class S3
51
+ attr_reader :interface
52
+
53
+ # Create a new handle to an S3 account. All handles share the same per process or per thread
54
+ # HTTP connection to Amazon S3. Each handle is for a specific account.
55
+ # The +params+ are passed through as-is to Aws::S3Interface.new
56
+ #
57
+ # Params is a hash:
58
+ #
59
+ # {:server => 's3.amazonaws.com' # Amazon service host: 's3.amazonaws.com'(default)
60
+ # :port => 443 # Amazon service port: 80 or 443(default)
61
+ # :protocol => 'https' # Amazon service protocol: 'http' or 'https'(default)
62
+ # :multi_thread => true|false # Multi-threaded (connection per each thread): true or false(default)
63
+ # :logger => Logger Object} # Logger instance: logs to STDOUT if omitted }
64
+ def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
65
+ @interface = S3Interface.new(aws_access_key_id, aws_secret_access_key, params)
66
+ end
67
+
68
+ def close_connection
69
+ @interface.close_connection
70
+ end
71
+
72
+ # Retrieve a list of buckets.
73
+ # Returns an array of Aws::S3::Bucket instances.
74
+ # # Create handle to S3 account
75
+ # s3 = Aws::S3.new(aws_access_key_id, aws_secret_access_key)
76
+ # my_buckets_names = s3.buckets.map{|b| b.name}
77
+ # puts "Buckets on S3: #{my_bucket_names.join(', ')}"
78
+ def buckets
79
+ @interface.list_all_my_buckets.map! do |entry|
80
+ owner = Owner.new(entry[:owner_id], entry[:owner_display_name])
81
+ Bucket.new(self, entry[:name], entry[:creation_date], owner)
82
+ end
83
+ end
84
+
85
+ # Retrieve an individual bucket.
86
+ # If the bucket does not exist and +create+ is set, a new bucket
87
+ # is created on S3. Launching this method with +create+=+true+ may
88
+ # affect on the bucket's ACL if the bucket already exists.
89
+ # Returns a Aws::S3::Bucket instance or +nil+ if the bucket does not exist
90
+ # and +create+ is not set.
91
+ #
92
+ # s3 = Aws::S3.new(aws_access_key_id, aws_secret_access_key)
93
+ # bucket1 = s3.bucket('my_awesome_bucket_1')
94
+ # bucket1.keys #=> exception here if the bucket does not exists
95
+ # ...
96
+ # bucket2 = s3.bucket('my_awesome_bucket_2', true)
97
+ # bucket2.keys #=> list of keys
98
+ # # create a bucket at the European location with public read access
99
+ # bucket3 = s3.bucket('my-awesome-bucket-3', true, 'public-read', :location => :eu)
100
+ #
101
+ # see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html
102
+ # (section: Canned Access Policies)
103
+ #
104
+ def bucket(name, create=false, perms=nil, headers={})
105
+ headers['x-amz-acl'] = perms if perms
106
+ @interface.create_bucket(name, headers) if create
107
+ return Bucket.new(self, name)
108
+ # The old way below was too slow and unnecessary because it retreived all the buckets every time.
109
+ # owner = Owner.new(entry[:owner_id], entry[:owner_display_name])
110
+ # buckets.each { |bucket| return bucket if bucket.name == name }
111
+ # nil
112
+ end
113
+
114
+
115
+ class Bucket
116
+ attr_reader :s3, :name, :owner, :creation_date
117
+
118
+ # Create a Bucket instance.
119
+ # If the bucket does not exist and +create+ is set, a new bucket
120
+ # is created on S3. Launching this method with +create+=+true+ may
121
+ # affect on the bucket's ACL if the bucket already exists.
122
+ # Returns Bucket instance or +nil+ if the bucket does not exist
123
+ # and +create+ is not set.
124
+ #
125
+ # s3 = Aws::S3.new(aws_access_key_id, aws_secret_access_key)
126
+ # ...
127
+ # bucket1 = Aws::S3::Bucket.create(s3, 'my_awesome_bucket_1')
128
+ # bucket1.keys #=> exception here if the bucket does not exists
129
+ # ...
130
+ # bucket2 = Aws::S3::Bucket.create(s3, 'my_awesome_bucket_2', true)
131
+ # bucket2.keys #=> list of keys
132
+ # # create a bucket at the European location with public read access
133
+ # bucket3 = Aws::S3::Bucket.create(s3,'my-awesome-bucket-3', true, 'public-read', :location => :eu)
134
+ #
135
+ # see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html
136
+ # (section: Canned Access Policies)
137
+ #
138
+ def self.create(s3, name, create=false, perms=nil, headers={})
139
+ s3.bucket(name, create, perms, headers)
140
+ end
141
+
142
+
143
+ # Create a bucket instance. In normal use this method should
144
+ # not be called directly.
145
+ # Use Aws::S3::Bucket.create or Aws::S3.bucket instead.
146
+ def initialize(s3, name, creation_date=nil, owner=nil)
147
+ @s3 = s3
148
+ @name = name
149
+ @owner = owner
150
+ @creation_date = creation_date
151
+ if @creation_date && !@creation_date.is_a?(Time)
152
+ @creation_date = Time.parse(@creation_date)
153
+ end
154
+ end
155
+
156
+ # Return bucket name as a String.
157
+ #
158
+ # bucket = Aws::S3.bucket('my_awesome_bucket')
159
+ # puts bucket #=> 'my_awesome_bucket'
160
+ #
161
+ def to_s
162
+ @name.to_s
163
+ end
164
+ alias_method :full_name, :to_s
165
+
166
+ # Return a public link to bucket.
167
+ #
168
+ # bucket.public_link #=> 'https://s3.amazonaws.com:443/my_awesome_bucket'
169
+ #
170
+ def public_link
171
+ params = @s3.interface.params
172
+ "#{params[:protocol]}://#{params[:server]}:#{params[:port]}/#{full_name}"
173
+ end
174
+
175
+ # Returns the bucket location
176
+ def location
177
+ @location ||= @s3.interface.bucket_location(@name)
178
+ end
179
+
180
+ # Retrieves the logging configuration for a bucket.
181
+ # Returns a hash of {:enabled, :targetbucket, :targetprefix}
182
+ #
183
+ # bucket.logging_info()
184
+ # => {:enabled=>true, :targetbucket=>"mylogbucket", :targetprefix=>"loggylogs/"}
185
+ def logging_info
186
+ @s3.interface.get_logging_parse(:bucket => @name)
187
+ end
188
+
189
+ # Enables S3 server access logging on a bucket. The target bucket must have been properly configured to receive server
190
+ # access logs.
191
+ # Params:
192
+ # :targetbucket - either the target bucket object or the name of the target bucket
193
+ # :targetprefix - the prefix under which all logs should be stored
194
+ #
195
+ # bucket.enable_logging(:targetbucket=>"mylogbucket", :targetprefix=>"loggylogs/")
196
+ # => true
197
+ def enable_logging(params)
198
+ AwsUtils.mandatory_arguments([:targetbucket, :targetprefix], params)
199
+ AwsUtils.allow_only([:targetbucket, :targetprefix], params)
200
+ xmldoc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><BucketLoggingStatus xmlns=\"http://doc.s3.amazonaws.com/2006-03-01\"><LoggingEnabled><TargetBucket>#{params[:targetbucket]}</TargetBucket><TargetPrefix>#{params[:targetprefix]}</TargetPrefix></LoggingEnabled></BucketLoggingStatus>"
201
+ @s3.interface.put_logging(:bucket => @name, :xmldoc => xmldoc)
202
+ end
203
+
204
+ # Disables S3 server access logging on a bucket. Takes no arguments.
205
+ def disable_logging
206
+ xmldoc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><BucketLoggingStatus xmlns=\"http://doc.s3.amazonaws.com/2006-03-01\"></BucketLoggingStatus>"
207
+ @s3.interface.put_logging(:bucket => @name, :xmldoc => xmldoc)
208
+ end
209
+
210
+ # Retrieve a group of keys from Amazon.
211
+ # +options+ is a hash: { 'prefix'=>'', 'marker'=>'', 'max-keys'=>5, 'delimiter'=>'' }).
212
+ # Retrieves meta-headers information if +head+ it +true+.
213
+ # Returns an array of Key instances.
214
+ #
215
+ # bucket.keys #=> # returns all keys from bucket
216
+ # bucket.keys('prefix' => 'logs') #=> # returns all keys that starts with 'logs'
217
+ #
218
+ def keys(options={}, head=false)
219
+ keys_and_service(options, head)[0]
220
+ end
221
+
222
+ # Same as +keys+ method but return an array of [keys, service_data].
223
+ # where +service_data+ is a hash with additional output information.
224
+ #
225
+ # keys, service = bucket.keys_and_service({'max-keys'=> 2, 'prefix' => 'logs'})
226
+ # p keys #=> # 2 keys array
227
+ # p service #=> {"max-keys"=>"2", "prefix"=>"logs", "name"=>"my_awesome_bucket", "marker"=>"", "is_truncated"=>true}
228
+ #
229
+ def keys_and_service(options={}, head=false)
230
+ opt = {}; options.each{ |key, value| opt[key.to_s] = value }
231
+ service_data = {}
232
+ thislist = {}
233
+ list = []
234
+ @s3.interface.incrementally_list_bucket(@name, opt) do |thislist|
235
+ thislist[:contents].each do |entry|
236
+ owner = Owner.new(entry[:owner_id], entry[:owner_display_name])
237
+ key = Key.new(self, entry[:key], nil, {}, {}, entry[:last_modified], entry[:e_tag], entry[:size], entry[:storage_class], owner)
238
+ key.head if head
239
+ list << key
240
+ end
241
+ end
242
+ thislist.each_key do |key|
243
+ service_data[key] = thislist[key] unless (key == :contents || key == :common_prefixes)
244
+ end
245
+ [list, service_data]
246
+ end
247
+
248
+ # Retrieve key information from Amazon.
249
+ # The +key_name+ is a +String+ or Key instance.
250
+ # Retrieves meta-header information if +head+ is +true+.
251
+ # Returns new Key instance.
252
+ #
253
+ # key = bucket.key('logs/today/1.log', true) #=> #<Aws::S3::Key:0xb7b1e240 ... >
254
+ # # is the same as:
255
+ # key = Aws::S3::Key.create(bucket, 'logs/today/1.log')
256
+ # key.head
257
+ #
258
+ def key(key_name, head=false)
259
+ raise 'Key name can not be empty.' if key_name.blank?
260
+ key_instance = nil
261
+ # if this key exists - find it ....
262
+ keys({'prefix'=>key_name}, head).each do |key|
263
+ if key.name == key_name.to_s
264
+ key_instance = key
265
+ break
266
+ end
267
+ end
268
+ # .... else this key is unknown
269
+ unless key_instance
270
+ key_instance = Key.create(self, key_name.to_s)
271
+ end
272
+ key_instance
273
+ end
274
+
275
+ # Store object data.
276
+ # The +key+ is a +String+ or Key instance.
277
+ # Returns +true+.
278
+ #
279
+ # bucket.put('logs/today/1.log', 'Olala!') #=> true
280
+ #
281
+ def put(key, data=nil, meta_headers={}, perms=nil, headers={})
282
+ key = Key.create(self, key.to_s, data, meta_headers) unless key.is_a?(Key)
283
+ key.put(data, perms, headers)
284
+ end
285
+
286
+ # Retrieve object data from Amazon.
287
+ # The +key+ is a +String+ or Key.
288
+ # Returns Key instance.
289
+ #
290
+ # key = bucket.get('logs/today/1.log') #=>
291
+ # puts key.data #=> 'sasfasfasdf'
292
+ #
293
+ def get(key, headers={})
294
+ key = Key.create(self, key.to_s) unless key.is_a?(Key)
295
+ key.get(headers)
296
+ end
297
+
298
+ # Rename object. Returns Aws::S3::Key instance.
299
+ #
300
+ # new_key = bucket.rename_key('logs/today/1.log','logs/today/2.log') #=> #<Aws::S3::Key:0xb7b1e240 ... >
301
+ # puts key.name #=> 'logs/today/2.log'
302
+ # key.exists? #=> true
303
+ #
304
+ def rename_key(old_key_or_name, new_name)
305
+ old_key_or_name = Key.create(self, old_key_or_name.to_s) unless old_key_or_name.is_a?(Key)
306
+ old_key_or_name.rename(new_name)
307
+ old_key_or_name
308
+ end
309
+
310
+ # Create an object copy. Returns a destination Aws::S3::Key instance.
311
+ #
312
+ # new_key = bucket.copy_key('logs/today/1.log','logs/today/2.log') #=> #<Aws::S3::Key:0xb7b1e240 ... >
313
+ # puts key.name #=> 'logs/today/2.log'
314
+ # key.exists? #=> true
315
+ #
316
+ def copy_key(old_key_or_name, new_key_or_name)
317
+ old_key_or_name = Key.create(self, old_key_or_name.to_s) unless old_key_or_name.is_a?(Key)
318
+ old_key_or_name.copy(new_key_or_name)
319
+ end
320
+
321
+ # Move an object to other location. Returns a destination Aws::S3::Key instance.
322
+ #
323
+ # new_key = bucket.copy_key('logs/today/1.log','logs/today/2.log') #=> #<Aws::S3::Key:0xb7b1e240 ... >
324
+ # puts key.name #=> 'logs/today/2.log'
325
+ # key.exists? #=> true
326
+ #
327
+ def move_key(old_key_or_name, new_key_or_name)
328
+ old_key_or_name = Key.create(self, old_key_or_name.to_s) unless old_key_or_name.is_a?(Key)
329
+ old_key_or_name.move(new_key_or_name)
330
+ end
331
+
332
+ # Remove all keys from a bucket.
333
+ # Returns +true+.
334
+ #
335
+ # bucket.clear #=> true
336
+ #
337
+ def clear
338
+ @s3.interface.clear_bucket(@name)
339
+ end
340
+
341
+ # Delete all keys where the 'folder_key' can be interpreted
342
+ # as a 'folder' name.
343
+ # Returns an array of string keys that have been deleted.
344
+ #
345
+ # bucket.keys.map{|key| key.name}.join(', ') #=> 'test, test/2/34, test/3, test1, test1/logs'
346
+ # bucket.delete_folder('test') #=> ['test','test/2/34','test/3']
347
+ #
348
+ def delete_folder(folder, separator='/')
349
+ @s3.interface.delete_folder(@name, folder, separator)
350
+ end
351
+
352
+ # Delete a bucket. Bucket must be empty.
353
+ # If +force+ is set, clears and deletes the bucket.
354
+ # Returns +true+.
355
+ #
356
+ # bucket.delete(true) #=> true
357
+ #
358
+ def delete(force=false)
359
+ force ? @s3.interface.force_delete_bucket(@name) : @s3.interface.delete_bucket(@name)
360
+ end
361
+
362
+ # Return a list of grantees.
363
+ #
364
+ def grantees
365
+ Grantee::grantees(self)
366
+ end
367
+
368
+ end
369
+
370
+
371
+ class Key
372
+ attr_reader :bucket, :name, :last_modified, :e_tag, :size, :storage_class, :owner
373
+ attr_accessor :headers, :meta_headers
374
+ attr_writer :data
375
+
376
+ # Separate Amazon meta headers from other headers
377
+ def self.split_meta(headers) #:nodoc:
378
+ hash = headers.dup
379
+ meta = {}
380
+ hash.each do |key, value|
381
+ if key[/^#{S3Interface::AMAZON_METADATA_PREFIX}/]
382
+ meta[key.gsub(S3Interface::AMAZON_METADATA_PREFIX,'')] = value
383
+ hash.delete(key)
384
+ end
385
+ end
386
+ [hash, meta]
387
+ end
388
+
389
+ def self.add_meta_prefix(meta_headers, prefix=S3Interface::AMAZON_METADATA_PREFIX)
390
+ meta = {}
391
+ meta_headers.each do |meta_header, value|
392
+ if meta_header[/#{prefix}/]
393
+ meta[meta_header] = value
394
+ else
395
+ meta["#{S3Interface::AMAZON_METADATA_PREFIX}#{meta_header}"] = value
396
+ end
397
+ end
398
+ meta
399
+ end
400
+
401
+
402
+ # Create a new Key instance, but do not create the actual key.
403
+ # The +name+ is a +String+.
404
+ # Returns a new Key instance.
405
+ #
406
+ # key = Aws::S3::Key.create(bucket, 'logs/today/1.log') #=> #<Aws::S3::Key:0xb7b1e240 ... >
407
+ # key.exists? #=> true | false
408
+ # key.put('Woohoo!') #=> true
409
+ # key.exists? #=> true
410
+ #
411
+ def self.create(bucket, name, data=nil, meta_headers={})
412
+ new(bucket, name, data, {}, meta_headers)
413
+ end
414
+
415
+ # Create a new Key instance, but do not create the actual key.
416
+ # In normal use this method should not be called directly.
417
+ # Use Aws::S3::Key.create or bucket.key() instead.
418
+ #
419
+ def initialize(bucket, name, data=nil, headers={}, meta_headers={},
420
+ last_modified=nil, e_tag=nil, size=nil, storage_class=nil, owner=nil)
421
+ raise 'Bucket must be a Bucket instance.' unless bucket.is_a?(Bucket)
422
+ @bucket = bucket
423
+ @name = name
424
+ @data = data
425
+ @e_tag = e_tag
426
+ @size = size.to_i
427
+ @storage_class = storage_class
428
+ @owner = owner
429
+ @last_modified = last_modified
430
+ if @last_modified && !@last_modified.is_a?(Time)
431
+ @last_modified = Time.parse(@last_modified)
432
+ end
433
+ @headers, @meta_headers = self.class.split_meta(headers)
434
+ @meta_headers.merge!(meta_headers)
435
+ end
436
+
437
+ # Return key name as a String.
438
+ #
439
+ # key = Aws::S3::Key.create(bucket, 'logs/today/1.log') #=> #<Aws::S3::Key:0xb7b1e240 ... >
440
+ # puts key #=> 'logs/today/1.log'
441
+ #
442
+ def to_s
443
+ @name.to_s
444
+ end
445
+
446
+ # Return the full S3 path to this key (bucket/key).
447
+ #
448
+ # key.full_name #=> 'my_awesome_bucket/cool_key'
449
+ #
450
+ def full_name(separator='/')
451
+ "#{@bucket.to_s}#{separator}#{@name}"
452
+ end
453
+
454
+ # Return a public link to a key.
455
+ #
456
+ # key.public_link #=> 'https://s3.amazonaws.com:443/my_awesome_bucket/cool_key'
457
+ #
458
+ def public_link
459
+ params = @bucket.s3.interface.params
460
+ "#{params[:protocol]}://#{params[:server]}:#{params[:port]}/#{full_name('/')}"
461
+ end
462
+
463
+ # Return Key data. Retrieve this data from Amazon if it is the first time call.
464
+ # TODO TRB 6/19/07 What does the above mean? Clarify.
465
+ #
466
+ def data
467
+ get if !@data and exists?
468
+ @data
469
+ end
470
+
471
+ # Retrieve object data and attributes from Amazon.
472
+ # Returns a +String+.
473
+ #
474
+ def get(headers={}, &block)
475
+ response = @bucket.s3.interface.get(@bucket.name, @name, headers, &block)
476
+ @data = response[:object]
477
+ @headers, @meta_headers = self.class.split_meta(response[:headers])
478
+ refresh(false)
479
+ @data
480
+ end
481
+
482
+ # Store object data on S3.
483
+ # Parameter +data+ is a +String+ or S3Object instance.
484
+ # Returns +true+.
485
+ #
486
+ # key = Aws::S3::Key.create(bucket, 'logs/today/1.log')
487
+ # key.data = 'Qwerty'
488
+ # key.put #=> true
489
+ # ...
490
+ # key.put('Olala!') #=> true
491
+ #
492
+ def put(data=nil, perms=nil, headers={})
493
+ headers['x-amz-acl'] = perms if perms
494
+ @data = data || @data
495
+ meta = self.class.add_meta_prefix(@meta_headers)
496
+ @bucket.s3.interface.put(@bucket.name, @name, @data, meta.merge(headers))
497
+ end
498
+
499
+ # Rename an object. Returns new object name.
500
+ #
501
+ # key = Aws::S3::Key.create(bucket, 'logs/today/1.log') #=> #<Aws::S3::Key:0xb7b1e240 ... >
502
+ # key.rename('logs/today/2.log') #=> 'logs/today/2.log'
503
+ # puts key.name #=> 'logs/today/2.log'
504
+ # key.exists? #=> true
505
+ #
506
+ def rename(new_name)
507
+ @bucket.s3.interface.rename(@bucket.name, @name, new_name)
508
+ @name = new_name
509
+ end
510
+
511
+ # Create an object copy. Returns a destination Aws::S3::Key instance.
512
+ #
513
+ # # Key instance as destination
514
+ # key1 = Aws::S3::Key.create(bucket, 'logs/today/1.log') #=> #<Aws::S3::Key:0xb7b1e240 ... >
515
+ # key2 = Aws::S3::Key.create(bucket, 'logs/today/2.log') #=> #<Aws::S3::Key:0xb7b5e240 ... >
516
+ # key1.put('Olala!') #=> true
517
+ # key1.copy(key2) #=> #<Aws::S3::Key:0xb7b5e240 ... >
518
+ # key1.exists? #=> true
519
+ # key2.exists? #=> true
520
+ # puts key2.data #=> 'Olala!'
521
+ #
522
+ # # String as destination
523
+ # key = Aws::S3::Key.create(bucket, 'logs/today/777.log') #=> #<Aws::S3::Key:0xb7b1e240 ... >
524
+ # key.put('Olala!') #=> true
525
+ # new_key = key.copy('logs/today/888.log') #=> #<Aws::S3::Key:0xb7b5e240 ... >
526
+ # key.exists? #=> true
527
+ # new_key.exists? #=> true
528
+ #
529
+ def copy(new_key_or_name)
530
+ new_key_or_name = Key.create(@bucket, new_key_or_name.to_s) unless new_key_or_name.is_a?(Key)
531
+ @bucket.s3.interface.copy(@bucket.name, @name, new_key_or_name.bucket.name, new_key_or_name.name)
532
+ new_key_or_name
533
+ end
534
+
535
+ # Move an object to other location. Returns a destination Aws::S3::Key instance.
536
+ #
537
+ # # Key instance as destination
538
+ # key1 = Aws::S3::Key.create(bucket, 'logs/today/1.log') #=> #<Aws::S3::Key:0xb7b1e240 ... >
539
+ # key2 = Aws::S3::Key.create(bucket, 'logs/today/2.log') #=> #<Aws::S3::Key:0xb7b5e240 ... >
540
+ # key1.put('Olala!') #=> true
541
+ # key1.move(key2) #=> #<Aws::S3::Key:0xb7b5e240 ... >
542
+ # key1.exists? #=> false
543
+ # key2.exists? #=> true
544
+ # puts key2.data #=> 'Olala!'
545
+ #
546
+ # # String as destination
547
+ # key = Aws::S3::Key.create(bucket, 'logs/today/777.log') #=> #<Aws::S3::Key:0xb7b1e240 ... >
548
+ # key.put('Olala!') #=> true
549
+ # new_key = key.move('logs/today/888.log') #=> #<Aws::S3::Key:0xb7b5e240 ... >
550
+ # key.exists? #=> false
551
+ # new_key.exists? #=> true
552
+ #
553
+ def move(new_key_or_name)
554
+ new_key_or_name = Key.create(@bucket, new_key_or_name.to_s) unless new_key_or_name.is_a?(Key)
555
+ @bucket.s3.interface.move(@bucket.name, @name, new_key_or_name.bucket.name, new_key_or_name.name)
556
+ new_key_or_name
557
+ end
558
+
559
+ # Retrieve key info from bucket and update attributes.
560
+ # Refresh meta-headers (by calling +head+ method) if +head+ is set.
561
+ # Returns +true+ if the key exists in bucket and +false+ otherwise.
562
+ #
563
+ # key = Aws::S3::Key.create(bucket, 'logs/today/1.log')
564
+ # key.e_tag #=> nil
565
+ # key.meta_headers #=> {}
566
+ # key.refresh #=> true
567
+ # key.e_tag #=> '12345678901234567890bf11094484b6'
568
+ # key.meta_headers #=> {"family"=>"qwerty", "name"=>"asdfg"}
569
+ #
570
+ def refresh(head=true)
571
+ new_key = @bucket.key(self)
572
+ @last_modified = new_key.last_modified
573
+ @e_tag = new_key.e_tag
574
+ @size = new_key.size
575
+ @storage_class = new_key.storage_class
576
+ @owner = new_key.owner
577
+ if @last_modified
578
+ self.head
579
+ true
580
+ else
581
+ @headers = @meta_headers = {}
582
+ false
583
+ end
584
+ end
585
+
586
+ # Updates headers and meta-headers from S3.
587
+ # Returns +true+.
588
+ #
589
+ # key.meta_headers #=> {"family"=>"qwerty"}
590
+ # key.head #=> true
591
+ # key.meta_headers #=> {"family"=>"qwerty", "name"=>"asdfg"}
592
+ #
593
+ def head
594
+ @headers, @meta_headers = self.class.split_meta(@bucket.s3.interface.head(@bucket, @name))
595
+ true
596
+ end
597
+
598
+ # Reload meta-headers only. Returns meta-headers hash.
599
+ #
600
+ # key.reload_meta #=> {"family"=>"qwerty", "name"=>"asdfg"}
601
+ #
602
+ def reload_meta
603
+ @meta_headers = self.class.split_meta(@bucket.s3.interface.head(@bucket, @name)).last
604
+ end
605
+
606
+ # Replace meta-headers by new hash at S3. Returns new meta-headers hash.
607
+ #
608
+ # key.reload_meta #=> {"family"=>"qwerty", "name"=>"asdfg"}
609
+ # key.save_meta #=> {"family"=>"oops", "race" => "troll"}
610
+ # key.reload_meta #=> {"family"=>"oops", "race" => "troll"}
611
+ #
612
+ def save_meta(meta_headers)
613
+ meta = self.class.add_meta_prefix(meta_headers)
614
+ @bucket.s3.interface.copy(@bucket.name, @name, @bucket.name, @name, :replace, meta)
615
+ @meta_headers = self.class.split_meta(meta)[1]
616
+ end
617
+
618
+ # Check for existence of the key in the given bucket.
619
+ # Returns +true+ or +false+.
620
+ #
621
+ # key = Aws::S3::Key.create(bucket,'logs/today/1.log')
622
+ # key.exists? #=> false
623
+ # key.put('Woohoo!') #=> true
624
+ # key.exists? #=> true
625
+ #
626
+ def exists?
627
+ @bucket.key(self).last_modified ? true : false
628
+ end
629
+
630
+ # Remove key from bucket.
631
+ # Returns +true+.
632
+ #
633
+ # key.delete #=> true
634
+ #
635
+ def delete
636
+ raise 'Key name must be specified.' if @name.blank?
637
+ @bucket.s3.interface.delete(@bucket, @name)
638
+ end
639
+
640
+ # Return a list of grantees.
641
+ #
642
+ def grantees
643
+ Grantee::grantees(self)
644
+ end
645
+
646
+ end
647
+
648
+
649
+ class Owner
650
+ attr_reader :id, :name
651
+
652
+ def initialize(id, name)
653
+ @id = id
654
+ @name = name
655
+ end
656
+
657
+ # Return Owner name as a +String+.
658
+ def to_s
659
+ @name
660
+ end
661
+ end
662
+
663
+
664
+ # There are 2 ways to set permissions for a bucket or key (called a +thing+ below):
665
+ #
666
+ # 1 . Use +perms+ param to set 'Canned Access Policies' when calling the <tt>bucket.create</tt>,
667
+ # <tt>bucket.put</tt> and <tt>key.put</tt> methods.
668
+ # The +perms+ param can take these values: 'private', 'public-read', 'public-read-write' and
669
+ # 'authenticated-read'.
670
+ # (see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html).
671
+ #
672
+ # bucket = s3.bucket('bucket_for_kd_test_13', true, 'public-read')
673
+ # key.put('Woohoo!','public-read-write' )
674
+ #
675
+ # 2 . Use Grantee instances (the permission is a +String+ or an +Array+ of: 'READ', 'WRITE',
676
+ # 'READ_ACP', 'WRITE_ACP', 'FULL_CONTROL'):
677
+ #
678
+ # bucket = s3.bucket('my_awesome_bucket', true)
679
+ # grantee1 = Aws::S3::Grantee.new(bucket, 'a123b...223c', FULL_CONTROL, :apply)
680
+ # grantee2 = Aws::S3::Grantee.new(bucket, 'xy3v3...5fhp', [READ, WRITE], :apply)
681
+ #
682
+ # There is only one way to get and to remove permission (via Grantee instances):
683
+ #
684
+ # grantees = bucket.grantees # a list of Grantees that have any access for this bucket
685
+ # grantee1 = Aws::S3::Grantee.new(bucket, 'a123b...223c')
686
+ # grantee1.perms #=> returns a list of perms for this grantee to that bucket
687
+ # ...
688
+ # grantee1.drop # remove all perms for this grantee
689
+ # grantee2.revoke('WRITE') # revoke write access only
690
+ #
691
+ class Grantee
692
+ # A bucket or a key the grantee has an access to.
693
+ attr_reader :thing
694
+ # Grantee Amazon id.
695
+ attr_reader :id
696
+ # Grantee display name.
697
+ attr_reader :name
698
+ # Array of permissions.
699
+ attr_accessor :perms
700
+
701
+ # Retrieve Owner information and a list of Grantee instances that have
702
+ # a access to this thing (bucket or key).
703
+ #
704
+ # bucket = s3.bucket('my_awesome_bucket', true, 'public-read')
705
+ # ...
706
+ # Aws::S3::Grantee.owner_and_grantees(bucket) #=> [owner, grantees]
707
+ #
708
+ def self.owner_and_grantees(thing)
709
+ if thing.is_a?(Bucket)
710
+ bucket, key = thing, ''
711
+ else
712
+ bucket, key = thing.bucket, thing
713
+ end
714
+ hash = bucket.s3.interface.get_acl_parse(bucket.to_s, key.to_s)
715
+ owner = Owner.new(hash[:owner][:id], hash[:owner][:display_name])
716
+
717
+ grantees = []
718
+ hash[:grantees].each do |id, params|
719
+ grantees << new(thing, id, params[:permissions], nil, params[:display_name])
720
+ end
721
+ [owner, grantees]
722
+ end
723
+
724
+ # Retrieves a list of Grantees instances that have an access to this thing(bucket or key).
725
+ #
726
+ # bucket = s3.bucket('my_awesome_bucket', true, 'public-read')
727
+ # ...
728
+ # Aws::S3::Grantee.grantees(bucket) #=> grantees
729
+ #
730
+ def self.grantees(thing)
731
+ owner_and_grantees(thing)[1]
732
+ end
733
+
734
+ def self.put_acl(thing, owner, grantees) #:nodoc:
735
+ if thing.is_a?(Bucket)
736
+ bucket, key = thing, ''
737
+ else
738
+ bucket, key = thing.bucket, thing
739
+ end
740
+ body = "<AccessControlPolicy>" +
741
+ "<Owner>" +
742
+ "<ID>#{owner.id}</ID>" +
743
+ "<DisplayName>#{owner.name}</DisplayName>" +
744
+ "</Owner>" +
745
+ "<AccessControlList>" +
746
+ grantees.map{|grantee| grantee.to_xml}.join +
747
+ "</AccessControlList>" +
748
+ "</AccessControlPolicy>"
749
+ bucket.s3.interface.put_acl(bucket.to_s, key.to_s, body)
750
+ end
751
+
752
+ # Create a new Grantee instance.
753
+ # Grantee +id+ must exist on S3. If +action+ == :refresh, then retrieve
754
+ # permissions from S3 and update @perms. If +action+ == :apply, then apply
755
+ # perms to +thing+ at S3. If +action+ == :apply_and_refresh then it performs.
756
+ # both the actions. This is used for the new grantees that had no perms to
757
+ # this thing before. The default action is :refresh.
758
+ #
759
+ # bucket = s3.bucket('my_awesome_bucket', true, 'public-read')
760
+ # grantee1 = Aws::S3::Grantee.new(bucket, 'a123b...223c', FULL_CONTROL)
761
+ # ...
762
+ # grantee2 = Aws::S3::Grantee.new(bucket, 'abcde...asdf', [FULL_CONTROL, READ], :apply)
763
+ # grantee3 = Aws::S3::Grantee.new(bucket, 'aaaaa...aaaa', 'READ', :apply_and_refresh)
764
+ #
765
+ def initialize(thing, id, perms=[], action=:refresh, name=nil)
766
+ @thing = thing
767
+ @id = id
768
+ @name = name
769
+ @perms = perms.to_a
770
+ case action
771
+ when :apply then apply
772
+ when :refresh then refresh
773
+ when :apply_and_refresh then apply; refresh
774
+ end
775
+ end
776
+
777
+ # Return +true+ if the grantee has any permissions to the thing.
778
+ def exists?
779
+ self.class.grantees(@thing).each do |grantee|
780
+ return true if @id == grantee.id
781
+ end
782
+ false
783
+ end
784
+
785
+ # Return Grantee type (+String+): "Group" or "CanonicalUser".
786
+ def type
787
+ @id[/^http:/] ? "Group" : "CanonicalUser"
788
+ end
789
+
790
+ # Return a name or an id.
791
+ def to_s
792
+ @name || @id
793
+ end
794
+
795
+ # Add permissions for grantee.
796
+ # Permissions: 'READ', 'WRITE', 'READ_ACP', 'WRITE_ACP', 'FULL_CONTROL'.
797
+ # See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingPermissions.html .
798
+ # Returns +true+.
799
+ #
800
+ # grantee.grant('FULL_CONTROL') #=> true
801
+ # grantee.grant('FULL_CONTROL','WRITE','READ') #=> true
802
+ # grantee.grant(['WRITE_ACP','READ','READ_ACP']) #=> true
803
+ #
804
+ def grant(*permissions)
805
+ permissions.flatten!
806
+ old_perms = @perms.dup
807
+ @perms += permissions
808
+ @perms.uniq!
809
+ return true if @perms == old_perms
810
+ apply
811
+ end
812
+
813
+ # Revoke permissions for grantee.
814
+ # Permissions: 'READ', 'WRITE', 'READ_ACP', 'WRITE_ACP', 'FULL_CONTROL'
815
+ # See http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingPermissions.html .
816
+ # Default value is 'FULL_CONTROL'.
817
+ # Returns +true+.
818
+ #
819
+ # grantee.revoke('READ') #=> true
820
+ # grantee.revoke('FULL_CONTROL','WRITE') #=> true
821
+ # grantee.revoke(['READ_ACP','WRITE_ACP']) #=> true
822
+ #
823
+ def revoke(*permissions)
824
+ permissions.flatten!
825
+ old_perms = @perms.dup
826
+ @perms -= permissions
827
+ @perms.uniq!
828
+ return true if @perms == old_perms
829
+ apply
830
+ end
831
+
832
+ # Revoke all permissions for this grantee.
833
+ # Returns +true+.
834
+ #
835
+ # grantee.drop #=> true
836
+ #
837
+ def drop
838
+ @perms = []
839
+ apply
840
+ end
841
+
842
+ # Refresh grantee perms for its +thing+.
843
+ # Returns +true+ if the grantee has perms for this +thing+ or
844
+ # +false+ otherwise, and updates @perms value as a side-effect.
845
+ #
846
+ # grantee.grant('FULL_CONTROL') #=> true
847
+ # grantee.refresh #=> true
848
+ # grantee.drop #=> true
849
+ # grantee.refresh #=> false
850
+ #
851
+ def refresh
852
+ @perms = []
853
+ self.class.grantees(@thing).each do |grantee|
854
+ if @id == grantee.id
855
+ @name = grantee.name
856
+ @perms = grantee.perms
857
+ return true
858
+ end
859
+ end
860
+ false
861
+ end
862
+
863
+ # Apply current grantee @perms to +thing+. This method is called internally by the +grant+
864
+ # and +revoke+ methods. In normal use this method should not
865
+ # be called directly.
866
+ #
867
+ # grantee.perms = ['FULL_CONTROL']
868
+ # grantee.apply #=> true
869
+ #
870
+ def apply
871
+ @perms.uniq!
872
+ owner, grantees = self.class.owner_and_grantees(@thing)
873
+ # walk through all the grantees and replace the data for the current one and ...
874
+ grantees.map! { |grantee| grantee.id == @id ? self : grantee }
875
+ # ... if this grantee is not known - add this bad boy to a list
876
+ grantees << self unless grantees.include?(self)
877
+ # set permissions
878
+ self.class.put_acl(@thing, owner, grantees)
879
+ end
880
+
881
+ def to_xml # :nodoc:
882
+ id_str = @id[/^http/] ? "<URI>#{@id}</URI>" : "<ID>#{@id}</ID>"
883
+ grants = ''
884
+ @perms.each do |perm|
885
+ grants << "<Grant>" +
886
+ "<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
887
+ "xsi:type=\"#{type}\">#{id_str}</Grantee>" +
888
+ "<Permission>#{perm}</Permission>" +
889
+ "</Grant>"
890
+ end
891
+ grants
892
+ end
893
+
894
+ end
895
+
896
+ end
897
+
898
+ # Aws::S3Generator and Aws::S3Generator::Bucket methods:
899
+ #
900
+ # s3g = Aws::S3Generator.new('1...2', 'nx...Y6') #=> #<Aws::S3Generator:0xb7b5cc94>
901
+ #
902
+ # # List all buckets(method 'GET'):
903
+ # buckets_list = s3g.buckets #=> 'https://s3.amazonaws.com:443/?Signature=Y...D&Expires=1180941864&AWSAccessKeyId=1...2'
904
+ # # Create bucket link (method 'PUT'):
905
+ # bucket = s3g.bucket('my_awesome_bucket') #=> #<Aws::S3Generator::Bucket:0xb7bcbda8>
906
+ # link_to_create = bucket.create_link(1.hour) #=> https://s3.amazonaws.com:443/my_awesome_bucket?Signature=4...D&Expires=1180942132&AWSAccessKeyId=1...2
907
+ # # ... or:
908
+ # bucket = Aws::S3Generator::Bucket.create(s3g, 'my_awesome_bucket') #=> #<Aws::S3Generator::Bucket:0xb7bcbda8>
909
+ # link_to_create = bucket.create_link(1.hour) #=> https://s3.amazonaws.com:443/my_awesome_bucket?Signature=4...D&Expires=1180942132&AWSAccessKeyId=1...2
910
+ # # ... or:
911
+ # bucket = Aws::S3Generator::Bucket.new(s3g, 'my_awesome_bucket') #=> #<Aws::S3Generator::Bucket:0xb7bcbda8>
912
+ # link_to_create = bucket.create_link(1.hour) #=> https://s3.amazonaws.com:443/my_awesome_bucket?Signature=4...D&Expires=1180942132&AWSAccessKeyId=1...2
913
+ # # List bucket(method 'GET'):
914
+ # bucket.keys(1.day) #=> https://s3.amazonaws.com:443/my_awesome_bucket?Signature=i...D&Expires=1180942620&AWSAccessKeyId=1...2
915
+ # # Create/put key (method 'PUT'):
916
+ # bucket.put('my_cool_key') #=> https://s3.amazonaws.com:443/my_awesome_bucket/my_cool_key?Signature=q...D&Expires=1180943094&AWSAccessKeyId=1...2
917
+ # # Get key data (method 'GET'):
918
+ # bucket.get('logs/today/1.log', 1.hour) #=> https://s3.amazonaws.com:443/my_awesome_bucket/my_cool_key?Signature=h...M%3D&Expires=1180820032&AWSAccessKeyId=1...2
919
+ # # Delete bucket (method 'DELETE'):
920
+ # bucket.delete(2.hour) #=> https://s3.amazonaws.com:443/my_awesome_bucket/logs%2Ftoday%2F1.log?Signature=4...D&Expires=1180820032&AWSAccessKeyId=1...2
921
+ #
922
+ # Aws::S3Generator::Key methods:
923
+ #
924
+ # # Create Key instance:
925
+ # key = Aws::S3Generator::Key.new(bicket, 'my_cool_key') #=> #<Aws::S3Generator::Key:0xb7b7394c>
926
+ # # Put key data (method 'PUT'):
927
+ # key.put #=> https://s3.amazonaws.com:443/my_awesome_bucket/my_cool_key?Signature=2...D&Expires=1180943302&AWSAccessKeyId=1...2
928
+ # # Get key data (method 'GET'):
929
+ # key.get #=> https://s3.amazonaws.com:443/my_awesome_bucket/my_cool_key?Signature=a...D&Expires=1180820032&AWSAccessKeyId=1...2
930
+ # # Head key (method 'HEAD'):
931
+ # key.head #=> https://s3.amazonaws.com:443/my_awesome_bucket/my_cool_key?Signature=b...D&Expires=1180820032&AWSAccessKeyId=1...2
932
+ # # Delete key (method 'DELETE'):
933
+ # key.delete #=> https://s3.amazonaws.com:443/my_awesome_bucket/my_cool_key?Signature=x...D&Expires=1180820032&AWSAccessKeyId=1...2
934
+ #
935
+ class S3Generator
936
+ attr_reader :interface
937
+
938
+ def initialize(aws_access_key_id, aws_secret_access_key, params={})
939
+ @interface = S3Interface.new(aws_access_key_id, aws_secret_access_key, params)
940
+ end
941
+
942
+ # Generate link to list all buckets
943
+ #
944
+ # s3.buckets(1.hour)
945
+ #
946
+ def buckets(expires=nil, headers={})
947
+ @interface.list_all_my_buckets_link(expires, headers)
948
+ end
949
+
950
+ # Create new S3LinkBucket instance and generate link to create it at S3.
951
+ #
952
+ # bucket= s3.bucket('my_owesome_bucket')
953
+ #
954
+ def bucket(name, expires=nil, headers={})
955
+ Bucket.create(self, name.to_s)
956
+ end
957
+
958
+ class Bucket
959
+ attr_reader :s3, :name
960
+
961
+ def to_s
962
+ @name
963
+ end
964
+ alias_method :full_name, :to_s
965
+
966
+ # Return a public link to bucket.
967
+ #
968
+ # bucket.public_link #=> 'https://s3.amazonaws.com:443/my_awesome_bucket'
969
+ #
970
+ def public_link
971
+ params = @s3.interface.params
972
+ "#{params[:protocol]}://#{params[:server]}:#{params[:port]}/#{full_name}"
973
+ end
974
+
975
+ # Create new S3LinkBucket instance and generate creation link for it.
976
+ def self.create(s3, name, expires=nil, headers={})
977
+ new(s3, name.to_s)
978
+ end
979
+
980
+ # Create new S3LinkBucket instance.
981
+ def initialize(s3, name)
982
+ @s3, @name = s3, name.to_s
983
+ end
984
+
985
+ # Return a link to create this bucket.
986
+ #
987
+ def create_link(expires=nil, headers={})
988
+ @s3.interface.create_bucket_link(@name, expires, headers)
989
+ end
990
+
991
+ # Generate link to list keys.
992
+ #
993
+ # bucket.keys
994
+ # bucket.keys('prefix'=>'logs')
995
+ #
996
+ def keys(options=nil, expires=nil, headers={})
997
+ @s3.interface.list_bucket_link(@name, options, expires, headers)
998
+ end
999
+
1000
+ # Return a S3Generator::Key instance.
1001
+ #
1002
+ # bucket.key('my_cool_key').get #=> https://s3.amazonaws.com:443/my_awesome_bucket/my_cool_key?Signature=B...D&Expires=1180820032&AWSAccessKeyId=1...2
1003
+ # bucket.key('my_cool_key').delete #=> https://s3.amazonaws.com:443/my_awesome_bucket/my_cool_key?Signature=B...D&Expires=1180820098&AWSAccessKeyId=1...2
1004
+ #
1005
+ def key(name)
1006
+ Key.new(self, name)
1007
+ end
1008
+
1009
+ # Generates link to PUT key data.
1010
+ #
1011
+ # puts bucket.put('logs/today/1.log', 2.hour)
1012
+ #
1013
+ def put(key, meta_headers={}, expires=nil, headers={})
1014
+ meta = Aws::S3::Key.add_meta_prefix(meta_headers)
1015
+ @s3.interface.put_link(@name, key.to_s, nil, expires, meta.merge(headers))
1016
+ end
1017
+
1018
+ # Generate link to GET key data.
1019
+ #
1020
+ # bucket.get('logs/today/1.log', 1.hour)
1021
+ #
1022
+ def get(key, expires=nil, headers={})
1023
+ @s3.interface.get_link(@name, key.to_s, expires, headers)
1024
+ end
1025
+
1026
+ # Generate link to delete bucket.
1027
+ #
1028
+ # bucket.delete(2.hour)
1029
+ #
1030
+ def delete(expires=nil, headers={})
1031
+ @s3.interface.delete_bucket_link(@name, expires, headers)
1032
+ end
1033
+ end
1034
+
1035
+
1036
+ class Key
1037
+ attr_reader :bucket, :name
1038
+
1039
+ def to_s
1040
+ @name
1041
+ end
1042
+
1043
+ # Return a full S# name (bucket/key).
1044
+ #
1045
+ # key.full_name #=> 'my_awesome_bucket/cool_key'
1046
+ #
1047
+ def full_name(separator='/')
1048
+ "#{@bucket.to_s}#{separator}#{@name}"
1049
+ end
1050
+
1051
+ # Return a public link to key.
1052
+ #
1053
+ # key.public_link #=> 'https://s3.amazonaws.com:443/my_awesome_bucket/cool_key'
1054
+ #
1055
+ def public_link
1056
+ params = @bucket.s3.interface.params
1057
+ "#{params[:protocol]}://#{params[:server]}:#{params[:port]}/#{full_name('/')}"
1058
+ end
1059
+
1060
+ def initialize(bucket, name, meta_headers={})
1061
+ @bucket = bucket
1062
+ @name = name.to_s
1063
+ @meta_headers = meta_headers
1064
+ raise 'Key name can not be empty.' if @name.blank?
1065
+ end
1066
+
1067
+ # Generate link to PUT key data.
1068
+ #
1069
+ # puts bucket.put('logs/today/1.log', '123', 2.hour) #=> https://s3.amazonaws.com:443/my_awesome_bucket/logs%2Ftoday%2F1.log?Signature=B...D&Expires=1180820032&AWSAccessKeyId=1...2
1070
+ #
1071
+ def put(expires=nil, headers={})
1072
+ @bucket.put(@name.to_s, @meta_headers, expires, headers)
1073
+ end
1074
+
1075
+ # Generate link to GET key data.
1076
+ #
1077
+ # bucket.get('logs/today/1.log', 1.hour) #=> https://s3.amazonaws.com:443/my_awesome_bucket/logs%2Ftoday%2F1.log?Signature=h...M%3D&Expires=1180820032&AWSAccessKeyId=1...2
1078
+ #
1079
+ def get(expires=nil, headers={})
1080
+ @bucket.s3.interface.get_link(@bucket.to_s, @name, expires, headers)
1081
+ end
1082
+
1083
+ # Generate link to delete key.
1084
+ #
1085
+ # bucket.delete(2.hour) #=> https://s3.amazonaws.com:443/my_awesome_bucket/logs%2Ftoday%2F1.log?Signature=4...D&Expires=1180820032&AWSAccessKeyId=1...2
1086
+ #
1087
+ def delete(expires=nil, headers={})
1088
+ @bucket.s3.interface.delete_link(@bucket.to_s, @name, expires, headers)
1089
+ end
1090
+
1091
+ # Generate link to head key.
1092
+ #
1093
+ # bucket.head(2.hour) #=> https://s3.amazonaws.com:443/my_awesome_bucket/logs%2Ftoday%2F1.log?Signature=4...D&Expires=1180820032&AWSAccessKeyId=1...2
1094
+ #
1095
+ def head(expires=nil, headers={})
1096
+ @bucket.s3.interface.head_link(@bucket.to_s, @name, expires, headers)
1097
+ end
1098
+ end
1099
+ end
1100
+
1101
+ end