qiniu_jxb_fix 6.4.2

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 (50) hide show
  1. data/.gitignore +18 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +12 -0
  4. data/CHANGELOG.md +146 -0
  5. data/Gemfile +8 -0
  6. data/Gemfile.lock +44 -0
  7. data/LICENSE +22 -0
  8. data/README.md +47 -0
  9. data/Rakefile +21 -0
  10. data/docs/README.md +790 -0
  11. data/lib/qiniu/abstract.rb +22 -0
  12. data/lib/qiniu/adt.rb +46 -0
  13. data/lib/qiniu/auth.rb +255 -0
  14. data/lib/qiniu/config.rb +60 -0
  15. data/lib/qiniu/exceptions.rb +120 -0
  16. data/lib/qiniu/fop.rb +4 -0
  17. data/lib/qiniu/http.rb +137 -0
  18. data/lib/qiniu/image.rb +38 -0
  19. data/lib/qiniu/log.rb +15 -0
  20. data/lib/qiniu/management.rb +166 -0
  21. data/lib/qiniu/misc.rb +35 -0
  22. data/lib/qiniu/pfop.rb +124 -0
  23. data/lib/qiniu/resumable_upload.rb +319 -0
  24. data/lib/qiniu/storage.rb +5 -0
  25. data/lib/qiniu/tokens/access_token.rb +23 -0
  26. data/lib/qiniu/tokens/download_token.rb +36 -0
  27. data/lib/qiniu/tokens/qbox_token.rb +38 -0
  28. data/lib/qiniu/tokens/upload_token.rb +57 -0
  29. data/lib/qiniu/upload.rb +134 -0
  30. data/lib/qiniu/utils.rb +109 -0
  31. data/lib/qiniu/version.rb +17 -0
  32. data/lib/qiniu-rs.rb +2 -0
  33. data/lib/qiniu.rb +209 -0
  34. data/qiniu.gemspec +29 -0
  35. data/rails3/Gemfile +4 -0
  36. data/rails3/qiniu.gemspec +29 -0
  37. data/spec/qiniu/abstract_spec.rb +30 -0
  38. data/spec/qiniu/auth_spec.rb +74 -0
  39. data/spec/qiniu/image_logo_for_test.png +0 -0
  40. data/spec/qiniu/image_spec.rb +80 -0
  41. data/spec/qiniu/management_spec.rb +163 -0
  42. data/spec/qiniu/misc_spec.rb +53 -0
  43. data/spec/qiniu/pfop_spec.rb +80 -0
  44. data/spec/qiniu/qiniu_spec.rb +321 -0
  45. data/spec/qiniu/tokens/qbox_token_spec.rb +29 -0
  46. data/spec/qiniu/upload_spec.rb +301 -0
  47. data/spec/qiniu/utils_spec.rb +49 -0
  48. data/spec/qiniu/version_spec.rb +10 -0
  49. data/spec/spec_helper.rb +19 -0
  50. metadata +222 -0
