fog-aliyun 0.3.13 → 0.3.19

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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +109 -0
  3. data/Gemfile +0 -1
  4. data/fog-aliyun.gemspec +2 -0
  5. data/lib/fog/aliyun/models/storage/directories.rb +30 -53
  6. data/lib/fog/aliyun/models/storage/directory.rb +96 -17
  7. data/lib/fog/aliyun/models/storage/file.rb +127 -125
  8. data/lib/fog/aliyun/models/storage/files.rb +62 -156
  9. data/lib/fog/aliyun/requests/storage/abort_multipart_upload.rb +22 -0
  10. data/lib/fog/aliyun/requests/storage/complete_multipart_upload.rb +21 -0
  11. data/lib/fog/aliyun/requests/storage/copy_object.rb +14 -19
  12. data/lib/fog/aliyun/requests/storage/delete_bucket.rb +3 -10
  13. data/lib/fog/aliyun/requests/storage/delete_multiple_objects.rb +20 -0
  14. data/lib/fog/aliyun/requests/storage/delete_object.rb +10 -11
  15. data/lib/fog/aliyun/requests/storage/get_bucket.rb +26 -125
  16. data/lib/fog/aliyun/requests/storage/get_bucket_location.rb +33 -0
  17. data/lib/fog/aliyun/requests/storage/get_object.rb +29 -11
  18. data/lib/fog/aliyun/requests/storage/get_object_acl.rb +30 -0
  19. data/lib/fog/aliyun/requests/storage/get_object_http_url.rb +8 -11
  20. data/lib/fog/aliyun/requests/storage/get_object_https_url.rb +8 -11
  21. data/lib/fog/aliyun/requests/storage/get_service.rb +13 -0
  22. data/lib/fog/aliyun/requests/storage/head_object.rb +25 -14
  23. data/lib/fog/aliyun/requests/storage/initiate_multipart_upload.rb +19 -0
  24. data/lib/fog/aliyun/requests/storage/list_buckets.rb +6 -24
  25. data/lib/fog/aliyun/requests/storage/list_objects.rb +10 -67
  26. data/lib/fog/aliyun/requests/storage/put_bucket.rb +2 -8
  27. data/lib/fog/aliyun/requests/storage/put_object.rb +16 -142
  28. data/lib/fog/aliyun/requests/storage/upload_part.rb +24 -0
  29. data/lib/fog/aliyun/storage.rb +41 -27
  30. data/lib/fog/aliyun/version.rb +1 -1
  31. metadata +39 -6
  32. data/lib/fog/aliyun/requests/storage/delete_container.rb +0 -31
  33. data/lib/fog/aliyun/requests/storage/get_container.rb +0 -56
  34. data/lib/fog/aliyun/requests/storage/get_containers.rb +0 -65
  35. data/lib/fog/aliyun/requests/storage/put_container.rb +0 -30
@@ -0,0 +1,33 @@
1
+ require 'nokogiri'
2
+ module Fog
3
+ module Aliyun
4
+ class Storage
5
+ class Real
6
+
7
+ # Get location constraint for an OSS bucket
8
+ #
9
+ # @param bucket_name [String] name of bucket to get location constraint for
10
+ #
11
+ # @see https://help.aliyun.com/document_detail/31967.html
12
+ #
13
+ # note: The OSS Ruby sdk does not support get_bucket_location and there needs to parse response
14
+
15
+ def get_bucket_location(bucket_name)
16
+ data = @oss_http.get({:bucket => bucket_name, :sub_res => { 'location' => nil} }, {})
17
+ doc = parse_xml(data.body)
18
+ doc.at_css("LocationConstraint").text
19
+ end
20
+
21
+ private
22
+
23
+ def parse_xml(content)
24
+ doc = Nokogiri::XML(content) do |config|
25
+ config.options |= Nokogiri::XML::ParseOptions::NOBLANKS
26
+ end
27
+
28
+ doc
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -7,21 +7,39 @@ module Fog
7
7
  # Get details for object
8
8
  #
9
9
  # ==== Parameters
10
- # * object<~String> - Name of object to look for
10
+ # * object_name<~String> - Name of object to look for
11
11
  #
