aliyun-oss-sdk 0.0.3 → 0.1.0

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +17 -0
  3. data/Gemfile +1 -0
  4. data/README.md +12 -10
  5. data/Rakefile +10 -0
  6. data/aliyun-oss.gemspec +2 -2
  7. data/lib/aliyun/oss.rb +4 -11
  8. data/lib/aliyun/oss/authorization.rb +59 -27
  9. data/lib/aliyun/oss/client.rb +137 -62
  10. data/lib/aliyun/oss/client/bucket_multiparts.rb +43 -0
  11. data/lib/aliyun/oss/client/bucket_objects.rb +111 -0
  12. data/lib/aliyun/oss/client/buckets.rb +50 -0
  13. data/lib/aliyun/oss/client/clients.rb +54 -0
  14. data/lib/aliyun/oss/error.rb +43 -0
  15. data/lib/aliyun/oss/http.rb +65 -23
  16. data/lib/aliyun/oss/struct.rb +26 -0
  17. data/lib/aliyun/oss/struct/bucket.rb +252 -0
  18. data/lib/aliyun/oss/struct/cors.rb +65 -0
  19. data/lib/aliyun/oss/struct/lifecycle.rb +73 -0
  20. data/lib/aliyun/oss/struct/logging.rb +33 -0
  21. data/lib/aliyun/oss/struct/multipart.rb +101 -0
  22. data/lib/aliyun/oss/struct/object.rb +71 -0
  23. data/lib/aliyun/oss/struct/part.rb +48 -0
  24. data/lib/aliyun/oss/struct/referer.rb +21 -0
  25. data/lib/aliyun/oss/struct/website.rb +13 -0
  26. data/lib/aliyun/oss/utils.rb +41 -1
  27. data/lib/aliyun/oss/version.rb +1 -1
  28. data/lib/aliyun/oss/xml_generator.rb +174 -0
  29. data/todo.md +5 -0
  30. data/wiki/bucket.md +20 -20
  31. data/wiki/cors.md +59 -0
  32. data/wiki/error.md +42 -31
  33. data/wiki/get_start.md +24 -7
  34. data/wiki/installation.md +2 -2
  35. data/wiki/lifecycle.md +75 -0
  36. data/wiki/multipart.md +7 -5
  37. data/wiki/object.md +16 -12
  38. metadata +48 -6
  39. data/lib/aliyun/oss/multipart/part.rb +0 -32
  40. data/lib/aliyun/oss/rule/cors.rb +0 -63
  41. data/lib/aliyun/oss/rule/lifecycle.rb +0 -61
