qiniu_jxb 6.2.4

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 (48) hide show
  1. data/.gitignore +18 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +9 -0
  4. data/CHANGELOG.md +118 -0
  5. data/Gemfile +8 -0
  6. data/Gemfile.lock +37 -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-rs.rb +2 -0
  12. data/lib/qiniu.rb +209 -0
  13. data/lib/qiniu/abstract.rb +22 -0
  14. data/lib/qiniu/adt.rb +46 -0
  15. data/lib/qiniu/auth.rb +234 -0
  16. data/lib/qiniu/config.rb +58 -0
  17. data/lib/qiniu/exceptions.rb +120 -0
  18. data/lib/qiniu/fop.rb +4 -0
  19. data/lib/qiniu/http.rb +137 -0
  20. data/lib/qiniu/image.rb +38 -0
  21. data/lib/qiniu/log.rb +15 -0
  22. data/lib/qiniu/management.rb +128 -0
  23. data/lib/qiniu/misc.rb +33 -0
  24. data/lib/qiniu/pfop.rb +124 -0
  25. data/lib/qiniu/resumable_upload.rb +319 -0
  26. data/lib/qiniu/storage.rb +5 -0
  27. data/lib/qiniu/tokens/access_token.rb +21 -0
  28. data/lib/qiniu/tokens/download_token.rb +31 -0
  29. data/lib/qiniu/tokens/qbox_token.rb +38 -0
  30. data/lib/qiniu/tokens/upload_token.rb +47 -0
  31. data/lib/qiniu/upload.rb +138 -0
  32. data/lib/qiniu/utils.rb +109 -0
  33. data/lib/qiniu/version.rb +17 -0
  34. data/qiniu.gemspec +29 -0
  35. data/spec/qiniu/abstract_spec.rb +30 -0
  36. data/spec/qiniu/auth_spec.rb +81 -0
  37. data/spec/qiniu/image_logo_for_test.png +0 -0
  38. data/spec/qiniu/image_spec.rb +89 -0
  39. data/spec/qiniu/management_spec.rb +156 -0
  40. data/spec/qiniu/misc_spec.rb +59 -0
  41. data/spec/qiniu/pfop_spec.rb +89 -0
  42. data/spec/qiniu/qiniu_spec.rb +329 -0
  43. data/spec/qiniu/tokens/qbox_token_spec.rb +29 -0
  44. data/spec/qiniu/upload_spec.rb +308 -0
  45. data/spec/qiniu/utils_spec.rb +49 -0
  46. data/spec/qiniu/version_spec.rb +10 -0
  47. data/spec/spec_helper.rb +19 -0
  48. metadata +220 -0
