oss-ruby-sdk 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/oss/object.rb ADDED
@@ -0,0 +1,318 @@
1
+ require 'oss/client'
2
+ require 'oss/util'
3
+ require 'openssl'
4
+ require 'base64'
5
+
6
+ module Oss
7
+
8
+ class Object
9
+
10
+ include Util
11
+
12
+ attr_accessor :client, :xml_obj
13
+
14
+ def initialize(client)
15
+ @client = client
16
+ end
17
+
18
+ def put_object(bucket_name, object, file, options = {})
19
+ # set header
20
+ headers = Util.hash_filter(options, {
21
+ expires: 'Expires',
22
+ content_control: 'Cache-Control',
23
+ content_encoding: 'Content-Encoding',
24
+ content_type: 'Content-Type',
25
+ content_md5: 'Content-MD5',
26
+ content_disposition: 'Content-Disposition',
27
+ encryption: 'x-oss-server-side-encryption',
28
+ acl: 'x-oss-object-acl',
29
+ })
30
+
31
+ # sign configs
32
+ sign_configs = {
33
+ resource: "/#{bucket_name}",
34
+ content_type: options[:content_type],
35
+ content_md5_check: options[:content_md5_check],
36
+ content_length_check: options[:content_length_check],
37
+ oss_headers: Util.oss_headers_to_s(options, {
38
+ acl: 'x-oss-object-acl',
39
+ encryption: 'x-oss-server-side-encryption',
40
+ })
41
+ }
42
+
43
+ client.put(
44
+ host: "#{bucket_name}.#{client.endpoint}",
45
+ path: "/#{object}",
46
+ headers: headers,
47
+ sign_configs: sign_configs,
48
+ payload: file,
49
+ )
50
+
51
+ true
52
+ end
53
+
54
+ def copy_object(bucket_name, object, old_bucket, old_object, options = {})
55
+ # copy source format
56
+ options[:copy_source] = "/#{old_bucket}/#{old_object}"
57
+
58
+ # set header
59
+ headers = Util.hash_filter(options, {
60
+ metadata_directive: 'x-oss-metadata-directive',
61
+ if_modified_since: 'x-oss-copy-source-if-modified-since',
62
+ if_unmodified_since: 'x-oss-copy-source-if-unmodified-since',
63
+ if_match: 'x-oss-copy-source-if-match',
64
+ if_none_match: 'x-oss-copy-source-if-none-match',
65
+ encryption: 'x-oss-server-side-encryption',
66
+ acl: 'x-oss-object-acl',
67
+ copy_source: 'x-oss-copy-source'
68
+ })
69
+
70
+ # sign configs
71
+ sign_configs = {
72
+ resource: "/#{bucket_name}",
73
+ content_type: 'application/x-www-form-urlencoded',
74
+ oss_headers: Util.oss_headers_to_s(options, {
75
+ metadata_directive: 'x-oss-metadata-directive',
76
+ if_modified_since: 'x-oss-copy-source-if-modified-since',
77
+ if_unmodified_since: 'x-oss-copy-source-if-unmodified-since',
78
+ if_match: 'x-oss-copy-source-if-match',
79
+ if_none_match: 'x-oss-copy-source-if-none-match',
80
+ encryption: 'x-oss-server-side-encryption',
81
+ acl: 'x-oss-object-acl',
82
+ copy_source: 'x-oss-copy-source'
83
+ })
84
+ }
85
+
86
+ @xml_obj = client.put(
87
+ host: "#{bucket_name}.#{client.endpoint}",
88
+ path: "/#{object}",
89
+ headers: headers,
90
+ sign_configs: sign_configs,
91
+ )
92
+
93
+ {
94
+ last_modify: @xml_obj.xpath('CopyObjectResult/LastModified').text,
95
+ etag: @xml_obj.xpath('CopyObjectResult/ETag').text,
96
+ }
97
+ end
98
+
99
+ def get_object(bucket_name, object, options = {})
100
+ # set header
101
+ headers = Util.hash_filter(options, {
102
+ range: 'Range',
103
+ if_modified_since: 'If-Modified-Since',
104
+ if_unmodified_since: 'If-Unmodified-Since',
105
+ if_match: 'If-Match',
106
+ if_none_match: 'If-None-Match'
107
+ })
108
+
109
+ # request params query string
110
+ query_string = Util.hash_filter(options, {
111
+ response_content_type: 'response-content-type',
112
+ response_content_language: 'response-content-language',
113
+ response_expires: 'response-expires',
114
+ response_cache_control: 'response-cache-control',
115
+ response_content_disposition: 'response-content-disposition',
116
+ response_content_encoding: 'response-content-encoding'
117
+ })
118
+
119
+ client.get(
120
+ host: "#{bucket_name}.#{client.endpoint}",
121
+ path: "/#{object}",
122
+ headers: headers,
123
+ sign_configs: { resource: "/#{bucket_name}", sign_query_string: true },
124
+ query_string: query_string,
125
+ as: :raw
126
+ )
127
+ end
128
+
129
+ def append_object(bucket_name, object, file, position = 0, options = {})
130
+ # set header
131
+ headers = Util.hash_filter(options, {
132
+ expires: 'Expires',
133
+ content_control: 'Cache-Control',
134
+ content_encoding: 'Content-Encoding',
135
+ content_type: 'Content-Type',
136
+ content_md5: 'Content-MD5',
137
+ content_disposition: 'Content-Disposition',
138
+ encryption: 'x-oss-server-side-encryption',
139
+ acl: 'x-oss-object-acl',
140
+ })
141
+
142
+ # sign configs
143
+ sign_configs = {
144
+ resource: "/#{bucket_name}",
145
+ content_type: options[:content_type],
146
+ content_md5: options[:content_md5],
147
+ sign_query_string: true,
148
+ oss_headers: Util.oss_headers_to_s(options, {
149
+ acl: 'x-oss-object-acl',
150
+ encryption: 'x-oss-server-side-encryption',
151
+ })
152
+ }
153
+
154
+ resp = client.post(
155
+ host: "#{bucket_name}.#{client.endpoint}",
156
+ path: "/#{object}?append&position=#{position}",
157
+ headers: headers,
158
+ sign_configs: sign_configs,
159
+ payload: file,
160
+ as: :raw
161
+ )
162
+
163
+ {
164
+ hash_crc64ecma: resp.headers[:x_oss_hash_crc64ecma],
165
+ next_append_position: resp.headers[:x_oss_next_append_position].to_i
166
+ }
167
+ end
168
+
169
+ # params:
170
+ # - bucket_name
171
+ # - object_name
172
+ def delete_object(bucket_name, object_name)
173
+
174
+ client.delete(
175
+ host: "#{bucket_name}.#{client.endpoint}",
176
+ path: "/#{object_name}",
177
+ sign_configs: {resource: "/#{bucket_name}"}
178
+ )
179
+
180
+ true
181
+ end
182
+
183
+ def delete_multiple_objects(bucket_name, objects = [])
184
+ # build payload xml
185
+ payload = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do
186
+ Delete do
187
+ Quiet 'false'
188
+ objects.each do |obj|
189
+ Object do
190
+ Key obj
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ xml_obj = client.post(
197
+ host: "#{bucket_name}.#{client.endpoint}",
198
+ path: "/?delete",
199
+ sign_configs: {resource: "/#{bucket_name}", content_type: 'application/x-www-form-urlencoded'},
200
+ content_md5_check: true,
201
+ content_length_check: true,
202
+ payload: payload.to_xml
203
+ )
204
+
205
+ # parse return deleted keys
206
+ deleted = Array.new
207
+ xml_obj.xpath('DeleteResult/Deleted').each do |obj|
208
+ deleted << obj.xpath('Key').text
209
+ end
210
+
211
+ deleted
212
+ end
213
+
214
+ def head_object(bucket_name, object_name, options = {})
215
+ # set header
216
+ headers = Util.hash_filter(options, {
217
+ if_modified_since: 'If-Modified-Since',
218
+ if_unmodified_since: 'If-Unmodified-Since',
219
+ if_match: 'If-Match',
220
+ if_none_match: 'If-None-Match'
221
+ })
222
+
223
+ resp = client.head(
224
+ host: "#{bucket_name}.#{client.endpoint}",
225
+ path: "/#{object_name}",
226
+ headers: headers,
227
+ sign_configs: {resource: "/#{bucket_name}"},
228
+ as: :raw
229
+ )
230
+
231
+ # head request returns hole response headers
232
+ resp.headers
233
+ end
234
+
235
+ # params:
236
+ # - bucket_name
237
+ # - object_name
238
+ # - acl
239
+ def put_object_acl(bucket_name, object_name, acl)
240
+ # sign configs
241
+ sign_configs = Hash.new
242
+ sign_configs[:resource] = "/#{bucket_name}"
243
+ sign_configs[:oss_headers] = "x-oss-object-acl:#{acl}"
244
+ sign_configs[:content_type] = 'application/x-www-form-urlencoded'
245
+
246
+ @xml_obj = client.put(
247
+ host: "#{bucket_name}.#{client.endpoint}",
248
+ path: "/#{object_name}?acl",
249
+ headers: {'x-oss-object-acl' => acl},
250
+ sign_configs: sign_configs
251
+ )
252
+
253
+ true
254
+ end
255
+
256
+ # params:
257
+ # - bucket_name
258
+ # - object_name
259
+ def get_object_acl(bucket_name, object_name)
260
+ xml_obj = client.get(
261
+ host: "#{bucket_name}.#{client.endpoint}",
262
+ path: "/#{object_name}?acl",
263
+ sign_configs: {resource: "/#{bucket_name}"}
264
+ ).xpath('AccessControlPolicy')
265
+
266
+ {
267
+ grant: xml_obj.xpath('AccessControlList/Grant').text,
268
+ owner: {
269
+ id: xml_obj.xpath('Owner/ID').text,
270
+ display_name: xml_obj.xpath('Owner/DisplayName').text
271
+ }
272
+ }
273
+ end
274
+
275
+ # params:
276
+ # - bucket_name
277
+ # - key
278
+ # - options
279
+ def post_object(bucket_name, key, options = {})
280
+
281
+ # build form upload info hash
282
+ form_hash = { 'key' => key, 'action' => "http://#{bucket_name}.#{client.endpoint}/"}
283
+ options.each do |k, v|
284
+ # need Signature
285
+ if k == :policy
286
+ # json policy string to base64 policy string
287
+ form_hash['policy'] = Base64.encode64(v).gsub("\n", '')
288
+
289
+ # create signature
290
+ digest = OpenSSL::Digest.new('sha1')
291
+ h = OpenSSL::HMAC.digest(digest, client.access_key_secret, form_hash['policy'])
292
+ # base64 result
293
+ form_hash['Signature'] = Base64.encode64(h).gsub("\n", '')
294
+ # add access key id
295
+ form_hash['OSSAccessKeyId'] = client.access_key_id
296
+ else
297
+ form_hash[k.to_s] = v
298
+ end
299
+ end
300
+
301
+ # return a hash for render a html upload form
302
+ form_hash
303
+ end
304
+
305
+ def method_missing(method)
306
+ if @xml_obj.nil?
307
+ super
308
+ else
309
+ camel = Util.camelize(method)
310
+ value = @xml_obj.xpath(camel)
311
+ raise "missing xml attribute #{camel}" if value.length == 0
312
+ value.inner_text
313
+ end
314
+ end
315
+
316
+ end
317
+
318
+ end
@@ -0,0 +1,63 @@
1
+ require 'oss/client'
2
+ require 'oss/util'
3
+
4
+ module Oss
5
+
6
+ SERVICE_HOST = 'oss.aliyuncs.com'
7
+
8
+ class Service
9
+
10
+ include Util
11
+
12
+ attr_accessor :client, :xml_obj
13
+
14
+ def initialize(client)
15
+ @client = client
16
+ end
17
+
18
+ # params:
19
+ # - options:
20
+ # - prefix
21
+ # - marker
22
+ # - max_keys
23
+ def get_service(options = {})
24
+ @xml_obj = client.get(host: SERVICE_HOST, path: '/', query_string: options).xpath('ListAllMyBucketsResult')
25
+ self
26
+ end
27
+
28
+ def owner
29
+ owner = @xml_obj.xpath('Owner')
30
+ {
31
+ :id => owner.xpath('ID').text,
32
+ :display_name => owner.xpath('DisplayName').text
33
+ }
34
+ end
35
+
36
+ def buckets
37
+ buckets = @xml_obj.xpath('Buckets')
38
+ results = Array.new
39
+ buckets.each do |bucket|
40
+ results << {
41
+ :location => bucket.xpath('Bucket/Location').text,
42
+ :name => bucket.xpath('Bucket/Name').text,
43
+ :creation_date => bucket.xpath('Bucket/CreationDate').text
44
+ }
45
+ end
46
+ results
47
+ end
48
+
49
+ # prefix, marker, max_keys, is_truncated, next_marker
50
+ def method_missing(method)
51
+ if @xml_obj.nil?
52
+ super
53
+ else
54
+ camel = Util.camelize(method)
55
+ value = @xml_obj.xpath(camel)
56
+ raise "missing xml attribute #{camel}" if value.length == 0
57
+ value.inner_text
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ end
data/lib/oss/util.rb ADDED
@@ -0,0 +1,59 @@
1
+ module Oss
2
+
3
+ module Util extend self
4
+
5
+ def camelize(str)
6
+ str.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
7
+ end
8
+
9
+ def hash_filter(input_hash, key_map, target_hash = Hash.new)
10
+ key_map.each do |key, value|
11
+ unless input_hash[key].nil?
12
+ target_hash[value] = input_hash[key]
13
+ end
14
+ end
15
+ target_hash
16
+ end
17
+
18
+ # x-oss:value
19
+ def oss_headers_to_s(input_hash, key_map)
20
+ header_array = Array.new
21
+
22
+ # sort by hash value
23
+ sorted = Hash[key_map.sort_by{|k,v| v}]
24
+
25
+ sorted.each do |key, value|
26
+ unless input_hash[key].nil?
27
+ header_array << "#{value}:#{input_hash[key]}"
28
+ end
29
+ end
30
+ header_array.join("\n")
31
+ end
32
+
33
+ def set_query_string(path, query)
34
+ return path if query.nil?
35
+
36
+ attrs = Array.new
37
+ new_path = "#{path}"
38
+
39
+ # sort by hash value
40
+ sorted = Hash[query.sort_by{|k,v| k}]
41
+
42
+ sorted.each do |k, v|
43
+ # query key ruby hash _ to -
44
+ attrs << "#{k.to_s.gsub('_', '-')}=#{v}"
45
+ end
46
+
47
+ # create http request query string
48
+ if attrs.length > 0
49
+ new_path << "?#{attrs.join('&')}"
50
+ end
51
+
52
+ new_path
53
+ end
54
+
55
+
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,3 @@
1
+ module Oss
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'oss/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "oss-ruby-sdk"
8
+ spec.version = Oss::VERSION
9
+ spec.authors = ["RaymondChou"]
10
+ spec.email = ["freezestart@gmail.com"]
11
+
12
+ spec.summary = %q{Aliyun OSS Ruby SDK}
13
+ spec.description = %q{Aliyun OSS(Object Storage Service) Ruby SDK}
14
+ spec.homepage = "http://github.com/RaymondChou"
15
+ spec.license = "Apache 2.0"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.10"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "rest-client", "~> 1.8"
25
+ spec.add_development_dependency "nokogiri", "~> 1.6"
26
+ end