12
- def get_object(object, range = nil, options = {})
12
+ def get_object(bucket_name, object_name, options = {}, &block)
13
13
  options = options.reject { |_key, value| value.nil? }
14
- bucket_name = options[:bucket]
15
- bucket_name ||= @aliyun_oss_bucket
14
+ unless bucket_name
15
+ raise ArgumentError.new('bucket_name is required')
16
+ end
17
+ unless object_name
18
+ raise ArgumentError.new('object_name is required')
19
+ end
16
20
  # Using OSS ruby SDK to fix performance issue
17
- bucket = @oss_client.get_bucket(bucket_name)
18
- body = Array.new
19
- obj = bucket.get_object(object) do |chunk|
20
- body << chunk
21
+ http_options = { :headers => {} }
22
+ http_options[:query] = options.delete('query') || {}
23
+
24
+ http_options[:headers].merge!(options)
25
+ if options['If-Modified-Since']
26
+ http_options[:headers]['If-Modified-Since'] = Fog::Time.at(options['If-Modified-Since'].to_i).to_date_header
21
27
  end
22
- response = {}
23
- obj.instance_variables.each {|var| response[var.to_s.delete("@")] = obj.instance_variable_get(var) }
24
- response.merge({:body => body.join('')})
28
+ if options['If-Unmodified-Since']
29
+ http_options[:headers]['If-Unmodified-Since'] = Fog::Time.at(options['If-Unmodified-Since'].to_i).to_date_header
30
+ end
31
+
32
+ if block_given?
33
+ http_options[:response_block] = Proc.new
34
+ end
35
+
36
+ resources = {
37
+ :bucket => bucket_name,
38
+ :object => object_name
39
+ }
40
+
41
+ @oss_http.get(resources, http_options, &block)
42
+
25
43
  end
26
44
  end
27
45
  end
@@ -0,0 +1,30 @@
1
+ module Fog
2
+ module Aliyun
3
+ class Storage
4
+ class Real
5
+
6
+ # Get access control list for an S3 object
7
+ #
8
+ # @param bucket_name [String] name of bucket containing object
9
+ # @param object_name [String] name of object to get access control list for
10
+ # @param options [Hash]
11
+ # @option options versionId [String] specify a particular version to retrieve
12
+
13
+ def get_object_acl(bucket_name, object_name, options = {})
14
+ unless bucket_name
15
+ raise ArgumentError.new('bucket_name is required')
16
+ end
17
+ unless object_name
18
+ raise ArgumentError.new('object_name is required')
19
+ end
20
+
21
+ # At present, sdk does not support versionId
22
+ # if version_id = options.delete('versionId')
23
+ # query['versionId'] = version_id
24
+ # end
25
+ @oss_protocol.get_object_acl(bucket_name, object_name)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -7,29 +7,26 @@ module Fog
7
7
  # Get an expiring object http url
8
8
  #
9
9
  # ==== Parameters
10
- # * container<~String> - Name of container containing object
11
- # * object<~String> - Name of object to get expiring url for
10
+ # * bucket_name<~String> - Name of bucket
11
+ # * object_name<~String> - Name of object to get expiring url for
12
12
  # * expires<~Integer> - An expiry time for this url
13
13
  #
14
14
  # ==== Returns
15
15
  # * response<~Excon::Response>:
16
16
  # * body<~String> - url for object
17
- def get_object_http_url_public(object, expires, options = {})
18
- options = options.reject { |_key, value| value.nil? }
19
- bucket = options[:bucket]
20
- bucket ||= @aliyun_oss_bucket
21
- acl = get_bucket_acl(bucket)
22
- location = get_bucket_location(bucket)
17
+ def get_object_http_url_public(bucket_name, object_name, expires)
18
+ bucket = @oss_client.get_bucket(bucket_name)
19
+ acl = bucket.acl()
23
20
 
24
21
  if acl == 'private'
25
22
  expires_time = (Time.now.to_i + (expires.nil? ? 0 : expires.to_i)).to_s
26
- resource = bucket + '/' + object
23
+ resource = bucket_name + '/' + object_name
27
24
  signature = sign('GET', expires_time, nil, resource)
