baidubce-sdk 0.9.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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE +177 -0
- data/README.md +1266 -0
- data/Rakefile +6 -0
- data/baidubce-sdk.gemspec +31 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/baidubce/auth/bce_credentials.rb +31 -0
- data/lib/baidubce/auth/bce_v1_signer.rb +76 -0
- data/lib/baidubce/bce_base_client.rb +52 -0
- data/lib/baidubce/bce_client_configuration.rb +47 -0
- data/lib/baidubce/bce_constants.rb +20 -0
- data/lib/baidubce/exception.rb +34 -0
- data/lib/baidubce/http/base_http_client.rb +259 -0
- data/lib/baidubce/http/http_constants.rb +102 -0
- data/lib/baidubce/retry_policy.rb +87 -0
- data/lib/baidubce/services/bos/bos_client.rb +461 -0
- data/lib/baidubce/services/bos/bos_constants.rb +25 -0
- data/lib/baidubce/services/sts/sts_client.rb +38 -0
- data/lib/baidubce/utils/log.rb +51 -0
- data/lib/baidubce/utils/utils.rb +124 -0
- data/lib/baidubce/version.rb +7 -0
- data/samples/baidubce/bos_sample.rb +376 -0
- data/samples/baidubce/sts_sample.rb +82 -0
- metadata +174 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
# Copyright 2017 Baidu, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
4
|
+
# except in compliance with the License. You may obtain a copy of the License at
|
5
|
+
#
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
#
|
8
|
+
# Unless required by applicable law or agreed to in writing, software distributed under the
|
9
|
+
# License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
10
|
+
# either express or implied. See the License for the specific language governing permissions
|
11
|
+
# and limitations under the License.
|
12
|
+
|
13
|
+
# This module provide constants for BOS services.
|
14
|
+
|
15
|
+
module Baidubce
|
16
|
+
module Services
|
17
|
+
|
18
|
+
MAX_PUT_OBJECT_LENGTH = 5 * 1024 * 1024 * 1024
|
19
|
+
MAX_APPEND_OBJECT_LENGTH = 5 * 1024 * 1024 * 1024
|
20
|
+
MAX_USER_METADATA_SIZE = 2 * 1024
|
21
|
+
MIN_PART_NUMBER = 1
|
22
|
+
MAX_PART_NUMBER = 10000
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Copyright (c) 2014 Baidu.com, Inc. All Rights Reserved
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
4
|
+
# except in compliance with the License. You may obtain a copy of the License at
|
5
|
+
#
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
#
|
8
|
+
# Unless required by applicable law or agreed to in writing, software distributed under the
|
9
|
+
# License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
10
|
+
# either express or implied. See the License for the specific language governing permissions
|
11
|
+
# and limitations under the License.
|
12
|
+
|
13
|
+
# This module provides a client for STS.
|
14
|
+
|
15
|
+
require_relative '../../bce_base_client'
|
16
|
+
|
17
|
+
module Baidubce
|
18
|
+
module Services
|
19
|
+
|
20
|
+
class StsClient < BceBaseClient
|
21
|
+
|
22
|
+
STS_URL_PREFIX = "/"
|
23
|
+
GET_SESSION_TOKEN_VERSION = "v1"
|
24
|
+
GET_SESSION_TOKEN_PATH = "sessionToken"
|
25
|
+
|
26
|
+
def get_session_token(acl, duration_seconds=nil)
|
27
|
+
params = duration_seconds.nil? ? {} : { durationSeconds: duration_seconds }
|
28
|
+
headers = { CONTENT_TYPE => JSON_TYPE }
|
29
|
+
body = acl.to_json
|
30
|
+
path = Utils.append_uri(STS_URL_PREFIX, GET_SESSION_TOKEN_VERSION, GET_SESSION_TOKEN_PATH)
|
31
|
+
body, headers = @http_client.send_request(@config, @signer, POST, path, params, headers, body)
|
32
|
+
Utils.generate_response(headers, body, false)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# Copyright 2017 Baidu, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
4
|
+
# except in compliance with the License. You may obtain a copy of the License at
|
5
|
+
#
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
#
|
8
|
+
# Unless required by applicable law or agreed to in writing, software distributed under the
|
9
|
+
# License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
10
|
+
# either express or implied. See the License for the specific language governing permissions
|
11
|
+
# and limitations under the License.
|
12
|
+
|
13
|
+
# This module provide logger utils for bce client.
|
14
|
+
|
15
|
+
require 'logger'
|
16
|
+
|
17
|
+
module Baidubce
|
18
|
+
|
19
|
+
module Log
|
20
|
+
DEFAULT_LOG_FILE = "./baidubce-sdk.log"
|
21
|
+
MAX_NUM_LOG = 100
|
22
|
+
LOG_FILE_SIZE = 10 * 1024 * 1024
|
23
|
+
|
24
|
+
def logger
|
25
|
+
Log.logger
|
26
|
+
end
|
27
|
+
|
28
|
+
# level : Logger::DEBUG | Logger::INFO | Logger::ERROR | Logger::FATAL
|
29
|
+
def self.set_log_level(level)
|
30
|
+
Log.logger.level = level
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.set_log_file(file)
|
34
|
+
@log_file = file
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def self.logger
|
40
|
+
unless @logger
|
41
|
+
@logger = Logger.new(
|
42
|
+
@log_file ||= DEFAULT_LOG_FILE, MAX_NUM_LOG, LOG_FILE_SIZE)
|
43
|
+
@logger.level = Logger::INFO
|
44
|
+
end
|
45
|
+
@logger
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# Copyright 2017 Baidu, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
4
|
+
# except in compliance with the License. You may obtain a copy of the License at
|
5
|
+
#
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
#
|
8
|
+
# Unless required by applicable law or agreed to in writing, software distributed under the
|
9
|
+
# License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
10
|
+
# either express or implied. See the License for the specific language governing permissions
|
11
|
+
# and limitations under the License.
|
12
|
+
|
13
|
+
# This module provide some utils for bce client.
|
14
|
+
|
15
|
+
require "erb"
|
16
|
+
require "uri"
|
17
|
+
require 'json'
|
18
|
+
require 'digest/md5'
|
19
|
+
|
20
|
+
require_relative "../http/http_constants"
|
21
|
+
|
22
|
+
module Baidubce
|
23
|
+
|
24
|
+
class Utils
|
25
|
+
|
26
|
+
# parse protocol, host, port from endpoint in config.
|
27
|
+
def self.parse_url_host(config)
|
28
|
+
endpoint = config.endpoint
|
29
|
+
unless endpoint.include?"://"
|
30
|
+
protocol = config.protocol.downcase
|
31
|
+
raise "Invalid protocol #{protocol}." if protocol != "http" && protocol != 'https'
|
32
|
+
endpoint = sprintf("%s://%s", protocol, endpoint)
|
33
|
+
end
|
34
|
+
parsed_endpoint = URI.parse(endpoint)
|
35
|
+
scheme = parsed_endpoint.scheme.downcase
|
36
|
+
raise "Invalid endpoint #{endpoint}, unsupported scheme #{scheme}." if scheme != "http" && protocol != 'https'
|
37
|
+
host = parsed_endpoint.host
|
38
|
+
port = parsed_endpoint.port
|
39
|
+
host += ":#{port}" unless scheme == 'http' && port == 80 || scheme == 'https' && port == 443
|
40
|
+
return "#{scheme}://#{host}", host
|
41
|
+
end
|
42
|
+
|
43
|
+
# Append path_components to the end of base_uri in order.
|
44
|
+
def self.append_uri(base_uri, *path_components)
|
45
|
+
uri = [base_uri]
|
46
|
+
path_components.reject(&:empty?)
|
47
|
+
path_components.each { |path| uri << path }
|
48
|
+
|
49
|
+
unless uri.empty?
|
50
|
+
uri[0].gsub!(/([\/]*$)/, '')
|
51
|
+
uri[-1].gsub!(/(^[\/]*)/, '')
|
52
|
+
uri.each { |u| u.gsub!(/(^[\/]*)|([\/]*$)/, '') }
|
53
|
+
end
|
54
|
+
|
55
|
+
uri.join("/")
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.url_encode_except_slash(path)
|
59
|
+
encoded_path = ERB::Util.url_encode(path)
|
60
|
+
encoded_path.gsub('%2F', '/')
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.get_canonical_querystring(params, for_signature)
|
64
|
+
return '' if params.nil? || params.empty?
|
65
|
+
|
66
|
+
arr = []
|
67
|
+
params.each do |key, value|
|
68
|
+
if !for_signature || key.downcase != Http::AUTHORIZATION.downcase
|
69
|
+
value = '' if value.nil?
|
70
|
+
str = ERB::Util.url_encode(key) + "=" + ERB::Util.url_encode(value)
|
71
|
+
arr << str
|
72
|
+
end
|
73
|
+
end
|
74
|
+
arr.sort!
|
75
|
+
arr.join("&")
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.get_md5_from_file(file_name, content_length, buf_size=8192)
|
79
|
+
|
80
|
+
md5 = Digest::MD5.new
|
81
|
+
left_size = content_length
|
82
|
+
File.open(file_name, 'rb') do |io|
|
83
|
+
bytes_to_read = left_size > buf_size ? buf_size : left_size
|
84
|
+
until left_size <= 0
|
85
|
+
md5.update(io.read(bytes_to_read))
|
86
|
+
left_size -= bytes_to_read
|
87
|
+
end
|
88
|
+
end
|
89
|
+
md5.base64digest
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.generate_response(headers, body, return_body)
|
93
|
+
return body if return_body
|
94
|
+
return generate_headers(headers) if body.empty?
|
95
|
+
ret = JSON.parse(body)
|
96
|
+
return ret
|
97
|
+
rescue JSON::ParserError
|
98
|
+
return body
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.generate_headers(headers)
|
102
|
+
user_metadata = {}
|
103
|
+
|
104
|
+
resp_headers = headers.inject({}) do |ret, (k, v)|
|
105
|
+
key = k.to_s.tr('_', '-')
|
106
|
+
if key.start_with?(Http::BCE_USER_METADATA_PREFIX)
|
107
|
+
key.slice!(Http::BCE_USER_METADATA_PREFIX)
|
108
|
+
user_metadata[key] = v
|
109
|
+
elsif key.downcase == Http::ETAG.downcase
|
110
|
+
ret[key] = v.delete('\"')
|
111
|
+
elsif key.downcase == Http::CONTENT_LENGTH.downcase
|
112
|
+
ret[key] = v.to_i
|
113
|
+
else
|
114
|
+
ret[key] = v
|
115
|
+
end
|
116
|
+
ret
|
117
|
+
end
|
118
|
+
resp_headers['user-metadata'] = user_metadata unless user_metadata.empty?
|
119
|
+
resp_headers
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
@@ -0,0 +1,376 @@
|
|
1
|
+
# Copyright 2017 Baidu, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
4
|
+
# the License. You may obtain a copy of the License at
|
5
|
+
#
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
7
|
+
#
|
8
|
+
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
9
|
+
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
10
|
+
# specific language governing permissions and limitations under the License.
|
11
|
+
|
12
|
+
# Samples for bos client.
|
13
|
+
|
14
|
+
$LOAD_PATH.unshift(File.expand_path("../../../lib", __FILE__))
|
15
|
+
|
16
|
+
require 'baidubce/services/bos/bos_client'
|
17
|
+
|
18
|
+
include Baidubce
|
19
|
+
|
20
|
+
# debug
|
21
|
+
credentials = Auth::BceCredentials.new(
|
22
|
+
# "your ak",
|
23
|
+
# "your sk"
|
24
|
+
)
|
25
|
+
|
26
|
+
conf = BceClientConfiguration.new(
|
27
|
+
credentials,
|
28
|
+
"http://bj.bcebos.com"
|
29
|
+
)
|
30
|
+
|
31
|
+
client = Services::BosClient.new(conf)
|
32
|
+
|
33
|
+
bucket_name = "ruby-test-bucket"
|
34
|
+
|
35
|
+
# log config
|
36
|
+
Log.set_log_file("./test.log")
|
37
|
+
Log.set_log_level(Logger::DEBUG)
|
38
|
+
|
39
|
+
def demo(msg)
|
40
|
+
puts "--------- #{msg} --------"
|
41
|
+
puts
|
42
|
+
yield
|
43
|
+
puts "----------- end --------------"
|
44
|
+
puts
|
45
|
+
end
|
46
|
+
|
47
|
+
demo "list buckets" do
|
48
|
+
puts client.list_buckets()
|
49
|
+
end
|
50
|
+
|
51
|
+
demo "delete bucket" do
|
52
|
+
# Only can delete the bucket you are owner and it is empty.
|
53
|
+
# puts client.delete_bucket("test-bucket") if client.does_bucket_exist("test-bucket")
|
54
|
+
end
|
55
|
+
|
56
|
+
demo "create bucket" do
|
57
|
+
puts client.create_bucket(bucket_name) unless client.does_bucket_exist(bucket_name)
|
58
|
+
end
|
59
|
+
|
60
|
+
demo "get bucket location" do
|
61
|
+
puts client.get_bucket_location(bucket_name)
|
62
|
+
end
|
63
|
+
|
64
|
+
demo "set/get bucket acl" do
|
65
|
+
client.set_bucket_canned_acl(bucket_name, "private")
|
66
|
+
puts "before set bucket acl"
|
67
|
+
puts client.get_bucket_acl(bucket_name)
|
68
|
+
|
69
|
+
acl = [{'grantee' => [{'id' => 'b124deeaf6f641c9ac27700b41a350a8'},
|
70
|
+
{'id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'}],
|
71
|
+
'permission' => ['FULL_CONTROL'],
|
72
|
+
'condition' => {
|
73
|
+
'referer' => {
|
74
|
+
'stringLike' => ['http://www.abc.com/*'],
|
75
|
+
'stringEquals' => ['http://www.abc.com']
|
76
|
+
},
|
77
|
+
"ipAddress" => [
|
78
|
+
'192.168.0.0/16',
|
79
|
+
'192.169.0.*',
|
80
|
+
'192.170.0.5'
|
81
|
+
]
|
82
|
+
}
|
83
|
+
}]
|
84
|
+
client.set_bucket_acl(bucket_name, acl)
|
85
|
+
puts "after set bucket acl"
|
86
|
+
puts client.get_bucket_acl(bucket_name)
|
87
|
+
end
|
88
|
+
|
89
|
+
demo "put/get bucket lifecycle" do
|
90
|
+
puts "before put bucket lifecycle"
|
91
|
+
lifecycle = [
|
92
|
+
{
|
93
|
+
id: "rule-id",
|
94
|
+
status: "enabled",
|
95
|
+
resource: [
|
96
|
+
"ruby-test-bucket/prefix/*"
|
97
|
+
],
|
98
|
+
condition: {
|
99
|
+
time: {
|
100
|
+
dateGreaterThan: "2016-09-07T00:00:00Z"
|
101
|
+
}
|
102
|
+
},
|
103
|
+
action: {
|
104
|
+
name: "DeleteObject"
|
105
|
+
}
|
106
|
+
}
|
107
|
+
]
|
108
|
+
|
109
|
+
client.put_bucket_lifecycle(bucket_name, lifecycle)
|
110
|
+
puts "after put bucket lifecycle"
|
111
|
+
puts client.get_bucket_lifecycle(bucket_name)
|
112
|
+
|
113
|
+
puts "after delete bucket lifecycle"
|
114
|
+
puts client.delete_bucket_lifecycle(bucket_name)
|
115
|
+
end
|
116
|
+
|
117
|
+
demo "put/get bucket cors" do
|
118
|
+
puts "before put bucket cors"
|
119
|
+
cors = [
|
120
|
+
{
|
121
|
+
allowedOrigins: [
|
122
|
+
"http://www.example.com",
|
123
|
+
"www.example2.com"
|
124
|
+
],
|
125
|
+
allowedMethods: [
|
126
|
+
"GET",
|
127
|
+
"HEAD",
|
128
|
+
"DELETE"
|
129
|
+
],
|
130
|
+
allowedHeaders: [
|
131
|
+
"Authorization",
|
132
|
+
"x-bce-test",
|
133
|
+
"x-bce-test2"
|
134
|
+
],
|
135
|
+
allowedExposeHeaders: [
|
136
|
+
"user-custom-expose-header"
|
137
|
+
],
|
138
|
+
maxAgeSeconds: 3600
|
139
|
+
}
|
140
|
+
]
|
141
|
+
|
142
|
+
client.put_bucket_cors(bucket_name, cors)
|
143
|
+
puts "after put bucket cors"
|
144
|
+
puts client.get_bucket_cors(bucket_name)
|
145
|
+
|
146
|
+
puts "after delete bucket cors"
|
147
|
+
puts client.delete_bucket_cors(bucket_name)
|
148
|
+
end
|
149
|
+
|
150
|
+
demo "put/get bucket logging" do
|
151
|
+
|
152
|
+
client.put_bucket_logging(bucket_name, bucket_name, "prefix")
|
153
|
+
puts "after put bucket logging"
|
154
|
+
puts client.get_bucket_logging(bucket_name)
|
155
|
+
|
156
|
+
puts "after delete bucket logging"
|
157
|
+
puts client.delete_bucket_logging(bucket_name)
|
158
|
+
end
|
159
|
+
|
160
|
+
demo "put/get bucket storage_class" do
|
161
|
+
puts "before put bucket storage_class"
|
162
|
+
puts client.get_bucket_storageclass(bucket_name)
|
163
|
+
|
164
|
+
client.put_bucket_storageclass(bucket_name, "STANDARD_IA")
|
165
|
+
puts "after put bucket storage_class"
|
166
|
+
puts client.get_bucket_storageclass(bucket_name)
|
167
|
+
|
168
|
+
client.put_bucket_storageclass(bucket_name, "STANDARD")
|
169
|
+
end
|
170
|
+
|
171
|
+
demo "put object" do
|
172
|
+
|
173
|
+
user_metadata = { "key1" => "value1" }
|
174
|
+
options = { Http::CONTENT_TYPE => 'string',
|
175
|
+
"key1" => "value1",
|
176
|
+
'Content-Disposition' => 'inline',
|
177
|
+
'user-metadata' => user_metadata
|
178
|
+
}
|
179
|
+
|
180
|
+
client.put_object_from_string(bucket_name, "obj.txt", "obj", options)
|
181
|
+
puts client.get_object_as_string(bucket_name, "obj.txt")
|
182
|
+
puts client.get_object_to_file(bucket_name, "obj.txt", "obj_file.txt")
|
183
|
+
|
184
|
+
# put cold storage class object
|
185
|
+
file_path = "obj.txt"
|
186
|
+
client.put_object_from_file(bucket_name, "obj_cold.txt", file_path, 'x-bce-storage-class' => 'COLD')
|
187
|
+
puts client.get_object_as_string(bucket_name, "obj_cold.txt")
|
188
|
+
|
189
|
+
# put object with content_length
|
190
|
+
file_path = "obj.txt"
|
191
|
+
client.put_object_from_file(bucket_name, "obj_with_content_length.txt", file_path, 'Content-Length' => 2)
|
192
|
+
puts client.get_object_as_string(bucket_name, "obj_with_content_length.txt")
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
demo "list objects" do
|
197
|
+
|
198
|
+
options = { prefix: 'obj',
|
199
|
+
maxKeys: 10,
|
200
|
+
delimiter: '',
|
201
|
+
marker: ''
|
202
|
+
}
|
203
|
+
puts client.list_objects(bucket_name, options)
|
204
|
+
end
|
205
|
+
|
206
|
+
demo "get object" do
|
207
|
+
puts client.put_object_from_string(bucket_name, "obj.txt", "object%123456")
|
208
|
+
puts client.get_object_as_string(bucket_name, "obj.txt", [0,2])
|
209
|
+
puts client.get_object_meta_data(bucket_name, "obj.txt")
|
210
|
+
end
|
211
|
+
|
212
|
+
demo "append object" do
|
213
|
+
puts client.append_object_from_string(bucket_name, "append.txt", "append")
|
214
|
+
puts client.get_object_as_string(bucket_name, "append.txt")
|
215
|
+
puts client.append_object_from_string(bucket_name, "append.txt", "append", 'offset' => 6)
|
216
|
+
puts client.get_object_as_string(bucket_name, "append.txt")
|
217
|
+
end
|
218
|
+
|
219
|
+
demo "delete object" do
|
220
|
+
object_key = "delete_obj.txt"
|
221
|
+
puts client.put_object_from_string(bucket_name, object_key, "object%123456")
|
222
|
+
puts client.get_object_as_string(bucket_name, object_key)
|
223
|
+
puts client.delete_object(bucket_name, object_key)
|
224
|
+
end
|
225
|
+
|
226
|
+
demo "delete multiple objects" do
|
227
|
+
object_list = ["multi_obj0.txt", "multi_obj1.txt","multi_obj2.txt"]
|
228
|
+
object_list.each { |key| client.put_object_from_string(bucket_name, key, "content") }
|
229
|
+
object_list << "other.txt"
|
230
|
+
puts client.delete_multiple_objects(bucket_name, object_list)
|
231
|
+
end
|
232
|
+
|
233
|
+
demo "generate pre signed url" do
|
234
|
+
|
235
|
+
options = { 'expiration_in_seconds' => 360,
|
236
|
+
'timestamp' => Time.now.to_i,
|
237
|
+
'headers_to_sign' => ["host", "content-md5", "content-length"]
|
238
|
+
}
|
239
|
+
|
240
|
+
puts client.generate_pre_signed_url(bucket_name, 'obj.txt', options)
|
241
|
+
end
|
242
|
+
|
243
|
+
demo "copy object" do
|
244
|
+
user_metadata = { "key1" => "value1" }
|
245
|
+
|
246
|
+
options = { Http::CONTENT_TYPE => 'string',
|
247
|
+
Http::CONTENT_MD5 => 'kkkkkkkk',
|
248
|
+
'user-metadata' => user_metadata
|
249
|
+
}
|
250
|
+
client.copy_object(bucket_name, "obj.txt", bucket_name, 'obj2.txt', options)
|
251
|
+
puts client.get_object_meta_data(bucket_name, "obj2.txt")
|
252
|
+
end
|
253
|
+
|
254
|
+
demo "set/get/delete object acl" do
|
255
|
+
# puts "before set object acl"
|
256
|
+
key = "obj.txt"
|
257
|
+
# client.get_object_acl(bucket_name, key)
|
258
|
+
acl = [{'grantee' => [{'id' => 'b124deeaf6f641c9ac27700b41a350a8'},
|
259
|
+
{'id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'}],
|
260
|
+
'permission' => ['FULL_CONTROL']}]
|
261
|
+
|
262
|
+
puts "after set object canned x-bce-acl: private"
|
263
|
+
client.set_object_canned_acl(bucket_name, key, 'x-bce-acl' => 'private')
|
264
|
+
puts client.get_object_acl(bucket_name, key)
|
265
|
+
|
266
|
+
puts "after set object canned x-bce-grant-read"
|
267
|
+
id_permission = "id=\"6c47a952db4444c5a097b41be3f24c94\",id=\"8c47a952db4444c5a097b41be3f24c94\",id=\"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\""
|
268
|
+
client.set_object_canned_acl(bucket_name, key, 'x-bce-grant-read' => id_permission)
|
269
|
+
puts client.get_object_acl(bucket_name, key)
|
270
|
+
|
271
|
+
puts "after set object body acl"
|
272
|
+
client.set_object_acl(bucket_name, key, acl)
|
273
|
+
puts client.get_object_acl(bucket_name, key)
|
274
|
+
client.delete_object_acl(bucket_name, key)
|
275
|
+
end
|
276
|
+
|
277
|
+
# create a 18MB file for multi upload
|
278
|
+
multi_file = "multi_upload.txt"
|
279
|
+
|
280
|
+
demo "multi-upload" do
|
281
|
+
# step 1: init multi-upload
|
282
|
+
key = "multi_file"
|
283
|
+
upload_id = client.initiate_multipart_upload(bucket_name, key)["uploadId"]
|
284
|
+
# step 2: upload file part by part
|
285
|
+
left_size = File.open(multi_file, "r").size()
|
286
|
+
offset = 0
|
287
|
+
part_number = 1
|
288
|
+
part_list = []
|
289
|
+
|
290
|
+
while left_size > 0 do
|
291
|
+
part_size = 5 * 1024 * 1024
|
292
|
+
if left_size < part_size
|
293
|
+
part_size = left_size
|
294
|
+
end
|
295
|
+
|
296
|
+
puts "offset: #{offset}, part_number: #{part_number}, part_list: #{part_list}, left_size: #{left_size}, part_size: #{part_size}"
|
297
|
+
response = client.upload_part_from_file(
|
298
|
+
bucket_name, key, upload_id, part_number, part_size, multi_file, offset)
|
299
|
+
left_size -= part_size
|
300
|
+
offset += part_size
|
301
|
+
# your should store every part number and etag to invoke complete multi-upload
|
302
|
+
part_list << {
|
303
|
+
"partNumber" => part_number,
|
304
|
+
"eTag" => response['etag']
|
305
|
+
}
|
306
|
+
part_number += 1
|
307
|
+
end
|
308
|
+
|
309
|
+
# list parts
|
310
|
+
puts "------------------ list parts ---------------"
|
311
|
+
puts client.list_parts(bucket_name, key, upload_id)
|
312
|
+
|
313
|
+
# SuperFile step 3: complete multi-upload
|
314
|
+
user_metadata = { "key1" => "value1" }
|
315
|
+
options = {
|
316
|
+
'user-metadata' => user_metadata
|
317
|
+
}
|
318
|
+
|
319
|
+
client.complete_multipart_upload(bucket_name, key, upload_id, part_list, options)
|
320
|
+
|
321
|
+
end
|
322
|
+
|
323
|
+
demo "multi-copy" do
|
324
|
+
# step 1: init multi-upload
|
325
|
+
key = "multi_file"
|
326
|
+
upload_id = client.initiate_multipart_upload(bucket_name, key+"_copy")["uploadId"]
|
327
|
+
# step 2: copy a object part by part
|
328
|
+
left_size = client.get_object_meta_data(bucket_name, key)['content-length']
|
329
|
+
offset = 0
|
330
|
+
part_number = 1
|
331
|
+
part_list = []
|
332
|
+
|
333
|
+
while left_size > 0 do
|
334
|
+
part_size = 5 * 1024 * 1024
|
335
|
+
if left_size < part_size
|
336
|
+
part_size = left_size
|
337
|
+
end
|
338
|
+
|
339
|
+
puts "offset: #{offset}, part_number: #{part_number}, part_list: #{part_list}, left_size: #{left_size}, part_size: #{part_size}"
|
340
|
+
response = client.upload_part_copy(
|
341
|
+
bucket_name, key, bucket_name, key+"_copy", upload_id, part_number, part_size, offset)
|
342
|
+
puts response
|
343
|
+
left_size -= part_size
|
344
|
+
offset += part_size
|
345
|
+
# your should store every part number and etag to invoke complete multi-upload
|
346
|
+
part_list << {
|
347
|
+
"partNumber" => part_number,
|
348
|
+
"eTag" => response["eTag"]
|
349
|
+
}
|
350
|
+
part_number += 1
|
351
|
+
end
|
352
|
+
|
353
|
+
# list parts
|
354
|
+
puts "------------------ list parts ---------------"
|
355
|
+
puts client.list_parts(bucket_name, key+"_copy", upload_id)
|
356
|
+
|
357
|
+
# SuperFile step 3: complete multi-upload
|
358
|
+
|
359
|
+
user_metadata = { "key1" => "value1" }
|
360
|
+
options = {
|
361
|
+
'user-metadata' => user_metadata
|
362
|
+
}
|
363
|
+
client.complete_multipart_upload(bucket_name, key+"_copy", upload_id, part_list, options)
|
364
|
+
end
|
365
|
+
|
366
|
+
demo "abort-multi-upload" do
|
367
|
+
key = "multi_file"
|
368
|
+
upload_id_abort = client.initiate_multipart_upload(bucket_name, key + "_abort")["uploadId"]
|
369
|
+
|
370
|
+
# list multi-uploads
|
371
|
+
puts "------------------ list multi-uploads ---------------"
|
372
|
+
puts client.list_multipart_uploads(bucket_name)
|
373
|
+
|
374
|
+
# abort multi-upload
|
375
|
+
client.abort_multipart_upload(bucket_name, key + "_abort", upload_id_abort)
|
376
|
+
end
|