@@ -0,0 +1,71 @@
1
+ module Aliyun
2
+ module Oss
3
+ module Struct
4
+ class Object < Base
5
+ # Key of object
6
+ attr_accessor :key
7
+
8
+ # last modified time of object
9
+ attr_accessor :last_modified
10
+
11
+ # etag of object
12
+ attr_accessor :etag
13
+
14
+ # type of object
15
+ attr_accessor :type
16
+
17
+ # size of object
18
+ attr_accessor :size
19
+
20
+ # storage class of object
21
+ attr_accessor :storage_class
22
+
23
+ # owner of object
24
+ attr_accessor :owner
25
+
26
+ # location of object
27
+ attr_accessor :location
28
+
29
+ # bucket of object placed
30
+ attr_accessor :bucket
31
+
32
+ # reference to client
33
+ attr_accessor :client
34
+
35
+ # Get ACL for object
36
+ #
37
+ # @raise [RequestError]
38
+ #
39
+ # @return [String]
40
+ def acl!
41
+ result = client.bucket_get_object_acl(key).parsed_response
42
+ acl_keys = %w(AccessControlPolicy AccessControlList Grant)
43
+ Utils.dig_value(result, *acl_keys).strip
44
+ end
45
+
46
+ # Set ACL for object
47
+ #
48
+ # @param acl [String] access value, supported value: private, public-read, public-read-write
49
+ #
50
+ # @raise [RequestError]
51
+ #
52
+ # @return [true]
53
+ def set_acl(acl)
54
+ !!client.bucket_set_object_acl(key, acl)
55
+ end
56
+
57
+ # Get meta information of object
58
+ #
59
+ # @param headers [Hash] headers
60
+ # @option (see #bucket_get_meta_object)
61
+ #
62
+ # @raise [RequestError]
63
+ #
64
+ # @return [Hash]
65
+ def meta!(*args)
66
+ client.bucket_get_meta_object(*args.unshift(key)).headers
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,48 @@
1
+ module Aliyun
2
+ module Oss
3
+ module Struct
4
+ class Part < Base
5
+ # [Integer] :number the part number
6
+ attr_accessor :number
7
+
8
+ # [String] :etag the etag for the part
9
+ attr_accessor :etag
10
+
11
+ # Last Modified time
12
+ attr_accessor :last_modified
13
+
14
+ # Part size
15
+ attr_accessor :size
16
+
17
+ def last_modified=(last_modified)
18
+ @last_modified = Time.parse(last_modified)
19
+ end
20
+
21
+ def part_number=(part_number)
22
+ @number = part_number
23
+ end
24
+
25
+ def e_tag=(e_tag)
26
+ @etag = e_tag
27
+ end
28
+
29
+ def to_hash
30
+ if valid?
31
+ {
32
+ 'PartNumber' => number,
33
+ 'ETag' => etag
34
+ }
35
+ else
36
+ {}
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def valid?
43
+ number && etag
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ module Aliyun
2
+ module Oss
3
+ module Struct
4
+ class Referer < Base
5
+ # specify allow empty referer access
6
+ attr_accessor :allow_empty
7
+
8
+ # specify white list for allows referers
9
+ attr_accessor :referers
10
+
11
+ def allow_empty=(allow_empty)
12
+ @allow_empty = allow_empty == 'true'
13
+ end
14
+
15
+ def referers=(referers)
16
+ @referers = Utils.wrap(referers).map(&:strip)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ module Aliyun
2
+ module Oss
3
+ module Struct
4
+ class Website < Base
5
+ # A suffix that is appended to a request that is for a directory on the website endpoint (e.g. if the suffix is index.html and you make a request to samplebucket/images/ the data that is returned will be for the object with the key name images/index.html) The suffix must not be empty and must not include a slash character.
6
+ attr_accessor :suffix
7
+
8
+ # The object key name to use when a 4XX class error occurs
9
+ attr_accessor :error_key
10
+ end
11
+ end
12
+ end
13
+ end
@@ -43,7 +43,47 @@ module Aliyun
43
43
  end
44
44
 
45
45
  def self.to_xml(hash) # nodoc