28
- 'http://' + bucket + '.' + location + '.aliyuncs.com/' + object +
25
+ 'http://' + bucket_name + '.' + @host + '/' + object_name +
29
26
  '?OSSAccessKeyId=' + @aliyun_accesskey_id + '&Expires=' + expires_time +
30
27
  '&Signature=' + URI.encode(signature, '/[^!*\'()\;?:@#&%=+$,{}[]<>`" ')
31
28
  elsif acl == 'public-read' || acl == 'public-read-write'
32
- 'http://' + bucket + '.' + location + '.aliyuncs.com/' + object
29
+ 'http://' + bucket_name + '.' + @host + '/' + object_name
33
30
  else
34
31
  'acl is wrong with value:' + acl
35
32
  end
@@ -7,29 +7,26 @@ module Fog
7
7
  # Get an expiring object https url from Cloud Files
8
8
  #
9
9
  # ==== Parameters
10
- # * container<~String> - Name of container containing object
11
- # * object<~String> - Name of object to get expiring url for
10
+ # * bucket_name<~String> - Name of bucket
11
+ # * object_name<~String> - Name of object to get expiring url for
12
12
  # * expires<~Integer> - An expiry time for this url
13
13
  #
14
14
  # ==== Returns
15
15
  # * response<~Excon::Response>:
16
16
  # * body<~String> - url for object
17
- def get_object_https_url_public(object, expires, options = {})
18
- options = options.reject { |_key, value| value.nil? }
19
- bucket = options[:bucket]
20
- bucket ||= @aliyun_oss_bucket
21
- acl = get_bucket_acl(bucket)
22
- location = get_bucket_location(bucket)
17
+ def get_object_https_url_public(bucket_name, object_name, expires)
18
+ bucket = @oss_client.get_bucket(bucket_name)
19
+ acl = bucket.acl()
23
20
 
24
21
  if acl == 'private'
25
22
  expires_time = (Time.now.to_i + (expires.nil? ? 0 : expires.to_i)).to_s
26
- resource = bucket + '/' + object
23
+ resource = bucket_name + '/' + object_name
27
24
  signature = sign('GET', expires_time, nil, resource)
28
- 'https://' + bucket + '.' + location + '.aliyuncs.com/' + object +
25
+ 'https://' + bucket_name + '.' + @host + '/' + object_name +
29
26
  '?OSSAccessKeyId=' + @aliyun_accesskey_id + '&Expires=' + expires_time +
30
27
  '&Signature=' + URI.encode(signature, '/[^!*\'()\;?:@#&%=+$,{}[]<>`" ')
31
28
  elsif acl == 'public-read' || acl == 'public-read-write'
32
- 'https://' + bucket + '.' + location + '.aliyuncs.com/' + object
29
+ 'https://' + bucket_name + '.' + @host + '/' + object_name
33
30
  else
34
31
  'acl is wrong with value:' + acl
35
32
  end
@@ -0,0 +1,13 @@
1
+ module Fog
2
+ module Aliyun
3
+ class Storage
4
+ class Real
5
+ # List information about OSS buckets for authorized user
6
+ #
7
+ def get_service
8
+ @oss_protocol.list_buckets
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -7,21 +7,32 @@ module Fog
7
7
  # Get headers for object
8
8
  #
9
9
  # ==== Parameters
10
- # * object<~String> - Name of object to look for
10
+ # * object_name<~String> - Name of object to look for
11
11
  #
12
- def head_object(object, options = {})
13
- bucket = options[:bucket]
14
- bucket ||= @aliyun_oss_bucket
15
- resource = bucket + '/' + object
16
- ret = request(
17
- expects: [200, 404],
18
- method: 'HEAD',
19
- path: object,
20
- bucket: bucket,
21
- resource: resource,
22
- location: get_bucket_location(bucket)
23
- )
24
- ret
12
+ def head_object(bucket_name, object_name, options={})
13
+ unless bucket_name
14
+ raise ArgumentError.new('bucket_name is required')
15
+ end
16
+ unless object_name
17
+ raise ArgumentError.new('object_name is required')
18
+ end
19
+
20
+ # Currently, the ruby sdk does not support versionId
21
+ # if version_id = options.delete('versionId')
22
+ # query = {'versionId' => version_id}
23
+ # end
24
+ headers = {}
25
+ headers['If-Modified-Since'] = Fog::Time.at(options['If-Modified-Since'].to_i).to_date_header if options['If-Modified-Since']
26
+ headers['If-Unmodified-Since'] = Fog::Time.at(options['If-Unmodified-Since'].to_i).to_date_header if options['If-Modified-Since']
27
+ headers.merge!(options)
28
+ resources = {
29
+ :bucket => bucket_name,
30
+ :object => object_name
31
+ }
32
+ http_options = {
33
+ :headers => headers
34
+ }
35
+ @oss_http.head(resources, http_options)
25
36
  end