@@ -0,0 +1,166 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # vim: sw=2 ts=2
3
+
4
+ require 'qiniu/adt'
5
+ require 'qiniu/http'
6
+
7
+ module Qiniu
8
+ module Storage
9
+ class ListPolicy
10
+ include ADT::Policy
11
+
12
+ private
13
+ def initialize(bucket,
14
+ limit = 1000,
15
+ prefix = '',
16
+ delimiter = '')
17
+ @bucket = bucket
18
+ @limit = limit
19
+ @prefix = prefix
20
+ @delimiter = delimiter
21
+ end # initialize
22
+
23
+ public
24
+ PARAMS = {
25
+ # 字符串类型参数
26
+ :bucket => "bucket",
27
+ :prefix => "prefix",
28
+ :delimiter => "delimiter",
29
+ :marker => "marker",
30
+
31
+ # 数值类型参数
32
+ :limit => "limit"
33
+ } # PARAMS
34
+
35
+ PARAMS.each_pair do |key, fld|
36
+ attr_accessor key
37
+ end
38
+
39
+ def params
40
+ return PARAMS
41
+ end # params
42
+
43
+ alias :to_s :to_query_string
44
+ end # class ListPolicy
45
+
46
+ class << self
47
+ include Utils
48
+
49
+ public
50
+ def buckets
51
+ url = Config.settings[:rs_host] + '/buckets'
52
+ return HTTP.management_post(url)
53
+ end # buckets
54
+
55
+ def stat(bucket, key)
56
+ url = Config.settings[:rs_host] + '/stat/' + encode_entry_uri(bucket, key)
57
+ return HTTP.management_post(url)
58
+ end # stat
59
+
60
+ def get(bucket, key, save_as = nil, expires_in = nil, version = nil)
61
+ url = Config.settings[:rs_host] + '/get/' + encode_entry_uri(bucket, key)
62
+ url += '/base/' + version unless version.nil?
63
+ url += '/attName/' + Utils.urlsafe_base64_encode(save_as) unless save_as.nil?
64
+ url += '/expires/' + expires_in.to_s if !expires_in.nil? && expires_in > 0
65
+ return HTTP.management_post(url)
66
+ end # get
67
+
68
+ def copy(source_bucket, source_key, target_bucket, target_key)
69
+ uri = _generate_cp_or_mv_opstr('copy', source_bucket, source_key, target_bucket, target_key)
70
+ url = Config.settings[:rs_host] + uri
71
+ return HTTP.management_post(url)
72
+ end # copy
73
+
74
+ def move(source_bucket, source_key, target_bucket, target_key)
75
+ uri = _generate_cp_or_mv_opstr('move', source_bucket, source_key, target_bucket, target_key)
76
+ url = Config.settings[:rs_host] + uri
77
+ return HTTP.management_post(url)
78
+ end # move
79
+
80
+ def delete(bucket, key)
81
+ url = Config.settings[:rs_host] + '/delete/' + encode_entry_uri(bucket, key)
82
+ return HTTP.management_post(url)
83
+ end # delete
84
+
85
+ def batch(command, bucket, keys)
86
+ execs = []
87
+ keys.each do |key|
88
+ encoded_uri = encode_entry_uri(bucket, key)
89
+ execs << "op=/#{command}/#{encoded_uri}"
90
+ end
91
+ url = Config.settings[:rs_host] + "/batch"
92
+ return HTTP.management_post(url, execs.join("&"))
93
+ end # batch
94
+
95
+ def batch_get(bucket, keys)
96
+ batch("get", bucket, keys)
97
+ end # batch_get
98
+
99
+ def batch_stat(bucket, keys)
100
+ batch("stat", bucket, keys)
101
+ end # batch_stat
102
+
103
+ def batch_copy(*args)
104
+ _batch_cp_or_mv('copy', args)
105
+ end # batch_copy
106
+
107
+ def batch_move(*args)
108
+ _batch_cp_or_mv('move', args)
109
+ end # batch_move
110
+
111
+ def batch_delete(bucket, keys)
112
+ batch("delete", bucket, keys)
113
+ end # batch_delete
114
+
115
+ def save_as(bucket, key, source_url, op_params_string)
116
+ encoded_uri = encode_entry_uri(bucket, key)
117
+ save_as_string = '/save-as/' + encoded_uri
118
+ new_url = source_url + '?' + op_params_string + save_as_string
119
+ return HTTP.management_post(new_url)
120
+ end # save_as
121
+
122
+ def image_mogrify_save_as(bucket, key, source_image_url, options)
123
+ mogrify_params_string = Fop::Image.generate_mogrify_params_string(options)
124
+ save_as(bucket, key, source_image_url, mogrify_params_string)
125
+ end # image_mogrify_save_as
126
+
127
+ def list(list_policy)
128
+ url = Config.settings[:rsf_host] + '/list?' + list_policy.to_query_string()
129
+
130
+ resp_code, resp_body, resp_headers = HTTP.management_post(url)
131
+ if resp_code == 0 || resp_code > 299 then
132
+ has_more = false
133
+ return resp_code, resp_body, resp_headers, has_more, list_policy
134
+ end
135
+
136
+ has_more = (resp_body['marker'].is_a?(String) && resp_body['marker'] != '')
137
+ if has_more then
138
+ new_list_policy = list_policy.clone()
139
+ new_list_policy.marker = resp_body['marker']
140
+ else
141
+ new_list_policy = list_policy
142
+ end
143
+
144
+ return resp_code, resp_body, resp_headers, has_more, new_list_policy
145
+ end # list
146
+
147
+ private
148
+
149
+ def _generate_cp_or_mv_opstr(command, source_bucket, source_key, target_bucket, target_key)
150
+ source_encoded_entry_uri = encode_entry_uri(source_bucket, source_key)
151
+ target_encoded_entry_uri = encode_entry_uri(target_bucket, target_key)
152
+ %Q(/#{command}/#{source_encoded_entry_uri}/#{target_encoded_entry_uri})
153
+ end # _generate_cp_or_mv_opstr
154
+
155
+ def _batch_cp_or_mv(command, *op_args)
156
+ execs = []
157
+ op_args.each do |e|
158
+ execs << 'op=' + _generate_cp_or_mv_opstr(command, e[0], e[1], e[2], e[3]) if e.size == 4
159
+ end
160
+ url = Config.settings[:rs_host] + "/batch"
161
+ return HTTP.management_post(url, execs.join("&"))
162
+ end # _batch_cp_or_mv
163
+
164
+ end # class << self
165
+ end # module Storage
166
+ end # module Qiniu
data/lib/qiniu/misc.rb ADDED
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'qiniu/http'
4
+
5
+ module Qiniu
6
+ module Misc
7
+ class << self
8
+ def set_protected(bucket, protected_mode)
9
+ url = Config.settings[:pub_host] + %Q(/accessMode/#{bucket}/mode/#{protected_mode})
10
+ return HTTP.management_post(url)
11
+ end # set_protected
12
+
13
+ def set_separator(bucket, separator)
14
+ encoded_separator = Utils.urlsafe_base64_encode(separator)
15
+ url = Config.settings[:pub_host] + %Q(/separator/#{bucket}/sep/#{encoded_separator})
16
+ return HTTP.management_post(url)
17
+ end # set_separator
18
+
19
+ def set_style(bucket, name, style)
20
+ encoded_name = Utils.urlsafe_base64_encode(name)
21
+ encoded_style = Utils.urlsafe_base64_encode(style)
22
+ url = Config.settings[:pub_host] + %Q(/style/#{bucket}/name/#{encoded_name}/style/#{encoded_style})
23
+ return HTTP.management_post(url)
24
+ end # set_style
25
+
26
+ def unset_style(bucket, name)
27
+ encoded_name = Utils.urlsafe_base64_encode(name)
28
+ url = Config.settings[:pub_host] + %Q(/unstyle/#{bucket}/name/#{encoded_name})
29
+ return HTTP.management_post(url)
30
+ end # unset_style
31
+ end # class << self
32
+
33
+ end # module Misc
34
+ end # module Qiniu
35
+
data/lib/qiniu/pfop.rb ADDED
@@ -0,0 +1,124 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # vim: sw=2 ts=2
3
+
4
+ require 'qiniu/adt'
5
+ require 'qiniu/http'
6
+
7
+ module Qiniu
8
+ module Fop
9
+ module Persistance
10
+
11
+ class PfopPolicy
12
+ include ADT::Policy
13
+
14
+ private
15
+ def initialize(bucket,
16
+ key,
17
+ fops,
18
+ notify_url)
19
+ @bucket = bucket
20
+ @key = key
21
+ @notify_url = notify_url
22
+
23
+ self.fops!(fops)
24
+ end # initialize
25
+
26
+ public
27
+ PARAMS = {
28
+ # 字符串类型参数
29
+ :bucket => "bucket",
30
+ :key => "key",
31
+ :fops => "fops",
32
+ :notify_url => "notifyURL",
33
+ :pipeline => "pipeline",
34
+
35
+ # 数值类型参数
36
+ :force => "force"
37
+ } # PARAMS
38
+
39
+ PARAMS.each_pair do |key, fld|
40
+ attr_accessor key
41
+ end
42
+
43
+ def params
44
+ return PARAMS
45
+ end # params
46
+
47
+ def fops! (fops)
48
+ if fops.is_a?(Hash) then
49
+ fops = fops.values
50
+ end
51
+
52
+ if fops.is_a?(Array) then
53
+ new_fops = []
54
+ fops.each do |v|
55
+ if v.is_a?(ApiSpecification) then
56
+ new_fops.push(v.to_s)
57
+ end
58
+ end
59
+
60
+ @fops = new_fops.join(";")
61
+ else
62
+ @fops = fops.to_s
63
+ end
64
+ end # fops!
65
+
66
+ def force!
67
+ @force = 1
68
+ end # force!
69
+
70
+ alias :to_s :to_json
71
+ end # class PfopPolicy
72
+
73
+ class << self
74
+
75
+ API_HOST = 'http://api.qiniu.com'
76
+
77
+ PFOP_URL = API_HOST + '/pfop/'
78
+
79
+ def pfop (args)
80
+ ### 生成fop指令串
81
+ if args.is_a?(PfopPolicy) then
82
+ # PfopPolicy的各个字段按固定顺序组织
83
+ body = args.to_query_string()
84
+ elsif args.is_a?(Hash) then
85
+ # 无法保证固定字段顺序
86
+ body = HTTP.generate_query_string(args)
87
+ else
88
+ # 由调用者保证固定字段顺序
89
+ body = args.to_s
90
+ end
91
+
92
+ ### 发送请求
93
+ return HTTP.management_post(PFOP_URL, body)
94
+ end # pfop
95
+
96
+ PREFOP_URL = API_HOST + '/status/get/prefop?id='
97
+
98
+ def prefop (persistent_id)
99
+ ### 抽取persistentId
100
+ if persistent_id.is_a?(Hash) then
101
+ pid = persistent_id['persistentId']
102
+ else
103
+ pid = persistent_id.to_s
104
+ end
105
+
106
+ ### 发送请求
107
+ url = PREFOP_URL + pid
108
+ return HTTP.api_get(url)
109
+ end # prefop
110
+
111
+ def generate_p1_url (url, fop)
112
+ # 如果fop是ApiSpecification,则各字段按固定顺序组织,保证一致性
113
+ # 否则由调用者保证固定字段顺序
114
+ fop = CGI.escape(fop.to_s).gsub('+', '%20')
115
+
116
+ ### 生成url
117
+ return url + '?p/1/' + fop
118
+ end # generate_pl_url
119
+
120
+ end # class << self
121
+
122
+ end # module Persistance
123
+ end # module Fop
124
+ end # module Qiniu
@@ -0,0 +1,319 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'zlib'
4
+ require 'yaml'
5
+ require 'tmpdir'
6
+ require 'fileutils'
7
+ require 'mime/types'
8
+ require 'digest/sha1'
9
+ require 'qiniu/abstract'
10
+ require 'qiniu/exceptions'
11
+
12
+ module Qiniu
13
+ module Storage
14
+
15
+ module AbstractClass
16
+ class ChunkProgressNotifier
17
+ include Qiniu::Abstract
18
+ abstract_methods :notify
19
+ # def notify(block_index, block_put_progress); end
20
+ end
21
+
22
+ class BlockProgressNotifier
23
+ include Qiniu::Abstract
24
+ abstract_methods :notify
25
+ # def notify(block_index, checksum); end
26
+ end
27
+ end # module AbstractClass
28
+
29
+ class ChunkProgressNotifier < AbstractClass::ChunkProgressNotifier
30
+ def notify(index, progress)
31
+ logmsg = "chunk #{progress[:offset]/Config.settings[:chunk_size]} in block #{index} successfully uploaded.\n" + progress.to_s
32
+ Utils.debug(logmsg)
33
+ end
34
+ end # class ChunkProgressNotifier
35
+
36
+ class BlockProgressNotifier < AbstractClass::BlockProgressNotifier
37
+ def notify(index, checksum)
38
+ Utils.debug "block #{index}: {ctx: #{checksum}} successfully uploaded."
39
+ Utils.debug "block #{index}: {checksum: #{checksum}} successfully uploaded."
40
+ end
41
+ end # class BlockProgressNotifier
42
+
43
+ class << self
44
+ include Utils
45
+
46
+ def resumable_upload_with_token(uptoken,
47
+ local_file,
48
+ bucket,
49
+ key = nil,
50
+ mime_type = nil,
51
+ custom_meta = nil,
52
+ customer = nil,
53
+ callback_params = nil,
54
+ rotate = nil)
55
+ begin
56
+ ifile = File.open(local_file, 'rb')
57
+ fh = FileData.new(ifile)
58
+ fsize = fh.data_size
59
+ key = Digest::SHA1.hexdigest(local_file + fh.mtime.to_s) if key.nil?
60
+ if mime_type.nil? || mime_type.empty?
61
+ mime = MIME::Types.type_for local_file
62
+ mime_type = mime.empty? ? 'application/octet-stream' : mime[0].content_type
63
+ end
64
+ code, data = _resumable_upload(uptoken, fh, fsize, bucket, key, mime_type, custom_meta, customer, callback_params, rotate)
65
+ [code, data]
66
+ ensure
67
+ ifile.close unless ifile.nil?
68
+ end
69
+ end # resumable_upload_with_token
70
+
71
+ private
72
+
73
+ class FileData
74
+ attr_accessor :fh
75
+ def initialize(fh)
76
+ @fh = fh
77
+ end
78
+ def data_size
79
+ @fh.stat.size
80
+ end
81
+ def get_data(offset, length)
82
+ @fh.seek(offset)
83
+ @fh.read(length)
84
+ end
85
+ def path
86
+ @fh.path
87
+ end
88
+ def mtime
89
+ @fh.mtime
90
+ end
91
+ #delegate :path, :mtime, :to => :fh
92
+ end # class FileData
93
+
94
+ def _new_block_put_progress_data
95
+ {:ctx => nil, :offset => 0, :restsize => nil, :status_code => nil, :host => nil}
96
+ end # _new_block_put_progress_data
97
+
98
+ def _call_binary_with_token(uptoken, url, data, content_type = nil, retry_times = 0)
99
+ options = {
100
+ :headers => {
101
+ :content_type => 'application/octet-stream',
102
+ 'Authorization' => 'UpToken ' + uptoken
103
+ }
104
+ }
105
+ if !content_type.nil? && !content_type.empty? then
106
+ options[:headers][:content_type] = content_type
107
+ end
108
+
109
+ code, data, raw_headers = HTTP.api_post(url, data, options)
110
+ unless HTTP.is_response_ok?(code)
111
+ retry_times += 1
112
+ if Config.settings[:auto_reconnect] && retry_times < Config.settings[:max_retry_times]
113
+ return _call_binary_with_token(uptoken, url, data, options[:content_type], retry_times)
114
+ end
115
+ end
116
+ return code, data, raw_headers
117
+ end # _call_binary_with_token
118
+
119
+ def _mkblock(uptoken, block_size, body)
120
+ url = Config.settings[:up_host] + "/mkblk/#{block_size}"
121
+ _call_binary_with_token(uptoken, url, body)
122
+ end # _mkblock
123
+
124
+ def _putblock(uphost, uptoken, ctx, offset, body)
125
+ url = uphost + "/bput/#{ctx}/#{offset}"
126
+ _call_binary_with_token(uptoken, url, body)
127
+ end # _putblock
128
+
129
+ def _resumable_put_block(uptoken,
130
+ fh,
131
+ block_index,
132
+ block_size,
133
+ chunk_size,
134
+ progress,
135
+ retry_times,
136
+ notifier)
137
+ code, data = 0, {}
138
+ fpath = fh.path
139
+
140
+ # this block has never been uploaded.
141
+ if progress[:ctx] == nil || progress[:ctx].empty?
142
+ progress[:offset] = 0
143
+ progress[:restsize] = block_size
144
+ # choose the smaller one
145
+ body_length = [block_size, chunk_size].min
146
+ for i in 1..retry_times
147
+ seek_pos = block_index*Config.settings[:block_size]
148
+ body = fh.get_data(seek_pos, body_length)
149
+ result_length = body.length
150
+ if result_length != body_length
151
+ raise FileSeekReadError.new(fpath, block_index, seek_pos, body_length, result_length)
152
+ end
153
+
154
+ code, data, raw_headers = _mkblock(uptoken, block_size, body)
155
+ Utils.debug "Mkblk : #{code.inspect} #{data.inspect} #{raw_headers.inspect}"
156
+
157
+ body_crc32 = Zlib.crc32(body)
158
+ if HTTP.is_response_ok?(code) && data["crc32"] == body_crc32
159
+ progress[:ctx] = data["ctx"]
160
+ progress[:offset] = body_length
161
+ progress[:restsize] = block_size - body_length
162
+ progress[:status_code] = code
163
+ progress[:host] = data["host"]
164
+ if !notifier.nil? && notifier.respond_to?("notify")
165
+ notifier.notify(block_index, progress)
166
+ end
167
+ break
168
+ elsif i == retry_times && data["crc32"] != body_crc32
169
+ Log.logger.error %Q(Uploading block error. Expected crc32: #{body_crc32}, but got: #{data["crc32"]})
170
+ return code, data, raw_headers
171
+ end
172
+ end
173
+ elsif progress[:offset] + progress[:restsize] != block_size
174
+ raise BlockSizeNotMathchError.new(fpath, block_index, progress[:offset], progress[:restsize], block_size)
175
+ end
176
+
177
+ # loop uploading other chunks except the first one
178
+ while progress[:restsize].to_i > 0 && progress[:restsize] < block_size
179
+ # choose the smaller one
180
+ body_length = [progress[:restsize], chunk_size].min
181
+ for i in 1..retry_times
182
+ seek_pos = block_index*Config.settings[:block_size] + progress[:offset]
183
+ body = fh.get_data(seek_pos, body_length)
184
+ result_length = body.length
185
+ if result_length != body_length
186
+ raise FileSeekReadError.new(fpath, block_index, seek_pos, body_length, result_length)
187
+ end
188
+
189
+ code, data, raw_headers = _putblock(progress[:host], uptoken, progress[:ctx], progress[:offset], body)
190
+ Utils.debug "Bput : #{code.inspect} #{data.inspect} #{raw_headers.inspect}"
191
+
192
+ body_crc32 = Zlib.crc32(body)
193
+ if HTTP.is_response_ok?(code) && data["crc32"] == body_crc32
194
+ progress[:ctx] = data["ctx"]
195
+ progress[:offset] += body_length
196
+ progress[:restsize] -= body_length
197
+ progress[:status_code] = code
198
+ progress[:host] = data["host"]
199
+ if !notifier.nil? && notifier.respond_to?("notify")
200
+ notifier.notify(block_index, progress)
201
+ end
202
+ break
203
+ elsif i == retry_times && data["crc32"] != body_crc32
204
+ Log.logger.error %Q(Uploading block error. Expected crc32: #{body_crc32}, but got: #{data["crc32"]})
205
+ return code, data, raw_headers
206
+ end
207
+ end
208
+ end
209
+ # return
210
+ return code, data, raw_headers
211
+ end # _resumable_put_block
212
+
213
+ def _block_count(fsize)
214
+ ((fsize + Config.settings[:block_size] - 1) / Config.settings[:block_size]).to_i
215
+ end # _block_count
216
+
217
+ def _resumable_put(uptoken,
218
+ fh,
219
+ checksums,
220
+ progresses,
221
+ block_notifier = nil,
222
+ chunk_notifier = nil)
223
+ code, data = 0, {}
224
+ fsize = fh.data_size
225
+ block_count = _block_count(fsize)
226
+ checksum_count = checksums.length
227
+ progress_count = progresses.length
228
+ if checksum_count != block_count || progress_count != block_count
229
+ raise BlockCountNotMathchError.new(fh.path, block_count, checksum_count, progress_count)
230
+ end
231
+ 0.upto(block_count-1).each do |block_index|
232
+ if checksums[block_index].nil? || checksums[block_index].empty?
233
+ block_size = Config.settings[:block_size]
234
+ if block_index == block_count - 1
235
+ block_size = fsize - block_index*Config.settings[:block_size]
236
+ end
237
+ if progresses[block_index].nil?
238
+ progresses[block_index] = _new_block_put_progress_data
239
+ end
240
+ #code, data = _resumable_put_block(uptoken, fh, block_index, block_size, Config.settings[:chunk_size], progresses[block_index], Config.settings[:max_retry_times], chunk_notifier)
241
+ # Put the whole block as a chunk
242
+ code, data = _resumable_put_block(uptoken, fh, block_index, block_size, block_size, progresses[block_index], Config.settings[:max_retry_times], chunk_notifier)
243
+ if HTTP.is_response_ok?(code)
244
+ #checksums[block_index] = data["checksum"]
245
+ checksums[block_index] = data["ctx"]
246
+ if !block_notifier.nil? && block_notifier.respond_to?("notify")
247
+ block_notifier.notify(block_index, checksums[block_index])
248
+ end
249
+ end
250
+ end
251
+ end
252
+ return [code, data]
253
+ end # _resumable_put
254
+
255
+ def _mkfile(uphost,
256
+ uptoken,
257
+ entry_uri,
258
+ fsize,
259
+ checksums,
260
+ mime_type = nil,
261
+ custom_meta = nil,
262
+ customer = nil,
263
+ callback_params = nil,
264
+ rotate = nil)
265
+ path = '/rs-mkfile/' + Utils.urlsafe_base64_encode(entry_uri) + "/fsize/#{fsize}"
266
+ path += '/mimeType/' + Utils.urlsafe_base64_encode(mime_type) if !mime_type.nil? && !mime_type.empty?
267
+ path += '/meta/' + Utils.urlsafe_base64_encode(custom_meta) if !custom_meta.nil? && !custom_meta.empty?
268
+ path += '/customer/' + customer if !customer.nil? && !customer.empty?
269
+ callback_query_string = HTTP.generate_query_string(callback_params) if !callback_params.nil? && !callback_params.empty?
270
+ path += '/params/' + Utils.urlsafe_base64_encode(callback_query_string) if !callback_query_string.nil? && !callback_query_string.empty?
271
+ path += '/rotate/' + rotate if !rotate.nil? && rotate.to_i >= 0
272
+ url = uphost + path
273
+ #body = ''
274
+ #checksums.each do |checksum|
275
+ # body += Utils.urlsafe_base64_decode(checksum)
276
+ #end
277
+ body = checksums.join(',')
278
+ _call_binary_with_token(uptoken, url, body, 'text/plain')
279
+ end # _mkfile
280
+
281
+ def _resumable_upload(uptoken,
282
+ fh,
283
+ fsize,
284
+ bucket,
285
+ key,
286
+ mime_type = nil,
287
+ custom_meta = nil,
288
+ customer = nil,
289
+ callback_params = nil,
290
+ rotate = nil)
291
+
292
+ block_count = _block_count(fsize)
293
+
294
+ chunk_notifier = ChunkProgressNotifier.new()
295
+ block_notifier = BlockProgressNotifier.new()
296
+
297
+ progresses = []
298
+ block_count.times{progresses << _new_block_put_progress_data}
299
+ checksums = []
300
+ block_count.times{checksums << ''}
301
+
302
+ code, data, raw_headers = _resumable_put(uptoken, fh, checksums, progresses, block_notifier, chunk_notifier)
303
+
304
+ if HTTP.is_response_ok?(code)
305
+ uphost = data["host"]
306
+ entry_uri = bucket + ':' + key
307
+ code, data, raw_headers = _mkfile(uphost, uptoken, entry_uri, fsize, checksums, mime_type, custom_meta, customer, callback_params, rotate)
308
+ Utils.debug "Mkfile : #{code.inspect} #{data.inspect} #{raw_headers.inspect}"
309
+ end
310
+
311
+ if HTTP.is_response_ok?(code)
312
+ Utils.debug "File #{fh.path} {size: #{fsize}} successfully uploaded."
313
+ end
314
+
315
+ return code, data, raw_headers
316
+ end # _resumable_upload
317
+ end # self class
318
+ end # module Storage
319
+ end # module Qiniu
@@ -0,0 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'qiniu/upload'
4
+ require 'qiniu/resumable_upload'
5
+ require 'qiniu/management'
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'hmac-sha1'
4
+ require 'qiniu/config'
5
+ require 'qiniu/utils'
6
+
7
+ ### AccessToken 类已经过时,请改用 Qiniu::Auth.generate_acctoken 方法 ###
8
+
9
+ module Qiniu
10
+ class AccessToken
11
+
12
+ include Utils
13
+
14
+ attr_accessor :access_key, :secret_key
15
+
16
+ def generate_encoded_digest(signature)
17
+ hmac = HMAC::SHA1.new(@secret_key)
18
+ hmac.update(signature)
19
+ urlsafe_base64_encode(hmac.digest)
20
+ end
21
+
22
+ end # AccessToken
23
+ end # module Qiniu