46
- %|<?xml version="1.0" encoding="UTF-8"?>#{Gyoku.xml(hash)}|
46
+ %(<?xml version="1.0" encoding="UTF-8"?>#{Gyoku.xml(hash)})
47
+ end
48
+
49
+ # Dig values in deep hash
50
+ #
51
+ # @example
52
+ # dig_value({ 'a' => { 'b' => { 'c' => 3 } } }, 'a', 'b', 'c') # => 3
53
+ #
54
+ def self.dig_value(hash, *keys)
55
+ new_hash = hash.dup
56
+
57
+ keys.each do |key|
58
+ if new_hash.is_a?(Hash) && new_hash.key?(key)
59
+ new_hash = new_hash[key]
60
+ else
61
+ return nil
62
+ end
63
+ end
64
+ new_hash
65
+ end
66
+
67
+ # @see {http://apidock.com/rails/String/underscore String#underscore}
68
+ def self.underscore(str)
69
+ word = str.to_s.dup
70
+ word.gsub!(/::/, '/')
71
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
72
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
73
+ word.tr!('-', '_')
74
+ word.downcase!
75
+ word
76
+ end
77
+
78
+ # Copy from {https://github.com/rails/rails/blob/14254d82a90b8aa4bd81f7eeebe33885bf83c378/activesupport/lib/active_support/core_ext/array/wrap.rb#L36 ActiveSupport::Array#wrap}
79
+ def self.wrap(object)
80
+ if object.nil?
81
+ []
82
+ elsif object.respond_to?(:to_ary)
83
+ object.to_ary || [object]
84
+ else
85
+ [object]
86
+ end
47
87
  end
48
88
  end
49
89
  end
@@ -1,5 +1,5 @@
1
1
  module Aliyun
2
2
  module Oss
3
- VERSION = '0.0.3'
3
+ VERSION = '0.1.0'
4
4
  end
5
5
  end
@@ -0,0 +1,174 @@
1
+ module Aliyun
2
+ module Oss
3
+ class XmlGenerator
4
+ # Generate xml from rules
5
+ #
6
+ # @example
7
+ # <?xml version="1.0" encoding="UTF-8"?>
8
+ # <LifecycleConfiguration>
9
+ # <Rule>
10
+ # <ID>RuleID</ID>
11
+ # <Prefix>Prefix</Prefix>
12
+ # <Status>Status</Status>
13
+ # <Expiration>
14
+ # <Days>Days</Days>
15
+ # </Expiration>
16
+ # </Rule>
17
+ # </LifecycleConfiguration>
18
+ def self.generate_lifecycle_rules(rules)
19
+ Utils.to_xml(
20
+ 'LifecycleConfiguration' => {
21
+ 'Rule' => rules.map(&:to_hash)
22
+ })
23
+ end
24
+
25
+ # Generate xml for cors from rules
26
+ #
27
+ # @example
28
+ # <?xml version="1.0" encoding="UTF-8"?>
29
+ # <CORSConfiguration>
30
+ # <CORSRule>
31
+ # <AllowedOrigin>the origin you want allow CORS request from</AllowedOrigin>
32
+ # <AllowedOrigin>...AllowedOrigin>
33
+ # <AllowedMethod>HTTP method</AllowedMethod>
34
+ # <AllowedMethod>...AllowedMethod>
35
+ # <AllowedHeader> headers that allowed browser to send</AllowedHeader>
36
+ # <AllowedHeader>...AllowedHeader>
37
+ # <ExposeHeader> headers in response that can access from client app</ExposeHeader>
38
+ # <ExposeHeader>...ExposeHeader>
39
+ # <MaxAgeSeconds>time to cache pre-fight response</MaxAgeSeconds>
40
+ # </CORSRule>
41
+ # <CORSRule>
42
+ # ...
43
+ # </CORSRule>
44
+ # ...
45
+ # </CORSConfiguration >
46
+ #
47
+ def self.generate_cors_rules(rules)
48
+ Utils.to_xml(
49
+ 'CORSConfiguration' => {
50
+ 'CORSRule' => rules.map(&:to_hash)
51
+ })
52
+ end
53
+
54
+ # Generate xml for delete objects
55
+ #
56
+ # @example
57
+ # <?xml version="1.0" encoding="UTF-8"?>
58
+ # <Delete>
59
+ # <Quiet>true</Quiet>
60
+ # <Object>
61
+ # <Key>key</Key>
62
+ # </Object>
63
+ # ...
64
+ # </Delete>
65
+ #
66
+ def self.generate_delete_objects_xml(keys, quiet)
67
+ key_objects = keys.map { |key| { 'Key' => key } }
68
+ Utils.to_xml(
69
+ 'Delete' => {
70
+ 'Object' => key_objects,
71
+ 'Quiet' => quiet
72
+ })
73
+ end
74
+
75
+ # Generate xml for complete multipart from parts
76
+ #
77
+ # @example
78
+ # <CompleteMultipartUpload>
79
+ # <Part>
80
+ # <PartNumber>PartNumber</PartNumber>
81
+ # <ETag>ETag</ETag>
82
+ # </Part>
83
+ # ...
84
+ # </CompleteMultipartUpload>
85
+ #
86
+ def self.generate_complete_multipart_xml(parts)
87
+ Utils.to_xml(
88
+ 'CompleteMultipartUpload' => {
89
+ 'Part' => parts.map(&:to_hash)
90
+ })
91
+ end
92
+
93
+ # Generate xml for #bucket_create with location
94
+ #
95
+ # @example
96
+ # <?xml version="1.0" encoding="UTF-8"?>
97
+ # <CreateBucketConfiguration>
98
+ # <LocationConstraint>BucketRegion</LocationConstraint>
99
+ # </CreateBucketConfiguration>
100
+ #
101
+ def self.generate_create_bucket_xml(location)
102
+ configuration = {
103
+ 'CreateBucketConfiguration' => {
104
+ 'LocationConstraint' => location
105
+ }
106
+ }
107
+ Utils.to_xml(configuration)
108
+ end
109
+
110
+ # Generate xml for enable logging
111
+ #
112
+ # @example
113
+ # <?xml version="1.0" encoding="UTF-8"?>
114
+ # <BucketLoggingStatus>
115
+ # <LoggingEnabled>
116
+ # <TargetBucket>TargetBucket</TargetBucket>
117
+ # <TargetPrefix>TargetPrefix</TargetPrefix>
118
+ # </LoggingEnabled>
119
+ # </BucketLoggingStatus>
120
+ #
121
+ def self.generate_enable_logging_xml(target_bucket, target_prefix)
122
+ logging = { 'TargetBucket' => target_bucket }
123
+ logging.merge!('TargetPrefix' => target_prefix) if target_prefix
124
+ Utils.to_xml(
125
+ 'BucketLoggingStatus' => {
126
+ 'LoggingEnabled' => logging
127
+ })
128
+ end
129
+
130
+ # Generate xml for enable website
131
+ #
132
+ # @example
133
+ # <?xml version="1.0" encoding="UTF-8"?>
134
+ # <WebsiteConfiguration>
135
+ # <IndexDocument>
136
+ # <Suffix>index.html</Suffix>
137
+ # </IndexDocument>
138
+ # <ErrorDocument>
139
+ # <Key>errorDocument.html</Key>
140
+ # </ErrorDocument>
141
+ # </WebsiteConfiguration>
142
+ #
143
+ def self.generate_enable_website_xml(suffix, key)
144
+ website_configuration = { 'IndexDocument' => { 'Suffix' => suffix } }
145
+ website_configuration.merge!('ErrorDocument' => { 'Key' => key }) if key
146
+ Utils.to_xml('WebsiteConfiguration' => website_configuration)
147
+ end
148
+
149
+ # Generate xml for set referer
150
+ #
151
+ # @example
152
+ # <?xml version="1.0" encoding="UTF-8"?>
153
+ # <RefererConfiguration>
154
+ # <AllowEmptyReferer>true</AllowEmptyReferer >
155
+ # <RefererList>
156
+ # <Referer> http://www.aliyun.com</Referer>
157
+ # <Referer> https://www.aliyun.com</Referer>
158
+ # <Referer> http://www.*.com</Referer>
159
+ # <Referer> https://www.?.aliyuncs.com</Referer>
160
+ # </ RefererList>
161
+ # </RefererConfiguration>
162
+ #
163
+ def self.generate_set_referer_xml(referers, allowed_empty)
164
+ Utils.to_xml(
165
+ 'RefererConfiguration' => {
166
+ 'AllowEmptyReferer' => allowed_empty,
167
+ 'RefererList' => {
168
+ 'Referer' => referers
169
+ }
170
+ })
171
+ end
172
+ end
173
+ end
174
+ end
data/todo.md ADDED
@@ -0,0 +1,5 @@
1
+ ## TODO
2
+
3
+ + Command Line Tool
4
+ + Custom Domain Support
5
+ + Get Download URL
@@ -1,10 +1,10 @@
1
1
  ## Bucket
2
2
 
3
- Bucket is namespace in OSS, as well as management entity for high functions such as pricing, access control, logging; Bucket names are global uniqueness throughout the OSS services, and cannot be modified. Each Object stored in the OSS must contained in a Bucket. An application, such as the picture sharing website, can correspond to one or more Bucket. A user can create up to 10 Bucket, but each bucket can store unlimit objects, there is no limit to the number of storage capacity each buckte highest support 2 PB.
3
+ Bucket is a namespace in OSS, as well as management entity for high functions such as pricing, access control, logging; Bucket names are global uniqueness throughout the OSS services, and cannot be modified. Each Object stored in the OSS must contained in a Bucket. An application, such as the picture sharing website, can correspond to one or more Bucket. A user can create up to 10 Bucket, but each bucket can store unlimit objects, there is no limit to the number of storage capacity each buckte highest support 2 PB.
4
4
 
5
5
  ### Name Spec
6
6
 
7
- + only contains lowercase letters, Numbers, dash (-)
7
+ + Only contains lowercase letters, Numbers, dash (-)
8
8
  + Must begin with lowercase letters or Numbers
9
9
  + Length must be between 3-63 bytes
10
10
 
@@ -21,7 +21,8 @@ Bucket is namespace in OSS, as well as management entity for high functions such
21
21
  res = client.bucket_create('new-bucket', 'oss-cn-beijing', 'private')
22
22
  puts res.success?, res.headers
23
23
 
24
- You can specify bucket name, location and acl when create new bucket. More about this method, visit [Client#bucket_create]()
24
+ You can specify bucket name, location(default 'oss-cn-hangzhou') and acl(default: 'private') when create new bucket.
25
+
25
26
 
26
27
  ### List all buckets
27
28
 
@@ -35,40 +36,38 @@ To get all buckets use Client#list_buckets:
35
36
  client = Aliyun::Oss::Client.new(access_key, secret_key, host: host)
36
37
 
37
38
  res = client.list_buckets
38
- puts res.parsed_response
39
+ puts res.success?, res.parsed_response
39
40
 
40
41
 
41
- ### Set ACL for Bucket
42
+ ### Set ACL
42
43
 
43
- With Client#bucket_set_acl you can modify the ACL for bucket:
44
+ With Client#bucket_set_acl you can modify the ACL:
44
45
 
45
46
  require 'aliyun/oss'
46
47
 
47
48
  access_key, secret_key = "your id", "your secret"
48
- host = "oss-cn-hangzhou.aliyuncs.com"
49
- bucket = "bucket-name"
49
+ host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
50
50
  client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
51
51
 
52
52
  # supported value: public-read-write | public-read | private
53
53
  res = client.bucket_set_acl("public-read")
54
- puts res.parsed_response
54
+ puts res.success?, res.parsed_response
55
55
 
56
56
  Now, it support public-read-write | public-read | private, more detail visit: [Bucket ACL](https://docs.aliyun.com/#/pub/oss/product-documentation/acl&bucket-acl)
57
57
 
58
- ### Get ACL of Bucket
59
58
 
60
- To get current ACL of Bucket, use Client#bucket_get_acl
59
+ ### Get ACL
61
60
 
61
+ To get current ACL of Bucket, use Client#bucket_get_acl:
62
62
 
63
63
  require 'aliyun/oss'
64
64
 
65
65
  access_key, secret_key = "your id", "your secret"
66
- host = "oss-cn-hangzhou.aliyuncs.com"
67
- bucket = "bucket-name"
66
+ host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
68
67
  client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
69
68
 
70
69
  res = client.bucket_get_acl
71
- puts res.parsed_response
70
+ puts res.success?, res.parsed_response
72
71
 
73
72
 
74
73
  ### Get Bucket Location
@@ -78,18 +77,18 @@ Get bucket's data center location, use Client#bucket_get_location:
78
77
  require 'aliyun/oss'
79
78
 
80
79
  access_key, secret_key = "your id", "your secret"
81
- host = "oss-cn-hangzhou.aliyuncs.com"
82
- bucket = "bucket-name"
80
+ host, bucket = "oss-cn-hangzhou.aliyuncs.com", "bucket-name"
83
81
  client = Aliyun::Oss::Client.new(access_key, secret_key, host: host, bucket: bucket)
84
82
 
85
83
  res = client.bucket_get_location
86
- puts res.parsed_response
84
+ puts res.success?, res.parsed_response
85
+
86
+ To get more bucket information, visit Client#bucket_get_xxx methods [here](http://www.rubydoc.info/gems/aliyun-oss-sdk/Aliyun/Oss/Client).
87
87
 
88
- More bucket information can fetch via Client#bucket_get_xxx methods. View the [Ruby Document]()
89
88
 
90
89
  ### Delete Bucket
91
90
 
92
- If you donot need the bucket, delete it with Client#bucket_delete
91
+ If you do need one bucket, delete it with Client#bucket_delete:
93
92
 
94
93
  require 'aliyun/oss'
95
94
 
@@ -100,7 +99,8 @@ If you donot need the bucket, delete it with Client#bucket_delete
100
99
  res = client.bucket_delete("deleted-bucket-name")
101
100
  puts res.success?, res.headers
102
101
 
103
- Note: when the bucket is not empty(existing object or parts upload via Multipart), the delete may be fail.
102
+ Note: when the bucket is not empty(existing object or [Multipart Uploaded](./multipart.md) parts), the delete will fail.
103
+
104
104
 
105
105
  OK, Let's visit [Objects](./object.md)
106
106