26
37
  end
27
38
  end
@@ -0,0 +1,19 @@
1
+ module Fog
2
+ module Aliyun
3
+ class Storage
4
+ class Real
5
+ # Initiate a multipart upload
6
+ #
7
+ # @param bucket_name [String] Name of bucket to create
8
+ # @param object_name [String] Name of object to create
9
+ # @param options [Hash]
10
+ #
11
+ # @see https://help.aliyun.com/document_detail/31992.html
12
+ #
13
+ def initiate_multipart_upload(bucket_name, object_name, options = {})
14
+ @oss_protocol.initiate_multipart_upload(bucket_name, object_name, options)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -5,31 +5,13 @@ module Fog
5
5
  class Storage
6
6
  class Real
7
7
  def list_buckets(options = {})
8
- prefix = options[:prefix]
9
- marker = options[:marker]
10
- maxKeys = options[:maxKeys]
8
+ maxKeys = options[:max_keys] || 1000
9
+ maxKeys = maxKeys.to_i
10
+ maxKeys = [maxKeys, 1000].min
11
11
 
12
- path = ''
13
- if prefix
14
- path += '?prefix=' + prefix
15
- path += '&marker=' + marker if marker
16
- path += '&max-keys=' + maxKeys if maxKeys
17
-
18
- elsif marker
19
- path += '?marker=' + marker
20
- path += '&max-keys=' + maxKeys if maxKeys
21
-
22
- elsif maxKeys
23
- path += '?max-keys=' + maxKeys
24
- end
25
-
26
- ret = request(
27
- expects: [200, 203],
28
- method: 'GET',
29
- path: path
30
- )
31
- xml = ret.data[:body]
32
- XmlSimple.xml_in(xml)['Buckets'][0]
12
+ options[:limit] = maxKeys
13
+ options.delete(:max_keys)
14
+ @oss_protocol.list_buckets(options)
33
15
  end
34
16
  end
35
17
  end
@@ -4,79 +4,22 @@ module Fog
4
4
  module Aliyun
5
5
  class Storage
6
6
  class Real
7
- def list_objects(options = {})
8
- bucket = options['bucket']
9
- bucket ||= @aliyun_oss_bucket
10
- prefix = options['prefix']
11
- marker = options['marker']
12
- # Set the ListObjects max limitation to 1000
13
- maxKeys = options['max-keys'] || 1000
7
+ def list_objects(bucket_name, options = {})
8
+ maxKeys = options[:max_keys] || 1000
9
+ maxKeys = maxKeys.to_i
14
10
  maxKeys = [maxKeys, 1000].min
15
- delimiter = options['delimiter']
16
11
 
17
- path = ''
18
- if prefix
19
- path += '/?prefix=' + prefix
20
- path += '&marker=' + marker if marker
21
- path += '&max-keys=' + maxKeys.to_s if maxKeys
22
- path += '&delimiter=' + delimiter if delimiter
23
-
24
- elsif marker
25
- path += '/?marker=' + marker
26
- path += '&max-keys=' + maxKeys.to_s if maxKeys
27
- path += '&delimiter=' + delimiter if delimiter
28
-
29
- elsif maxKeys
30
- path += '/?max-keys=' + maxKeys.to_s
31
- path += '&delimiter=' + delimiter if delimiter
32
- elsif delimiter
33
- path += '/?delimiter=' + delimiter
34
- end
35
-
36
- resource = bucket + '/'
37
- ret = request(
38
- expects: [200, 203, 400],
39
- method: 'GET',
40
- path: path,
41
- resource: resource,
42
- bucket: bucket
43
- )
44
- xml = ret.data[:body]
45
- XmlSimple.xml_in(xml)
12
+ options[:limit] = maxKeys
13
+ options.delete(:max_keys)
14
+ @oss_protocol.list_objects(bucket_name, options)
46
15
  end