@@ -0,0 +1,58 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # USAGE WAY 1:
4
+ # Qbox::Config.initialize_connect :client_id => "<ClientID>",
5
+ # :client_secret => "<ClientSecret>"
6
+ #
7
+ # USAGE WAY 2:
8
+ # Qbox::Config.load "path/to/your_project/config/qiniu.yml"
9
+ #
10
+
11
+ require 'tmpdir'
12
+
13
+ module Qiniu
14
+ module Config
15
+ class << self
16
+
17
+ DEFAULT_OPTIONS = {
18
+ :user_agent => 'QiniuRuby/' + Version.to_s + ' ('+RUBY_PLATFORM+')' + ' Ruby/'+ RUBY_VERSION,
19
+ :method => :post,
20
+ :content_type => 'application/x-www-form-urlencoded',
21
+ :auth_url => "https://acc.qbox.me/oauth2/token",
22
+ :rs_host => "http://rs.qiniu.com",
23
+ :up_host => "http://up.qiniu.com",
24
+ :pub_host => "http://pu.qbox.me:10200",
25
+ :eu_host => "http://eu.qbox.me",
26
+ :access_key => "",
27
+ :secret_key => "",
28
+ :auto_reconnect => true,
29
+ :max_retry_times => 3,
30
+ :block_size => 1024*1024*4,
31
+ :chunk_size => 1024*256,
32
+ :enable_debug => true,
33
+ :tmpdir => Dir.tmpdir + File::SEPARATOR + 'QiniuRuby'
34
+ }
35
+
36
+ REQUIRED_OPTION_KEYS = [:access_key, :secret_key]
37
+
38
+ attr_reader :settings, :default_params
39
+
40
+ def load config_file
41
+ if File.exist?(config_file)
42
+ config_options = YAML.load_file(config_file)
43
+ initialize_connect(config_options)
44
+ else
45
+ raise MissingConfError, config_file
46
+ end
47
+ end
48
+
49
+ def initialize_connect options = {}
50
+ @settings = DEFAULT_OPTIONS.merge(options)
51
+ REQUIRED_OPTION_KEYS.each do |opt|
52
+ raise MissingArgsError, [opt] unless @settings.has_key?(opt)
53
+ end
54
+ end
55
+
56
+ end
57
+ end # module Config
58
+ end # module Qiniu
@@ -0,0 +1,120 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Qiniu
4
+
5
+ class Exception < RuntimeError
6
+ end
7
+
8
+ class ResponseError < Exception
9
+ attr_reader :response
10
+
11
+ def initialize(message, response = nil)
12
+ @response = response
13
+ super(message)
14
+ end
15
+
16
+ def http_code
17
+ @response.code.to_i if @response
18
+ end
19
+
20
+ def http_body
21
+ @response.body if @response
22
+ end
23
+
24
+ def inspect
25
+ "#{message}: #{http_body}"
26
+ end
27
+ end
28
+
29
+ class RequestFailed < ResponseError
30
+ def message
31
+ "HTTP status code: #{http_code}. Response body: #{http_body}"
32
+ end
33
+
34
+ def to_s
35
+ message
36
+ end
37
+ end
38
+
39
+ class UploadFailedError < Exception
40
+ def initialize(status_code, response_data)
41
+ data_string = response_data.map { |key, value| %Q(:#{key.to_s} => #{value.to_s}) }
42
+ msg = %Q(Uploading Failed. HTTP Status Code: #{status_code}. HTTP response body: #{data_string.join(', ')}.)
43
+ super(msg)
44
+ end
45
+ end
46
+
47
+ class FileSeekReadError < Exception
48
+ def initialize(fpath, block_index, seek_pos, read_length, result_length)
49
+ msg = "Reading file: #{fpath}, "
50
+ msg += "at block index: #{block_index}. "
51
+ msg += "Expected seek_pos:#{seek_pos} and read_length:#{read_length}, "
52
+ msg += "but got result_length: #{result_length}."
53
+ super(msg)
54
+ end
55
+ end
56
+
57
+ class BlockSizeNotMathchError < Exception
58
+ def initialize(fpath, block_index, offset, restsize, block_size)
59
+ msg = "Reading file: #{fpath}, "
60
+ msg += "at block index: #{block_index}. "
61
+ msg += "Expected offset: #{offset}, restsize: #{restsize} and block_size: #{block_size}, "
62
+ msg += "but got offset+restsize=#{offset+restsize}."
63
+ super(msg)
64
+ end
65
+ end
66
+
67
+ class BlockCountNotMathchError < Exception
68
+ def initialize(fpath, block_count, checksum_count, progress_count)
69
+ msg = "Reading file: #{fpath}, "
70
+ msg += "Expected block_count, checksum_count, progress_count is: #{block_count}, "
71
+ msg += "but got checksum_count: #{checksum_count}, progress_count: #{progress_count}."
72
+ super(msg)
73
+ end
74
+ end
75
+
76
+ class MissingArgsError < Exception
77
+ def initialize(missing_keys)
78
+ key_list = missing_keys.map {|key| key.to_s}.join(' and the ')
79
+ super("You did not provide both required args. Please provide the #{key_list}.")
80
+ end
81
+ end
82
+
83
+ class MissingAccessToken < MissingArgsError
84
+ def initialize
85
+ super([:access_token])
86
+ end
87
+ end
88
+
89
+ class MissingRefreshToken < MissingArgsError
90
+ def initialize
91
+ super([:refresh_token])
92
+ end
93
+ end
94
+
95
+ class MissingUsernameOrPassword < MissingArgsError
96
+ def initialize
97
+ super([:username, :password])
98
+ end
99
+ end
100
+
101
+ class InvalidArgsError < Exception
102
+ def initialize(invalid_keys)
103
+ key_list = invalid_keys.map {|key| key.to_s}.join(' and the ')
104
+ super("#{key_list} should not be empty.")
105
+ end
106
+ end
107
+
108
+ class MissingConfError < Exception
109
+ def initialize(missing_conf_file)
110
+ super("Error, missing #{missing_conf_file}. You must have #{missing_conf_file} to configure your client id and secret.")
111
+ end
112
+ end
113
+
114
+ class NoSuchFileError < Exception
115
+ def initialize(missing_file)
116
+ super("Error, no such file #{missing_file}.")
117
+ end
118
+ end
119
+
120
+ end # module Qiniu
data/lib/qiniu/fop.rb ADDED
@@ -0,0 +1,4 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'qiniu/image'
4
+ require 'qiniu/pfop'
data/lib/qiniu/http.rb ADDED
@@ -0,0 +1,137 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # vim: sw=2 ts=2
3
+
4
+ module Qiniu
5
+ module HTTP
6
+
7
+ class << self
8
+ public
9
+ def is_response_ok?(http_code)
10
+ return 200 <= http_code && http_code <= 299
11
+ end # is_response_ok?
12
+
13
+ def generate_query_string(params)
14
+ if params.is_a?(Hash)
15
+ total_param = params.map { |key, value| %Q(#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s).gsub('+', '%20')}) }
16
+ return total_param.join("&")
17
+ end
18
+
19
+ return params
20
+ end # generate_query_string
21
+
22
+ def get (url, opts = {})
23
+ ### 配置请求Header
24
+ req_headers = {
25
+ :connection => 'close',
26
+ :accept => '*/*',
27
+ :user_agent => Config.settings[:user_agent]
28
+ }
29
+
30
+ # 优先使用外部Header,覆盖任何特定Header
31
+ if opts[:headers].is_a?(Hash) then
32
+ req_headers.merge!(opts[:headers])
33
+ end
34
+
35
+ ### 发送请求
36
+ response = RestClient.get(url, req_headers)
37
+ return response.code.to_i, response.body, response.raw_headers
38
+ rescue => e
39
+ Log.logger.warn "#{e.message} => Qiniu::HTTP.get('#{url}')"
40
+ if e.respond_to?(:response) && e.response.respond_to?(:code) then
41
+ return e.response.code, e.response.body, e.response.raw_headers
42
+ end
43
+ return nil, nil, nil
44
+ end # get
45
+
46
+ API_RESULT_MIMETYPE = 'application/json'
47
+
48
+ def api_get (url, opts = {})
49
+ ### 配置请求Header
50
+ headers = {
51
+ :accept => API_RESULT_MIMETYPE
52
+ }
53
+
54
+ # 将特定Header混入外部Header中
55
+ if opts[:headers].is_a?(Hash) then
56
+ opts[:headers] = opts[:headers].dup.merge!(headers)
57
+ else
58
+ opts[:headers] = headers
59
+ end
60
+
61
+ ### 发送请求,然后转换返回值
62
+ resp_code, resp_body, resp_headers = get(url, opts)
63
+ if resp_code.nil? then
64
+ return 0, {}, {}
65
+ end
66
+
67
+ content_type = resp_headers["content-type"][0]
68
+ if !content_type.nil? && content_type == API_RESULT_MIMETYPE then
69
+ # 如果是JSON格式,则反序列化
70
+ resp_body = Utils.safe_json_parse(resp_body)
71
+ end
72
+
73
+ return resp_code, resp_body, resp_headers
74
+ end # api_get
75
+
76
+ def post (url, req_body = nil, opts = {})
77
+ ### 配置请求Header
78
+ req_headers = {
79
+ :connection => 'close',
80
+ :accept => '*/*',
81
+ :user_agent => Config.settings[:user_agent]
82
+ }
83
+
84
+ # 优先使用外部Header,覆盖任何特定Header
85
+ if opts[:headers].is_a?(Hash) then
86
+ req_headers.merge!(opts[:headers])
87
+ end
88
+
89
+ ### 发送请求
90
+ response = RestClient.post(url, req_body, req_headers)
91
+ return response.code.to_i, response.body, response.raw_headers
92
+ rescue => e
93
+ Log.logger.warn "#{e.message} => Qiniu::HTTP.post('#{url}')"
94
+ if e.respond_to?(:response) && e.response.respond_to?(:code) then
95
+ return e.response.code, e.response.body, e.response.raw_headers
96
+ end
97
+ return nil, nil, nil
98
+ end # post
99
+
100
+ def api_post (url, req_body = nil, opts = {})
101
+ ### 配置请求Header
102
+ headers = {
103
+ :accept => API_RESULT_MIMETYPE
104
+ }
105
+
106
+ # 将特定Header混入外部Header中
107
+ if opts[:headers].is_a?(Hash) then
108
+ opts[:headers] = opts[:headers].dup.merge!(headers)
109
+ else
110
+ opts[:headers] = headers
111
+ end
112
+
113
+ ### 发送请求,然后转换返回值
114
+ resp_code, resp_body, resp_headers = post(url, req_body, opts)
115
+ if resp_code.nil? then
116
+ return 0, {}, {}
117
+ end
118
+
119
+ content_type = resp_headers["content-type"][0]
120
+ if !content_type.nil? && content_type == API_RESULT_MIMETYPE then
121
+ # 如果是JSON格式,则反序列化
122
+ resp_body = Utils.safe_json_parse(resp_body)
123
+ end
124
+
125
+ return resp_code, resp_body, resp_headers
126
+ end # api_post
127
+
128
+ def management_post (url, body = '')
129
+ ### 授权并执行管理操作
130
+ return HTTP.api_post(url, body, {
131
+ :headers => { 'Authorization' => 'QBox ' + Auth.generate_acctoken(url, body) }
132
+ })
133
+ end # management_post
134
+ end # class << self
135
+
136
+ end # module HTTP
137
+ end # module Qiniu
@@ -0,0 +1,38 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Qiniu
4
+ module Fop
5
+ module Image
6
+ class << self
7
+ include Utils
8
+
9
+ def info(url)
10
+ return HTTP.api_get(url + '?imageInfo')
11
+ end # info
12
+
13
+ def exif(url)
14
+ return HTTP.api_get(url + '?exif')
15
+ end # exif
16
+
17
+ def mogrify_preview_url(source_image_url, options)
18
+ source_image_url + '?' + generate_mogrify_params_string(options)
19
+ end
20
+
21
+ def generate_mogrify_params_string(options = {})
22
+ opts = {}
23
+ options.each do |k, v|
24
+ opts[k.to_s] = v
25
+ end
26
+ params_string = ""
27
+ keys = ["thumbnail", "gravity", "crop", "quality", "rotate", "format"]
28
+ keys.each do |key|
29
+ params_string += %Q(/#{key}/#{opts[key]}) unless opts[key].nil?
30
+ end
31
+ params_string += '/auto-orient' unless opts["auto_orient"].nil?
32
+ 'imageMogr' + URI.escape(params_string)
33
+ end
34
+
35
+ end
36
+ end # module Image
37
+ end # module Fop
38
+ end # module Qiniu
data/lib/qiniu/log.rb ADDED
@@ -0,0 +1,15 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'logger'
4
+
5
+ module Qiniu
6
+ module Log
7
+ class << self
8
+ attr_accessor :logger
9
+
10
+ def logger
11
+ @logger ||= Logger.new(STDERR)
12
+ end
13
+ end
14
+ end # module Log
15
+ end # module Qiniu
@@ -0,0 +1,128 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # vim: sw=2 ts=2
3
+
4
+ require 'qiniu/http'
5
+
6
+ module Qiniu
7
+ module Storage
8
+ class << self
9
+ include Utils
10
+
11
+ public
12
+ def buckets
13
+ url = Config.settings[:rs_host] + '/buckets'
14
+ return HTTP.management_post(url)
15
+ end # buckets
16
+
17
+ PRIVATE_BUCKET = 0
18
+ PUBLIC_BUCKET = 1
19
+
20
+ def mkbucket(bucket_name, is_public = PUBLIC_BUCKET)
21
+ url = Config.settings[:rs_host] + '/mkbucket2/' + bucket_name + '/public/' + is_public.to_s
22
+ return HTTP.management_post(url)
23
+ end # mkbucket
24
+
25
+ def make_a_private_bucket(bucket_name)
26
+ return mkbucket(bucket_name, PRIVATE_BUCKET)
27
+ end # make_a_private_bucket
28
+
29
+ def make_a_public_bucket(bucket_name)
30
+ return mkbucket(bucket_name, PUBLIC_BUCKET)
31
+ end # make_a_public_bucket
32
+
33
+ def stat(bucket, key)
34
+ url = Config.settings[:rs_host] + '/stat/' + encode_entry_uri(bucket, key)
35
+ return HTTP.management_post(url)
36
+ end # stat
37
+
38
+ def get(bucket, key, save_as = nil, expires_in = nil, version = nil)
39
+ url = Config.settings[:rs_host] + '/get/' + encode_entry_uri(bucket, key)
40
+ url += '/base/' + version unless version.nil?
41
+ url += '/attName/' + Utils.urlsafe_base64_encode(save_as) unless save_as.nil?
42
+ url += '/expires/' + expires_in.to_s if !expires_in.nil? && expires_in > 0
43
+ return HTTP.management_post(url)
44
+ end # get
45
+
46
+ def copy(source_bucket, source_key, target_bucket, target_key)
47
+ uri = _generate_cp_or_mv_opstr('copy', source_bucket, source_key, target_bucket, target_key)
48
+ url = Config.settings[:rs_host] + uri
49
+ return HTTP.management_post(url)
50
+ end # copy
51
+
52
+ def move(source_bucket, source_key, target_bucket, target_key)
53
+ uri = _generate_cp_or_mv_opstr('move', source_bucket, source_key, target_bucket, target_key)
54
+ url = Config.settings[:rs_host] + uri
55
+ return HTTP.management_post(url)
56
+ end # move
57
+
58
+ def delete(bucket, key)
59
+ url = Config.settings[:rs_host] + '/delete/' + encode_entry_uri(bucket, key)
60
+ return HTTP.management_post(url)
61
+ end # delete
62
+
63
+ def drop(bucket)
64
+ url = Config.settings[:rs_host] + "/drop/#{bucket}"
65
+ return HTTP.management_post(url)
66
+ end # drop
67
+
68
+ def batch(command, bucket, keys)
69
+ execs = []
70
+ keys.each do |key|
71
+ encoded_uri = encode_entry_uri(bucket, key)
72
+ execs << "op=/#{command}/#{encoded_uri}"
73
+ end
74
+ url = Config.settings[:rs_host] + "/batch"
75
+ return HTTP.management_post(url, execs.join("&"))
76
+ end # batch
77
+
78
+ def batch_get(bucket, keys)
79
+ batch("get", bucket, keys)
80
+ end # batch_get
81
+
82
+ def batch_stat(bucket, keys)
83
+ batch("stat", bucket, keys)
84
+ end # batch_stat
85
+
86
+ def batch_copy(*args)
87
+ _batch_cp_or_mv('copy', args)
88
+ end # batch_copy
89
+
90
+ def batch_move(*args)
91
+ _batch_cp_or_mv('move', args)
92
+ end # batch_move
93
+
94
+ def batch_delete(bucket, keys)
95
+ batch("delete", bucket, keys)
96
+ end # batch_delete
97
+
98
+ def save_as(bucket, key, source_url, op_params_string)
99
+ encoded_uri = encode_entry_uri(bucket, key)
100
+ save_as_string = '/save-as/' + encoded_uri
101
+ new_url = source_url + '?' + op_params_string + save_as_string
102
+ return HTTP.management_post(new_url)
103
+ end # save_as
104
+
105
+ def image_mogrify_save_as(bucket, key, source_image_url, options)
106
+ mogrify_params_string = Fop::Image.generate_mogrify_params_string(options)
107
+ save_as(bucket, key, source_image_url, mogrify_params_string)
108
+ end # image_mogrify_save_as
109
+
110
+ private
111
+
112
+ def _generate_cp_or_mv_opstr(command, source_bucket, source_key, target_bucket, target_key)
113
+ source_encoded_entry_uri = encode_entry_uri(source_bucket, source_key)
114
+ target_encoded_entry_uri = encode_entry_uri(target_bucket, target_key)
115
+ %Q(/#{command}/#{source_encoded_entry_uri}/#{target_encoded_entry_uri})
116
+ end # _generate_cp_or_mv_opstr
117
+
118
+ def _batch_cp_or_mv(command, *op_args)
119
+ execs = []
120
+ op_args.each do |e|
121
+ execs << 'op=' + _generate_cp_or_mv_opstr(command, e[0], e[1], e[2], e[3]) if e.size == 4
122
+ end
123
+ url = Config.settings[:rs_host] + "/batch"
124
+ return HTTP.management_post(url, execs.join("&"))
125
+ end # _batch_cp_or_mv
126
+ end
127
+ end # module Storage
128
+ end # module Qiniu