From 36c492b9b9c9396e49cbe15d53dde4c3e71dfebe Mon Sep 17 00:00:00 2001 From: Liang Tao Date: Mon, 3 Mar 2014 16:40:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=BB=E9=99=A4io/up=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/qiniu/up.rb | 279 ------------------------------------------ spec/qiniu/io_spec.rb | 59 --------- spec/qiniu/up_spec.rb | 152 ----------------------- 3 files changed, 490 deletions(-) delete mode 100755 lib/qiniu/up.rb delete mode 100755 spec/qiniu/io_spec.rb delete mode 100755 spec/qiniu/up_spec.rb diff --git a/lib/qiniu/up.rb b/lib/qiniu/up.rb deleted file mode 100755 index 0ed2fe9..0000000 --- a/lib/qiniu/up.rb +++ /dev/null @@ -1,279 +0,0 @@ -# -*- encoding: utf-8 -*- - -require 'zlib' -require 'yaml' -require 'tmpdir' -require 'fileutils' -require 'mime/types' -require 'digest/sha1' -require 'qiniu/abstract' -require 'qiniu/exceptions' -require 'qiniu/io' - -module Qiniu - module UP - - module AbstractClass - class ChunkProgressNotifier - include Qiniu::Abstract - abstract_methods :notify - # def notify(block_index, block_put_progress); end - end - - class BlockProgressNotifier - include Qiniu::Abstract - abstract_methods :notify - # def notify(block_index, checksum); end - end - end - - class ChunkProgressNotifier < AbstractClass::ChunkProgressNotifier - def notify(index, progress) - logmsg = "chunk #{progress[:offset]/Config.settings[:chunk_size]} in block #{index} successfully uploaded.\n" + progress.to_s - Utils.debug(logmsg) - end - end - - class BlockProgressNotifier < AbstractClass::BlockProgressNotifier - def notify(index, checksum) - Utils.debug "block #{index}: {ctx: #{checksum}} successfully uploaded." - Utils.debug "block #{index}: {checksum: #{checksum}} successfully uploaded." - end - end - - class << self - include Utils - - def upload_with_token(uptoken, - local_file, - bucket, - key = nil, - mime_type = nil, - custom_meta = nil, - customer = nil, - callback_params = nil, - rotate = nil) - begin - ifile = File.open(local_file, 'rb') - fh = FileData.new(ifile) - fsize = fh.data_size - key = Digest::SHA1.hexdigest(local_file + fh.mtime.to_s) if key.nil? - if mime_type.nil? || mime_type.empty? - mime = MIME::Types.type_for local_file - mime_type = mime.empty? ? 'application/octet-stream' : mime[0].content_type - end - code, data = _resumable_upload(uptoken, fh, fsize, bucket, key, mime_type, custom_meta, customer, callback_params, rotate) - [code, data] - ensure - ifile.close unless ifile.nil? - end - end - - private - - class FileData - attr_accessor :fh - def initialize(fh) - @fh = fh - end - def data_size - @fh.stat.size - end - def get_data(offset, length) - @fh.seek(offset) - @fh.read(length) - end - def path - @fh.path - end - def mtime - @fh.mtime - end - #delegate :path, :mtime, :to => :fh - end - - def _new_block_put_progress_data - {:ctx => nil, :offset => 0, :restsize => nil, :status_code => nil, :host => nil} - end - - def _call_binary_with_token(uptoken, url, data, content_type = nil, retry_times = 0) - options = { - :method => :post, - :content_type => 'application/octet-stream', - :upload_signature_token => uptoken - } - options[:content_type] = content_type if !content_type.nil? && !content_type.empty? - code, data = http_request url, data, options - unless Utils.is_response_ok?(code) - retry_times += 1 - if Config.settings[:auto_reconnect] && retry_times < Config.settings[:max_retry_times] - return _call_binary_with_token(uptoken, url, data, options[:content_type], retry_times) - end - end - [code, data] - end - - def _mkblock(uptoken, block_size, body) - url = Config.settings[:up_host] + "/mkblk/#{block_size}" - _call_binary_with_token(uptoken, url, body) - end - - def _putblock(uphost, uptoken, ctx, offset, body) - url = uphost + "/bput/#{ctx}/#{offset}" - _call_binary_with_token(uptoken, url, body) - end - - def _resumable_put_block(uptoken, fh, block_index, block_size, chunk_size, progress, retry_times, notifier) - code, data = 0, {} - fpath = fh.path - - # this block has never been uploaded. - if progress[:ctx] == nil || progress[:ctx].empty? - progress[:offset] = 0 - progress[:restsize] = block_size - # choose the smaller one - body_length = [block_size, chunk_size].min - for i in 1..retry_times - seek_pos = block_index*Config.settings[:block_size] - body = fh.get_data(seek_pos, body_length) - result_length = body.length - if result_length != body_length - raise FileSeekReadError.new(fpath, block_index, seek_pos, body_length, result_length) - end - code, data = _mkblock(uptoken, block_size, body) - body_crc32 = Zlib.crc32(body) - if Utils.is_response_ok?(code) && data["crc32"] == body_crc32 - progress[:ctx] = data["ctx"] - progress[:offset] = body_length - progress[:restsize] = block_size - body_length - progress[:status_code] = code - progress[:host] = data["host"] - if !notifier.nil? && notifier.respond_to?("notify") - notifier.notify(block_index, progress) - end - break - elsif i == retry_times && data["crc32"] != body_crc32 - Log.logger.error %Q(Uploading block error. Expected crc32: #{body_crc32}, but got: #{data["crc32"]}) - end - end - elsif progress[:offset] + progress[:restsize] != block_size - raise BlockSizeNotMathchError.new(fpath, block_index, progress[:offset], progress[:restsize], block_size) - end - - # loop uploading other chunks except the first one - while progress[:restsize].to_i > 0 && progress[:restsize] < block_size - # choose the smaller one - body_length = [progress[:restsize], chunk_size].min - for i in 1..retry_times - seek_pos = block_index*Config.settings[:block_size] + progress[:offset] - body = fh.get_data(seek_pos, body_length) - result_length = body.length - if result_length != body_length - raise FileSeekReadError.new(fpath, block_index, seek_pos, body_length, result_length) - end - code, data = _putblock(progress[:host], uptoken, progress[:ctx], progress[:offset], body) - body_crc32 = Zlib.crc32(body) - if Utils.is_response_ok?(code) && data["crc32"] == body_crc32 - progress[:ctx] = data["ctx"] - progress[:offset] += body_length - progress[:restsize] -= body_length - progress[:status_code] = code - progress[:host] = data["host"] - if !notifier.nil? && notifier.respond_to?("notify") - notifier.notify(block_index, progress) - end - break - elsif i == retry_times && data["crc32"] != body_crc32 - Log.logger.error %Q(Uploading block error. Expected crc32: #{body_crc32}, but got: #{data["crc32"]}) - end - end - end - # return - return [code, data] - end - - def _block_count(fsize) - ((fsize + Config.settings[:block_size] - 1) / Config.settings[:block_size]).to_i - end - - def _resumable_put(uptoken, fh, checksums, progresses, block_notifier = nil, chunk_notifier = nil) - code, data = 0, {} - fsize = fh.data_size - block_count = _block_count(fsize) - checksum_count = checksums.length - progress_count = progresses.length - if checksum_count != block_count || progress_count != block_count - raise BlockCountNotMathchError.new(fh.path, block_count, checksum_count, progress_count) - end - 0.upto(block_count-1).each do |block_index| - if checksums[block_index].nil? || checksums[block_index].empty? - block_size = Config.settings[:block_size] - if block_index == block_count - 1 - block_size = fsize - block_index*Config.settings[:block_size] - end - if progresses[block_index].nil? - progresses[block_index] = _new_block_put_progress_data - end - #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) - # Put the whole block as a chunk - code, data = _resumable_put_block(uptoken, fh, block_index, block_size, block_size, progresses[block_index], Config.settings[:max_retry_times], chunk_notifier) - if Utils.is_response_ok?(code) - #checksums[block_index] = data["checksum"] - checksums[block_index] = data["ctx"] - if !block_notifier.nil? && block_notifier.respond_to?("notify") - block_notifier.notify(block_index, checksums[block_index]) - end - end - end - end - return [code, data] - end - - def _mkfile(uphost, uptoken, entry_uri, fsize, checksums, mime_type = nil, custom_meta = nil, customer = nil, callback_params = nil, rotate = nil) - path = '/rs-mkfile/' + Utils.urlsafe_base64_encode(entry_uri) + "/fsize/#{fsize}" - path += '/mimeType/' + Utils.urlsafe_base64_encode(mime_type) if !mime_type.nil? && !mime_type.empty? - path += '/meta/' + Utils.urlsafe_base64_encode(custom_meta) if !custom_meta.nil? && !custom_meta.empty? - path += '/customer/' + customer if !customer.nil? && !customer.empty? - callback_query_string = Utils.generate_query_string(callback_params) if !callback_params.nil? && !callback_params.empty? - path += '/params/' + Utils.urlsafe_base64_encode(callback_query_string) if !callback_query_string.nil? && !callback_query_string.empty? - path += '/rotate/' + rotate if !rotate.nil? && rotate.to_i >= 0 - url = uphost + path - #body = '' - #checksums.each do |checksum| - # body += Utils.urlsafe_base64_decode(checksum) - #end - body = checksums.join(',') - _call_binary_with_token(uptoken, url, body, 'text/plain') - end - - def _resumable_upload(uptoken, fh, fsize, bucket, key, mime_type = nil, custom_meta = nil, customer = nil, callback_params = nil, rotate = nil) - - block_count = _block_count(fsize) - - chunk_notifier = ChunkProgressNotifier.new() - block_notifier = BlockProgressNotifier.new() - - progresses = [] - block_count.times{progresses << _new_block_put_progress_data} - checksums = [] - block_count.times{checksums << ''} - - code, data = _resumable_put(uptoken, fh, checksums, progresses, block_notifier, chunk_notifier) - - if Utils.is_response_ok?(code) - uphost = data["host"] - entry_uri = bucket + ':' + key - code, data = _mkfile(uphost, uptoken, entry_uri, fsize, checksums, mime_type, custom_meta, customer, callback_params, rotate) - end - - if Utils.is_response_ok?(code) - Utils.debug "File #{fh.path} {size: #{fsize}} successfully uploaded." - end - - [code, data] - end - - end - - end # module UP -end # module Qiniu diff --git a/spec/qiniu/io_spec.rb b/spec/qiniu/io_spec.rb deleted file mode 100755 index 9b596fb..0000000 --- a/spec/qiniu/io_spec.rb +++ /dev/null @@ -1,59 +0,0 @@ -# -*- encoding: utf-8 -*- - -require 'spec_helper' -require 'qiniu/auth' -require 'qiniu/io' -require 'digest/sha1' - -module Qiniu - module IO - describe IO do - - before :all do - @bucket = 'RubySdkTest' + (Time.now.to_i+rand(1000)).to_s - @key = Digest::SHA1.hexdigest((Time.now.to_i+rand(100)).to_s) - - result = Qiniu.mkbucket(@bucket) - puts result.inspect - result.should be_true - end - - after :all do - result = Qiniu.drop(@bucket) - puts result.inspect - result.should_not be_false - end - - context ".put_file" do - it "should works" do - code, data = Qiniu::IO.put_file(__FILE__, @bucket, @key, 'application/x-ruby', 'customMeta', true) - code.should == 200 - puts data.inspect - end - end - - context ".upload_with_token" do - it "should works" do - upopts = {:scope => @bucket, :expires_in => 3600, :customer => "why404@gmail.com"} - uptoken = Qiniu.generate_upload_token(upopts) - code, data = Qiniu::IO.upload_with_token(uptoken, __FILE__, @bucket, @key, nil, nil, nil, true) - code.should == 200 - puts data.inspect - end - end - - context ".upload_with_token_2" do - it "should works" do - upopts = {:scope => @bucket, :expires_in => 3600, :endUser => "why404@gmail.com"} - uptoken = Qiniu.generate_upload_token(upopts) - - code, data = Qiniu::IO.upload_with_token_2(uptoken, __FILE__, @key) - - code.should == 200 - puts data.inspect - end - end # .upload_with_token_2 - - end - end # module IO -end # module Qiniu diff --git a/spec/qiniu/up_spec.rb b/spec/qiniu/up_spec.rb deleted file mode 100755 index dd82c2e..0000000 --- a/spec/qiniu/up_spec.rb +++ /dev/null @@ -1,152 +0,0 @@ -# -*- encoding: utf-8 -*- - -require 'digest/sha1' -require 'spec_helper' -require 'qiniu' -require 'qiniu/up' - -module Qiniu - module UP - describe UP do - - before :all do - @localfile = "bigfile.txt" - File.open(@localfile, "w"){|f| 5242888.times{ f.write(rand(9).to_s) }} - @bucket = 'RubySdkTest' + (Time.now.to_i+rand(1000)).to_s - @key = Digest::SHA1.hexdigest(@localfile+Time.now.to_s) - - @localfile2 = "bigfile2.txt" - File.open(@localfile2, "w"){|f| (1 << 22).times{ f.write(rand(9).to_s) }} - @key2 = Digest::SHA1.hexdigest(@localfile2+Time.now.to_s) - - @localfile3 = "bigfile3.txt" - File.open(@localfile3, "w"){|f| (1 << 23).times{ f.write(rand(9).to_s) }} - @key3 = Digest::SHA1.hexdigest(@localfile3+Time.now.to_s) - - @localfile4 = "smallfile.txt" - File.open(@localfile4, "w"){|f| (1 << 20).times{ f.write(rand(9).to_s) }} - @key4 = Digest::SHA1.hexdigest(@localfile4+Time.now.to_s) - - code, data = Qiniu::RS.mkbucket(@bucket) - puts [code, data].inspect - code.should == 200 - end - - after :all do - File.unlink(@localfile) if File.exists?(@localfile) - File.unlink(@localfile2) if File.exists?(@localfile2) - File.unlink(@localfile3) if File.exists?(@localfile3) - File.unlink(@localfile4) if File.exists?(@localfile4) - - code, data = Qiniu::RS.drop(@bucket) - puts [code, data].inspect - code.should == 200 - end - - context ".upload_with_token" do - it "should works" do - upopts = {:scope => @bucket, :expires_in => 3600, :customer => "why404@gmail.com"} - uptoken = Qiniu.generate_upload_token(upopts) - code, data = Qiniu::UP.upload_with_token(uptoken, @localfile, @bucket, @key) - puts data.inspect - (code/100).should == 2 - end - end - - context ".stat" do - it "should exists" do - code, data = Qiniu::RS.stat(@bucket, @key) - puts data.inspect - code.should == 200 - end - end - - context ".delete" do - it "should works" do - code, data = Qiniu::RS.delete(@bucket, @key) - puts data.inspect - code.should == 200 - end - end - - context ".upload_with_token2" do - it "should works" do - upopts = {:scope => @bucket, :expires_in => 3600, :customer => "why404@gmail.com"} - uptoken = Qiniu.generate_upload_token(upopts) - code, data = Qiniu::UP.upload_with_token(uptoken, @localfile2, @bucket, @key2) - puts data.inspect - (code/100).should == 2 - end - end - - context ".stat" do - it "should exists" do - code, data = Qiniu::RS.stat(@bucket, @key2) - puts data.inspect - code.should == 200 - end - end - - context ".delete" do - it "should works" do - code, data = Qiniu::RS.delete(@bucket, @key2) - puts data.inspect - code.should == 200 - end - end - - context ".upload_with_token3" do - it "should works" do - upopts = {:scope => @bucket, :expires_in => 3600, :customer => "why404@gmail.com"} - uptoken = Qiniu.generate_upload_token(upopts) - code, data = Qiniu::UP.upload_with_token(uptoken, @localfile3, @bucket, @key3) - puts data.inspect - (code/100).should == 2 - end - end - - context ".stat" do - it "should exists" do - code, data = Qiniu::RS.stat(@bucket, @key3) - puts data.inspect - code.should == 200 - end - end - - context ".delete" do - it "should works" do - code, data = Qiniu::RS.delete(@bucket, @key3) - puts data.inspect - code.should == 200 - end - end - - context ".upload_with_token4" do - it "should works" do - upopts = {:scope => @bucket, :expires_in => 3600, :customer => "why404@gmail.com"} - uptoken = Qiniu.generate_upload_token(upopts) - code, data = Qiniu::UP.upload_with_token(uptoken, @localfile4, @bucket, @key4) - puts data.inspect - (code/100).should == 2 - end - end - - context ".stat" do - it "should exists" do - code, data = Qiniu::RS.stat(@bucket, @key4) - puts data.inspect - code.should == 200 - end - end - - context ".delete" do - it "should works" do - code, data = Qiniu::RS.delete(@bucket, @key4) - puts data.inspect - code.should == 200 - end - end - - end - end # module UP -end # module Qiniu