47
16
 
48
- def list_multipart_uploads(bucket, location, _options = {})
49
- location ||= get_bucket_location(bucket)
50
-
51
- path = '?uploads'
52
- resource = bucket + '/' + path
53
-
54
- ret = request(
55
- expects: 200,
56
- method: 'GET',
57
- path: path,
58
- bucket: bucket,
59
- resource: resource,
60
- location: location
61
- )
62
- XmlSimple.xml_in(ret.data[:body])['Upload']
17
+ def list_multipart_uploads(bucket_name, _options = {})
18
+ @oss_protocol.list_multipart_uploads(bucket_name, _options)
63
19
  end
64
20
 
65
- def list_parts(bucket, object, location, uploadid, _options = {})
66
- location ||= get_bucket_location(bucket)
67
-
68
- path = object + '?uploadId=' + uploadid
69
- resource = bucket + '/' + path
70
-
71
- ret = request(
72
- expects: 200,
73
- method: 'GET',
74
- path: path,
75
- bucket: bucket,
76
- resource: resource,
77
- location: location
78
- )
79
- XmlSimple.xml_in(ret.data[:body])['Part']
21
+ def list_parts(bucket_name, object_name, upload_id, _options = {})
22
+ @oss_protocol.list_parts(bucket_name, object_name, upload_id, _options)
80
23
  end
81
24
  end
82
25
  end
@@ -4,14 +4,8 @@ module Fog
4
4
  module Aliyun
5
5
  class Storage
6
6
  class Real
7
- def put_bucket(bucketName)
8
- resource = bucketName + '/'
9
- request(
10
- expects: [200, 203],
11
- method: 'PUT',
12
- resource: resource,
13
- bucket: bucketName
14
- )
7
+ def put_bucket(bucket_name, options = {})
8
+ @oss_protocol.create_bucket(bucket_name, options)
15
9
  end
16
10
  end
17
11
  end
@@ -7,153 +7,27 @@ module Fog
7
7
  # Put details for object
8
8
  #
9
9
  # ==== Parameters
10
- # * object<~String> - Name of object to look for
10
+ # * bucket_name<~String> - Name of bucket to look for
11
+ # * object_name<~String> - Object of object to look for
12
+ # * data<~File>
13
+ # * options<~Hash>
11
14
  #
12
- def put_object(object, file = nil, options = {})
13
- bucket = options[:bucket]
14
- bucket ||= @aliyun_oss_bucket
15
- return put_folder(bucket, object) if file.nil?
16
-
17
- # put multiparts if object's size is over 100m
18
- return put_multipart_object(bucket, object, file) if file.size > 104_857_600
19
-
20
- body = file.read
21
-
22
- resource = bucket + '/' + object
23
- request(
24
- expects: [200, 203],
25
- method: 'PUT',
26
- path: object,
27
- bucket: bucket,
28
- resource: resource,
29
- body: body,
30
- location: get_bucket_location(bucket)
31
- )
32
- end
33
-
34
- def put_object_with_body(object, body, options = {})
35
- bucket = options[:bucket]
36
- bucket ||= @aliyun_oss_bucket
37
-
38
- resource = bucket + '/' + object
39
- request(
40
- expects: [200, 203],
41
- method: 'PUT',
42
- path: object,
43
- bucket: bucket,
44
- resource: resource,
45
- body: body,
46
- location: get_bucket_location(bucket)
47
- )
48
- end
49
-
50
- def put_folder(bucket, folder)
51
- path = folder + '/'
52
- resource = bucket + '/' + folder + '/'
53
- request(
54
- expects: [200, 203],
55
- method: 'PUT',
56
- path: path,
57
- bucket: bucket,
58
- resource: resource,
59
- location: get_bucket_location(bucket)
60
- )
61
- end
62
-
63
- def put_multipart_object(bucket, object, file)
64
- location = get_bucket_location(bucket)
65
-
66
- # find the right uploadid
67
- uploads = list_multipart_uploads(bucket, location)
68
- upload = (uploads&.find { |tmpupload| tmpupload['Key'][0] == object })
69
-
70
- uploadedSize = 0
71
- start_partNumber = 1
72
- if !upload.nil?
73
- uploadId = upload['UploadId'][0]
74
- parts = list_parts(bucket, object, location, uploadId)
75
- if !parts.nil? && !parts.empty?
76
- if parts[-1]['Size'][0].to_i != 5_242_880
77
- # the part is the last one, if its size is over 5m, then finish this upload
78
- complete_multipart_upload(bucket, object, location, uploadId)
79
- return
15
+ def put_object(bucket_name, object_name, data, options = {})
16
+ if data.is_a? ::File
17
+ @oss_protocol.put_object(bucket_name, object_name, options)do |sw|
18
+ while line = data.read(16*1024)
19
+ sw.write(line)
80
20
  end
