fog-aliyun 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +2 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +114 -0
- data/README.md +61 -3
- data/fog-aliyun.gemspec +9 -4
- data/lib/fog/aliyun/compute.rb +34 -10
- data/lib/fog/aliyun/models/compute/flavor.rb +28 -0
- data/lib/fog/aliyun/models/compute/flavors.rb +13 -0
- data/lib/fog/aliyun/models/compute/image.rb +3 -1
- data/lib/fog/aliyun/models/compute/server.rb +13 -1
- data/lib/fog/aliyun/models/compute/servers.rb +2 -1
- data/lib/fog/aliyun/models/compute/vpcs.rb +1 -1
- data/lib/fog/aliyun/models/storage/directories.rb +34 -17
- data/lib/fog/aliyun/models/storage/directory.rb +102 -14
- data/lib/fog/aliyun/models/storage/file.rb +130 -120
- data/lib/fog/aliyun/models/storage/files.rb +69 -128
- data/lib/fog/aliyun/requests/compute/allocate_eip_address.rb +1 -1
- data/lib/fog/aliyun/requests/compute/allocate_public_ip_address.rb +1 -1
- data/lib/fog/aliyun/requests/compute/associate_eip_address.rb +1 -1
- data/lib/fog/aliyun/requests/compute/attach_disk.rb +4 -2
- data/lib/fog/aliyun/requests/compute/create_disk.rb +2 -2
- data/lib/fog/aliyun/requests/compute/create_image.rb +1 -1
- data/lib/fog/aliyun/requests/compute/create_security_group.rb +1 -1
- data/lib/fog/aliyun/requests/compute/create_security_group_egress_ip_rule.rb +5 -3
- data/lib/fog/aliyun/requests/compute/create_security_group_egress_sg_rule.rb +4 -2
- data/lib/fog/aliyun/requests/compute/create_security_group_ip_rule.rb +5 -3
- data/lib/fog/aliyun/requests/compute/create_security_group_sg_rule.rb +4 -2
- data/lib/fog/aliyun/requests/compute/create_server.rb +23 -12
- data/lib/fog/aliyun/requests/compute/create_snapshot.rb +1 -1
- data/lib/fog/aliyun/requests/compute/create_vpc.rb +4 -2
- data/lib/fog/aliyun/requests/compute/create_vswitch.rb +4 -2
- data/lib/fog/aliyun/requests/compute/delete_disk.rb +1 -1
- data/lib/fog/aliyun/requests/compute/delete_image.rb +1 -1
- data/lib/fog/aliyun/requests/compute/delete_security_group.rb +1 -1
- data/lib/fog/aliyun/requests/compute/delete_security_group_egress_ip_rule.rb +5 -3
- data/lib/fog/aliyun/requests/compute/delete_security_group_egress_sg_rule.rb +4 -2
- data/lib/fog/aliyun/requests/compute/delete_security_group_ip_rule.rb +5 -3
- data/lib/fog/aliyun/requests/compute/delete_security_group_sg_rule.rb +4 -2
- data/lib/fog/aliyun/requests/compute/delete_server.rb +1 -1
- data/lib/fog/aliyun/requests/compute/delete_snapshot.rb +1 -1
- data/lib/fog/aliyun/requests/compute/delete_vpc.rb +1 -1
- data/lib/fog/aliyun/requests/compute/delete_vswitch.rb +1 -1
- data/lib/fog/aliyun/requests/compute/detach_disk.rb +4 -2
- data/lib/fog/aliyun/requests/compute/join_security_group.rb +1 -1
- data/lib/fog/aliyun/requests/compute/leave_security_group.rb +1 -1
- data/lib/fog/aliyun/requests/compute/list_disks.rb +1 -1
- data/lib/fog/aliyun/requests/compute/list_eip_addresses.rb +1 -1
- data/lib/fog/aliyun/requests/compute/list_images.rb +1 -1
- data/lib/fog/aliyun/requests/compute/list_route_tables.rb +1 -1
- data/lib/fog/aliyun/requests/compute/list_security_group_rules.rb +1 -1
- data/lib/fog/aliyun/requests/compute/list_security_groups.rb +1 -1
- data/lib/fog/aliyun/requests/compute/list_server_types.rb +3 -3
- data/lib/fog/aliyun/requests/compute/list_servers.rb +10 -10
- data/lib/fog/aliyun/requests/compute/list_snapshots.rb +1 -1
- data/lib/fog/aliyun/requests/compute/list_vpcs.rb +1 -1
- data/lib/fog/aliyun/requests/compute/list_vrouters.rb +1 -1
- data/lib/fog/aliyun/requests/compute/list_vswitchs.rb +1 -1
- data/lib/fog/aliyun/requests/compute/list_zones.rb +1 -1
- data/lib/fog/aliyun/requests/compute/modify_vpc.rb +4 -2
- data/lib/fog/aliyun/requests/compute/modify_vswitch.rb +4 -2
- data/lib/fog/aliyun/requests/compute/reboot_server.rb +1 -1
- data/lib/fog/aliyun/requests/compute/release_eip_address.rb +1 -1
- data/lib/fog/aliyun/requests/compute/start_server.rb +1 -1
- data/lib/fog/aliyun/requests/compute/stop_server.rb +1 -1
- data/lib/fog/aliyun/requests/compute/unassociate_eip_address.rb +1 -1
- data/lib/fog/aliyun/requests/storage/abort_multipart_upload.rb +22 -0
- data/lib/fog/aliyun/requests/storage/complete_multipart_upload.rb +21 -0
- data/lib/fog/aliyun/requests/storage/copy_object.rb +16 -23
- data/lib/fog/aliyun/requests/storage/delete_bucket.rb +5 -14
- data/lib/fog/aliyun/requests/storage/delete_multiple_objects.rb +20 -0
- data/lib/fog/aliyun/requests/storage/delete_object.rb +12 -35
- data/lib/fog/aliyun/requests/storage/get_bucket.rb +30 -110
- data/lib/fog/aliyun/requests/storage/get_bucket_location.rb +33 -0
- data/lib/fog/aliyun/requests/storage/get_object.rb +29 -24
- data/lib/fog/aliyun/requests/storage/get_object_acl.rb +30 -0
- data/lib/fog/aliyun/requests/storage/get_object_http_url.rb +14 -15
- data/lib/fog/aliyun/requests/storage/get_object_https_url.rb +14 -15
- data/lib/fog/aliyun/requests/storage/get_service.rb +13 -0
- data/lib/fog/aliyun/requests/storage/head_object.rb +27 -18
- data/lib/fog/aliyun/requests/storage/initiate_multipart_upload.rb +19 -0
- data/lib/fog/aliyun/requests/storage/list_buckets.rb +8 -26
- data/lib/fog/aliyun/requests/storage/list_objects.rb +14 -73
- data/lib/fog/aliyun/requests/storage/put_bucket.rb +4 -10
- data/lib/fog/aliyun/requests/storage/put_object.rb +18 -162
- data/lib/fog/aliyun/requests/storage/upload_part.rb +24 -0
- data/lib/fog/aliyun/storage.rb +57 -29
- data/lib/fog/aliyun/version.rb +1 -1
- data/lib/fog/aliyun.rb +6 -9
- data/lib/fog/bin/aliyun.rb +1 -1
- metadata +118 -47
- data/lib/fog/aliyun/requests/storage/delete_container.rb +0 -33
- data/lib/fog/aliyun/requests/storage/get_container.rb +0 -56
- data/lib/fog/aliyun/requests/storage/get_containers.rb +0 -60
- data/lib/fog/aliyun/requests/storage/put_container.rb +0 -32
@@ -4,46 +4,134 @@ require 'fog/core/model'
|
|
4
4
|
require 'fog/aliyun/models/storage/files'
|
5
5
|
|
6
6
|
module Fog
|
7
|
-
module
|
8
|
-
class
|
7
|
+
module Aliyun
|
8
|
+
class Storage
|
9
9
|
class Directory < Fog::Model
|
10
|
-
|
10
|
+
VALID_ACLS = ['private', 'public-read', 'public-read-write']
|
11
|
+
|
12
|
+
attr_reader :acl
|
13
|
+
identity :key, :aliases => ['Key', 'Name', 'name']
|
14
|
+
|
15
|
+
attribute :creation_date, :aliases => 'CreationDate', :type => 'time'
|
16
|
+
|
17
|
+
def acl=(new_acl)
|
18
|
+
unless VALID_ACLS.include?(new_acl)
|
19
|
+
raise ArgumentError.new("acl must be one of [#{VALID_ACLS.join(', ')}]")
|
20
|
+
else
|
21
|
+
@acl = new_acl
|
22
|
+
end
|
23
|
+
end
|
11
24
|
|
12
25
|
def destroy
|
13
26
|
requires :key
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
if
|
18
|
-
puts ' Not found: Direction not exist!'
|
27
|
+
service.delete_bucket(key)
|
28
|
+
true
|
29
|
+
rescue AliyunOssSdk::ServerError => error
|
30
|
+
if error.error_code == "NoSuchBucket"
|
19
31
|
false
|
20
|
-
elsif ret.size == 1
|
21
|
-
service.delete_container(key)
|
22
|
-
true
|
23
32
|
else
|
24
|
-
raise
|
33
|
+
raise(error)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def destroy!(options = {})
|
38
|
+
requires :key
|
39
|
+
options = {
|
40
|
+
timeout: Fog.timeout,
|
41
|
+
interval: Fog.interval,
|
42
|
+
}.merge(options)
|
43
|
+
|
44
|
+
begin
|
45
|
+
clear!
|
46
|
+
Fog.wait_for(options[:timeout], options[:interval]) { objects_keys.size == 0 }
|
47
|
+
service.delete_bucket(key)
|
48
|
+
true
|
49
|
+
rescue AliyunOssSdk::ServerError
|
25
50
|
false
|
26
51
|
end
|
27
52
|
end
|
28
53
|
|
54
|
+
def location
|
55
|
+
region = @aliyun_region_id
|
56
|
+
region ||= Storage::DEFAULT_REGION
|
57
|
+
@location = (bucket_location || 'oss-' + region)
|
58
|
+
end
|
59
|
+
|
60
|
+
# NOTE: you can't change the region once the bucket is created
|
61
|
+
def location=(new_location)
|
62
|
+
new_location = 'oss-' + new_location unless new_location.start_with?('oss-')
|
63
|
+
@location = new_location
|
64
|
+
end
|
65
|
+
|
29
66
|
def files
|
30
67
|
@files ||= begin
|
31
|
-
Fog::Storage::
|
68
|
+
Fog::Aliyun::Storage::Files.new(
|
32
69
|
directory: self,
|
33
70
|
service: service
|
34
71
|
)
|
35
72
|
end
|
36
73
|
end
|
37
74
|
|
75
|
+
# TODO
|
76
|
+
def public=(new_public)
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
|
80
|
+
# TODO
|
38
81
|
def public_url
|
39
82
|
nil
|
40
83
|
end
|
41
84
|
|
42
85
|
def save
|
43
86
|
requires :key
|
44
|
-
|
87
|
+
|
88
|
+
options = {}
|
89
|
+
|
90
|
+
options['x-oss-acl'] = acl if acl
|
91
|
+
|
92
|
+
# https://help.aliyun.com/document_detail/31959.html
|
93
|
+
# if !persisted?
|
94
|
+
# # There is a sdk bug that location can not be set
|
95
|
+
# options[:location] = location
|
96
|
+
# end
|
97
|
+
|
98
|
+
service.put_bucket(key, options)
|
99
|
+
attributes[:is_persisted] = true
|
100
|
+
|
45
101
|
true
|
46
102
|
end
|
103
|
+
|
104
|
+
def persisted?
|
105
|
+
# is_persisted is true in case of directories.get or after #save
|
106
|
+
# creation_date is set in case of directories.all
|
107
|
+
attributes[:is_persisted] || !!attributes[:creation_date]
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def bucket_location
|
113
|
+
requires :key
|
114
|
+
return nil unless persisted?
|
115
|
+
service.get_bucket_location(key)
|
116
|
+
end
|
117
|
+
|
118
|
+
def objects_keys
|
119
|
+
requires :key
|
120
|
+
bucket_query = service.get_bucket(key)
|
121
|
+
|
122
|
+
object_keys = []
|
123
|
+
i = 0
|
124
|
+
bucket_query[0].each do |o|
|
125
|
+
object_keys[i] = o.key
|
126
|
+
i += 1
|
127
|
+
end
|
128
|
+
object_keys
|
129
|
+
end
|
130
|
+
|
131
|
+
def clear!
|
132
|
+
requires :key
|
133
|
+
service.delete_multiple_objects(key, objects_keys) if objects_keys.size > 0
|
134
|
+
end
|
47
135
|
end
|
48
136
|
end
|
49
137
|
end
|
@@ -3,78 +3,127 @@
|
|
3
3
|
require 'fog/core/model'
|
4
4
|
|
5
5
|
module Fog
|
6
|
-
module
|
7
|
-
class
|
6
|
+
module Aliyun
|
7
|
+
class Storage
|
8
8
|
class File < Fog::Model
|
9
|
-
identity :key, aliases: 'name'
|
9
|
+
identity :key, aliases: ['Key', 'Name', 'name']
|
10
|
+
|
11
|
+
attr_writer :body
|
12
|
+
attribute :cache_control, aliases: 'Cache-Control'
|
13
|
+
attribute :content_encoding, aliases: 'Content-Encoding'
|
10
14
|
attribute :date, aliases: 'Date'
|
11
|
-
attribute :content_length, aliases: 'Content-Length', type: :integer
|
15
|
+
attribute :content_length, aliases: ['Content-Length', 'Size'], type: :integer
|
16
|
+
attribute :content_md5, aliases: 'Content-MD5'
|
12
17
|
attribute :content_type, aliases: 'Content-Type'
|
13
18
|
attribute :connection, aliases: 'Connection'
|
14
19
|
attribute :content_disposition, aliases: 'Content-Disposition'
|
15
|
-
attribute :etag, aliases: 'Etag'
|
20
|
+
attribute :etag, aliases: ['Etag', 'ETag']
|
21
|
+
attribute :expires, aliases: 'Expires'
|
22
|
+
attribute :metadata
|
23
|
+
attribute :owner, aliases: 'Owner'
|
16
24
|
attribute :last_modified, aliases: 'Last-Modified', type: :time
|
17
25
|
attribute :accept_ranges, aliases: 'Accept-Ranges'
|
18
26
|
attribute :server, aliases: 'Server'
|
19
|
-
attribute :object_type, aliases: 'x-oss-object-type'
|
27
|
+
attribute :object_type, aliases: ['x-oss-object-type', 'x_oss_object_type']
|
28
|
+
|
29
|
+
# @note Chunk size to use for multipart uploads.
|
30
|
+
# Use small chunk sizes to minimize memory. E.g. 5242880 = 5mb
|
31
|
+
attr_reader :multipart_chunk_size
|
32
|
+
def multipart_chunk_size=(mp_chunk_size)
|
33
|
+
raise ArgumentError.new("minimum multipart_chunk_size is 5242880") if mp_chunk_size < 5242880
|
34
|
+
@multipart_chunk_size = mp_chunk_size
|
35
|
+
end
|
36
|
+
|
37
|
+
def acl
|
38
|
+
requires :directory, :key
|
39
|
+
service.get_object_acl(directory.key, key)
|
40
|
+
end
|
41
|
+
|
42
|
+
def acl=(new_acl)
|
43
|
+
valid_acls = ['private', 'public-read', 'public-read-write', 'default']
|
44
|
+
unless valid_acls.include?(new_acl)
|
45
|
+
raise ArgumentError.new("acl must be one of [#{valid_acls.join(', ')}]")
|
46
|
+
end
|
47
|
+
@acl = new_acl
|
48
|
+
end
|
20
49
|
|
21
50
|
def body
|
22
|
-
attributes[:body]
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
51
|
+
return attributes[:body] if attributes[:body]
|
52
|
+
return '' unless last_modified
|
53
|
+
|
54
|
+
file = collection.get(identity)
|
55
|
+
if file
|
56
|
+
attributes[:body] = file.body
|
57
|
+
else
|
58
|
+
attributes[:body] = ''
|
59
|
+
end
|
28
60
|
end
|
29
61
|
|
30
62
|
def body=(new_body)
|
31
63
|
attributes[:body] = new_body
|
32
64
|
end
|
33
65
|
|
34
|
-
|
66
|
+
def directory
|
67
|
+
@directory
|
68
|
+
end
|
35
69
|
|
70
|
+
# Copy object from one bucket to other bucket.
|
71
|
+
#
|
72
|
+
# required attributes: directory, key
|
73
|
+
#
|
74
|
+
# @param target_directory_key [String]
|
75
|
+
# @param target_file_key [String]
|
76
|
+
# @param options [Hash] options for copy_object method
|
77
|
+
# @return [String] Fog::Aliyun::Files#head status of directory contents
|
78
|
+
#
|
36
79
|
def copy(target_directory_key, target_file_key, options = {})
|
37
80
|
requires :directory, :key
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
target_file_key
|
45
|
-
else
|
46
|
-
target_directory_key + '/' + target_file_key
|
47
|
-
end
|
48
|
-
service.copy_object(nil, source_object, nil, target_object, options)
|
49
|
-
target_directory = service.directories.new(key: target_directory_key)
|
50
|
-
target_directory.files.get(target_file_key)
|
51
|
-
end
|
52
|
-
|
53
|
-
def destroy
|
81
|
+
service.copy_object(directory.key, key, target_directory_key, target_file_key, options)
|
82
|
+
target_directory = service.directories.new(:key => target_directory_key)
|
83
|
+
target_directory.files.head(target_file_key)
|
84
|
+
end
|
85
|
+
|
86
|
+
def destroy(options = {})
|
54
87
|
requires :directory, :key
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
directory.key + '/' + key
|
59
|
-
end
|
60
|
-
service.delete_object(object)
|
88
|
+
# TODO support versionId
|
89
|
+
# attributes[:body] = nil if options['versionId'] == version
|
90
|
+
service.delete_object(directory.key, key, options)
|
61
91
|
true
|
62
92
|
end
|
63
93
|
|
94
|
+
remove_method :metadata
|
64
95
|
def metadata
|
65
|
-
attributes
|
96
|
+
attributes.reject {|key, value| !(key.to_s =~ /^x-oss-/)}
|
97
|
+
end
|
98
|
+
|
99
|
+
remove_method :metadata=
|
100
|
+
def metadata=(new_metadata)
|
101
|
+
merge_attributes(new_metadata)
|
66
102
|
end
|
67
103
|
|
104
|
+
remove_method :owner=
|
68
105
|
def owner=(new_owner)
|
69
106
|
if new_owner
|
70
107
|
attributes[:owner] = {
|
71
|
-
|
72
|
-
|
108
|
+
:display_name => new_owner['DisplayName'] || new_owner[:display_name],
|
109
|
+
:id => new_owner['ID'] || new_owner[:id]
|
73
110
|
}
|
74
111
|
end
|
75
112
|
end
|
76
113
|
|
114
|
+
# Set Access-Control-List permissions.
|
115
|
+
#
|
116
|
+
# valid new_publics: public_read, private
|
117
|
+
#
|
118
|
+
# @param [String] new_public
|
119
|
+
# @return [String] new_public
|
120
|
+
#
|
77
121
|
def public=(new_public)
|
122
|
+
if new_public
|
123
|
+
@acl = 'public-read'
|
124
|
+
else
|
125
|
+
@acl = 'private'
|
126
|
+
end
|
78
127
|
new_public
|
79
128
|
end
|
80
129
|
|
@@ -83,48 +132,32 @@ module Fog
|
|
83
132
|
# required attributes: directory, key
|
84
133
|
#
|
85
134
|
# @param expires [String] number of seconds (since 1970-01-01 00:00) before url expires
|
86
|
-
# @param options
|
135
|
+
# @param options[Hash] No need to use
|
87
136
|
# @return [String] url
|
88
137
|
#
|
89
138
|
def url(expires, options = {})
|
90
|
-
|
91
|
-
expires = expires.nil? ? 0 : expires.to_i
|
92
|
-
|
93
|
-
requires :directory, :key
|
94
|
-
object = if directory.key == ''
|
95
|
-
key
|
96
|
-
else
|
97
|
-
directory.key + '/' + key
|
98
|
-
end
|
99
|
-
service.get_object_http_url_public(object, expires, options)
|
100
|
-
end
|
101
|
-
|
102
|
-
def public_url
|
103
139
|
requires :key
|
104
|
-
|
140
|
+
service.get_object_http_url_public(directory.key, key, expires)
|
105
141
|
end
|
106
142
|
|
107
143
|
def save(options = {})
|
108
144
|
requires :body, :directory, :key
|
109
|
-
options['
|
145
|
+
options['x-oss-object-acl'] ||= @acl if @acl
|
146
|
+
options['Cache-Control'] = cache_control if cache_control
|
110
147
|
options['Content-Disposition'] = content_disposition if content_disposition
|
111
|
-
options
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
if body.
|
119
|
-
|
120
|
-
elsif body.is_a?(String)
|
121
|
-
data = service.put_object_with_body(object, body, options).data
|
148
|
+
options['Content-Encoding'] = content_encoding if content_encoding
|
149
|
+
options['Content-MD5'] = content_md5 if content_md5
|
150
|
+
options['Content-Type'] = content_type if content_type
|
151
|
+
options['Expires'] = expires if expires
|
152
|
+
options.merge!(metadata)
|
153
|
+
|
154
|
+
self.multipart_chunk_size = 5242880 if !multipart_chunk_size && Fog::Storage.get_body_size(body) > 5368709120
|
155
|
+
if multipart_chunk_size && Fog::Storage.get_body_size(body) >= multipart_chunk_size && body.respond_to?(:read)
|
156
|
+
multipart_save(options)
|
122
157
|
else
|
123
|
-
|
158
|
+
service.put_object(directory.key, key, body, options)
|
124
159
|
end
|
125
|
-
|
126
|
-
refresh_metadata
|
127
|
-
|
160
|
+
self.etag = self.etag.gsub('"','') if self.etag
|
128
161
|
self.content_length = Fog::Storage.get_body_size(body)
|
129
162
|
self.content_type ||= Fog::Storage.get_content_type(body)
|
130
163
|
true
|
@@ -132,66 +165,43 @@ module Fog
|
|
132
165
|
|
133
166
|
private
|
134
167
|
|
135
|
-
|
136
|
-
|
137
|
-
def refresh_metadata
|
138
|
-
metadata.reject! { |_k, v| v.nil? }
|
139
|
-
end
|
140
|
-
|
141
|
-
def headers_to_metadata
|
142
|
-
key_map = key_mapping
|
143
|
-
Hash[metadata_attributes.map { |k, v| [key_map[k], v] }]
|
144
|
-
end
|
145
|
-
|
146
|
-
def key_mapping
|
147
|
-
key_map = metadata_attributes
|
148
|
-
key_map.each_pair { |k, _v| key_map[k] = header_to_key(k) }
|
168
|
+
def directory=(new_directory)
|
169
|
+
@directory = new_directory
|
149
170
|
end
|
150
171
|
|
151
|
-
def
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
def metadata_to_headers
|
156
|
-
header_map = header_mapping
|
157
|
-
Hash[metadata.map { |k, v| [header_map[k], v] }]
|
158
|
-
end
|
159
|
-
|
160
|
-
def header_mapping
|
161
|
-
header_map = metadata.dup
|
162
|
-
header_map.each_pair { |k, _v| header_map[k] = key_to_header(k) }
|
163
|
-
end
|
164
|
-
|
165
|
-
def key_to_header(key)
|
166
|
-
metadata_prefix + key.to_s.split(/[-_]/).map(&:capitalize).join('-')
|
167
|
-
end
|
172
|
+
def multipart_save(options)
|
173
|
+
# Initiate the upload
|
174
|
+
upload_id = service.initiate_multipart_upload(directory.key, key, options)
|
168
175
|
|
169
|
-
|
170
|
-
|
171
|
-
object = if directory.key == ''
|
172
|
-
key
|
173
|
-
else
|
174
|
-
directory.key + '/' + key
|
175
|
-
end
|
176
|
+
# Store ETags of upload parts
|
177
|
+
part_tags = []
|
176
178
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
179
|
+
# Upload each part
|
180
|
+
# TODO: optionally upload chunks in parallel using threads
|
181
|
+
# (may cause network performance problems with many small chunks)
|
182
|
+
# TODO: Support large chunk sizes without reading the chunk into memory
|
183
|
+
if body.respond_to?(:rewind)
|
184
|
+
body.rewind rescue nil
|
185
|
+
end
|
186
|
+
while (chunk = body.read(multipart_chunk_size)) do
|
187
|
+
part_upload = service.upload_part(directory.key, key, upload_id, part_tags.size + 1, chunk)
|
188
|
+
part_tags << part_upload
|
181
189
|
end
|
182
|
-
end
|
183
190
|
|
184
|
-
|
185
|
-
|
186
|
-
|
191
|
+
if part_tags.empty? #it is an error to have a multipart upload with no parts
|
192
|
+
part_upload = service.upload_part(directory.key, key, upload_id, 1, '')
|
193
|
+
part_tags << part_upload
|
194
|
+
end
|
187
195
|
|
188
|
-
|
189
|
-
|
196
|
+
rescue
|
197
|
+
# Abort the upload & reraise
|
198
|
+
service.abort_multipart_upload(directory.key, key, upload_id) if upload_id
|
199
|
+
raise
|
200
|
+
else
|
201
|
+
# Complete the upload
|
202
|
+
service.complete_multipart_upload(directory.key, key, upload_id, part_tags)
|
190
203
|
end
|
191
204
|
|
192
|
-
def update_attributes_from(data)
|
193
|
-
merge_attributes(data[:headers].reject { |key, _value| ['Content-Length', 'Content-Type'].include?(key) })
|
194
|
-
end
|
195
205
|
end
|
196
206
|
end
|
197
207
|
end
|