81
- uploadedSize = (parts[0]['Size'][0].to_i * (parts.size - 1)) + parts[-1]['Size'][0].to_i
82
- start_partNumber = parts[-1]['PartNumber'][0].to_i + 1
83
21
  end
84
22
  else
85
- # create upload ID
86
- uploadId = initiate_multipart_upload(bucket, object, location)
87
- end
88
-
89
- if file.size <= uploadedSize
90
- complete_multipart_upload(bucket, object, location, uploadId)
91
- return
92
- end
93
-
94
- end_partNumber = (file.size + 5_242_880 - 1) / 5_242_880
95
- file.seek(uploadedSize)
96
-
97
- for i in start_partNumber..end_partNumber
98
- body = file.read(5_242_880)
99
- upload_part(bucket, object, location, i.to_s, uploadId, body)
100
- end
101
-
102
- complete_multipart_upload(bucket, object, location, uploadId)
103
- end
104
-
105
- def initiate_multipart_upload(bucket, object, location)
106
- location ||= get_bucket_location(bucket)
107
- path = object + '?uploads'
108
- resource = bucket + '/' + path
109
- ret = request(
110
- expects: 200,
111
- method: 'POST',
112
- path: path,
113
- bucket: bucket,
114
- resource: resource,
115
- location: location
116
- )
117
- XmlSimple.xml_in(ret.data[:body])['UploadId'][0]
118
- end
119
-
120
- def upload_part(bucket, object, location, partNumber, uploadId, body)
121
- location ||= get_bucket_location(bucket)
122
- path = object + '?partNumber=' + partNumber + '&uploadId=' + uploadId
123
- resource = bucket + '/' + path
124
- request(
125
- expects: [200, 203],
126
- method: 'PUT',
127
- path: path,
128
- bucket: bucket,
129
- resource: resource,
130
- body: body,
131
- location: location
132
- )
133
- end
134
-
135
- def complete_multipart_upload(bucket, object, location, uploadId)
136
- location ||= get_bucket_location(bucket)
137
- parts = list_parts(bucket, object, location, uploadId, options = {})
138
- request_part = []
139
- return if parts.empty?
140
- for i in 0..(parts.size - 1)
141
- part = parts[i]
142
- request_part[i] = { 'PartNumber' => part['PartNumber'], 'ETag' => part['ETag'] }
23
+ content=StringIO.new(data.dup)
24
+ @oss_protocol.put_object(bucket_name, object_name, options)do |sw|
25
+ while line=content.read(16*1024)
26
+ sw.write(line)
27
+ end
28
+ end
29
+ content.close
143
30
  end
144
- body = XmlSimple.xml_out({ 'Part' => request_part }, 'RootName' => 'CompleteMultipartUpload')
145
-
146
- path = object + '?uploadId=' + uploadId
147
- resource = bucket + '/' + path
148
- request(
149
- expects: 200,
150
- method: 'POST',
151
- path: path,
152
- bucket: bucket,
153
- resource: resource,
154
- location: location,
155
- body: body
156
- )
157
31
  end
158
32
  end
159
33
  end