qiniu 6.0.1
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 +18 -0
- data/.rspec +1 -0
- data/.travis.yml +14 -0
- data/CHANGELOG.md +83 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +37 -0
- data/LICENSE +22 -0
- data/README.md +45 -0
- data/Rakefile +21 -0
- data/docs/README.md +790 -0
- data/lib/qiniu-rs.rb +2 -0
- data/lib/qiniu.rb +229 -0
- data/lib/qiniu/abstract.rb +22 -0
- data/lib/qiniu/auth.rb +25 -0
- data/lib/qiniu/config.rb +61 -0
- data/lib/qiniu/exceptions.rb +120 -0
- data/lib/qiniu/fop.rb +3 -0
- data/lib/qiniu/image.rb +38 -0
- data/lib/qiniu/log.rb +15 -0
- data/lib/qiniu/management.rb +114 -0
- data/lib/qiniu/misc.rb +35 -0
- data/lib/qiniu/resumable_upload.rb +306 -0
- data/lib/qiniu/storage.rb +5 -0
- data/lib/qiniu/tokens/access_token.rb +21 -0
- data/lib/qiniu/tokens/download_token.rb +31 -0
- data/lib/qiniu/tokens/qbox_token.rb +38 -0
- data/lib/qiniu/tokens/upload_token.rb +47 -0
- data/lib/qiniu/upload.rb +114 -0
- data/lib/qiniu/utils.rb +151 -0
- data/lib/qiniu/version.rb +17 -0
- data/qiniu.gemspec +28 -0
- data/spec/qiniu/abstract_spec.rb +30 -0
- data/spec/qiniu/image_logo_for_test.png +0 -0
- data/spec/qiniu/image_spec.rb +87 -0
- data/spec/qiniu/management_spec.rb +181 -0
- data/spec/qiniu/misc_spec.rb +59 -0
- data/spec/qiniu/qiniu_spec.rb +385 -0
- data/spec/qiniu/tokens/qbox_token_spec.rb +29 -0
- data/spec/qiniu/upload_spec.rb +184 -0
- data/spec/qiniu/utils_spec.rb +49 -0
- data/spec/qiniu/version_spec.rb +10 -0
- data/spec/spec_helper.rb +11 -0
- metadata +194 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'hmac-sha1'
|
4
|
+
require 'qiniu/config'
|
5
|
+
require 'qiniu/utils'
|
6
|
+
|
7
|
+
module Qiniu
|
8
|
+
class AccessToken
|
9
|
+
|
10
|
+
include Utils
|
11
|
+
|
12
|
+
attr_accessor :access_key, :secret_key
|
13
|
+
|
14
|
+
def generate_encoded_digest(signature)
|
15
|
+
hmac = HMAC::SHA1.new(@secret_key)
|
16
|
+
hmac.update(signature)
|
17
|
+
urlsafe_base64_encode(hmac.digest)
|
18
|
+
end
|
19
|
+
|
20
|
+
end # AccessToken
|
21
|
+
end # module Qiniu
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'qiniu/tokens/access_token'
|
5
|
+
require 'qiniu/utils'
|
6
|
+
|
7
|
+
module Qiniu
|
8
|
+
class DownloadToken < AccessToken
|
9
|
+
|
10
|
+
include Utils
|
11
|
+
|
12
|
+
attr_accessor :pattern, :expires_in
|
13
|
+
|
14
|
+
def initialize(opts = {})
|
15
|
+
@pattern = opts[:pattern]
|
16
|
+
@expires_in = opts[:expires_in] || 3600
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate_signature
|
20
|
+
params = {"S" => @pattern, "E" => Time.now.to_i + @expires_in}
|
21
|
+
Utils.urlsafe_base64_encode(params.to_json)
|
22
|
+
end
|
23
|
+
|
24
|
+
def generate_token
|
25
|
+
signature = generate_signature
|
26
|
+
encoded_digest = generate_encoded_digest(signature)
|
27
|
+
%Q(#{@access_key}:#{encoded_digest}:#{signature})
|
28
|
+
end
|
29
|
+
|
30
|
+
end # moidule DownloadToken
|
31
|
+
end # module Qiniu
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'cgi'
|
4
|
+
require 'json'
|
5
|
+
require 'qiniu/tokens/access_token'
|
6
|
+
|
7
|
+
module Qiniu
|
8
|
+
class QboxToken < AccessToken
|
9
|
+
|
10
|
+
include Utils
|
11
|
+
|
12
|
+
attr_accessor :url, :params
|
13
|
+
|
14
|
+
def initialize(opts = {})
|
15
|
+
@url = opts[:url]
|
16
|
+
@params = opts[:params]
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate_signature
|
20
|
+
uri = URI.parse(@url)
|
21
|
+
signature = uri.path
|
22
|
+
query_string = uri.query
|
23
|
+
signature += '?' + query_string if !query_string.nil? && !query_string.empty?
|
24
|
+
signature += "\n"
|
25
|
+
if @params.is_a?(Hash)
|
26
|
+
params_string = Utils.generate_query_string(@params)
|
27
|
+
signature += params_string
|
28
|
+
end
|
29
|
+
signature
|
30
|
+
end
|
31
|
+
|
32
|
+
def generate_token
|
33
|
+
encoded_digest = generate_encoded_digest(generate_signature)
|
34
|
+
%Q(#{@access_key}:#{encoded_digest})
|
35
|
+
end
|
36
|
+
|
37
|
+
end # module QboxToken
|
38
|
+
end # module Qiniu
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'qiniu/tokens/access_token'
|
5
|
+
require 'qiniu/utils'
|
6
|
+
|
7
|
+
module Qiniu
|
8
|
+
class UploadToken < AccessToken
|
9
|
+
|
10
|
+
include Utils
|
11
|
+
|
12
|
+
attr_accessor :scope, :expires_in, :callback_url, :callback_body, :callback_body_type, :customer, :escape, :async_options, :return_body, :return_url
|
13
|
+
|
14
|
+
def initialize(opts = {})
|
15
|
+
@scope = opts[:scope]
|
16
|
+
@expires_in = opts[:expires_in] || 3600
|
17
|
+
@callback_url = opts[:callback_url]
|
18
|
+
@callback_body = opts[:callback_body]
|
19
|
+
@callback_body_type = opts[:callback_body_type]
|
20
|
+
@customer = opts[:customer]
|
21
|
+
@escape = opts[:escape]
|
22
|
+
@async_options = opts[:async_options]
|
23
|
+
@return_body = opts[:return_body]
|
24
|
+
@return_url = opts[:return_url]
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_signature
|
28
|
+
params = {:scope => @scope, :deadline => Time.now.to_i + @expires_in}
|
29
|
+
params[:callbackUrl] = @callback_url if !@callback_url.nil? && !@callback_url.empty?
|
30
|
+
params[:callbackBody] = @callback_body if !@callback_body.nil? && !@callback_body.empty?
|
31
|
+
params[:callbackBodyType] = @callback_body_type if !@callback_body_type.nil? && !@callback_body_type.empty?
|
32
|
+
params[:customer] = @customer if !@customer.nil? && !@customer.empty?
|
33
|
+
params[:escape] = 1 if @escape == 1 || @escape == true
|
34
|
+
params[:asyncOps] = @async_options if !@async_options.nil? && !@async_options.empty?
|
35
|
+
params[:returnBody] = @return_body if !@return_body.nil? && !@return_body.empty?
|
36
|
+
params[:returnUrl] = @return_url if !@return_url.nil? && !@return_url.empty?
|
37
|
+
Utils.urlsafe_base64_encode(params.to_json)
|
38
|
+
end
|
39
|
+
|
40
|
+
def generate_token
|
41
|
+
signature = generate_signature
|
42
|
+
encoded_digest = generate_encoded_digest(signature)
|
43
|
+
%Q(#{@access_key}:#{encoded_digest}:#{signature})
|
44
|
+
end
|
45
|
+
|
46
|
+
end # module UploadToken
|
47
|
+
end # module Qiniu
|
data/lib/qiniu/upload.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module Qiniu
|
4
|
+
module Storage
|
5
|
+
class << self
|
6
|
+
include Utils
|
7
|
+
|
8
|
+
def put_file(local_file,
|
9
|
+
bucket,
|
10
|
+
key = nil,
|
11
|
+
mime_type = nil,
|
12
|
+
custom_meta = nil,
|
13
|
+
enable_crc32_check = false)
|
14
|
+
action_params = _generate_action_params(
|
15
|
+
local_file,
|
16
|
+
bucket,
|
17
|
+
key,
|
18
|
+
mime_type,
|
19
|
+
custom_meta,
|
20
|
+
enable_crc32_check
|
21
|
+
)
|
22
|
+
|
23
|
+
url = Config.settings[:io_host] + action_params
|
24
|
+
options = {:content_type => 'application/octet-stream'}
|
25
|
+
|
26
|
+
Auth.request url, ::IO.read(local_file), options
|
27
|
+
end # put_file
|
28
|
+
|
29
|
+
def upload_with_token(uptoken,
|
30
|
+
local_file,
|
31
|
+
bucket,
|
32
|
+
key = nil,
|
33
|
+
mime_type = nil,
|
34
|
+
custom_meta = nil,
|
35
|
+
callback_params = nil,
|
36
|
+
enable_crc32_check = false,
|
37
|
+
rotate = nil)
|
38
|
+
action_params = _generate_action_params(
|
39
|
+
local_file,
|
40
|
+
bucket,
|
41
|
+
key,
|
42
|
+
mime_type,
|
43
|
+
custom_meta,
|
44
|
+
enable_crc32_check,
|
45
|
+
rotate
|
46
|
+
)
|
47
|
+
|
48
|
+
if callback_params.nil?
|
49
|
+
callback_params = {:bucket => bucket, :key => key, :mime_type => mime_type}
|
50
|
+
end
|
51
|
+
callback_query_string = Utils.generate_query_string(callback_params)
|
52
|
+
url = Config.settings[:up_host] + '/upload'
|
53
|
+
|
54
|
+
Utils.upload_multipart_data(url, local_file, action_params, callback_query_string, uptoken)
|
55
|
+
end # upload_with_token
|
56
|
+
|
57
|
+
def upload_with_token_2(uptoken,
|
58
|
+
local_file,
|
59
|
+
key = nil,
|
60
|
+
x_vars = nil)
|
61
|
+
### 构造URL
|
62
|
+
url = Config.settings[:up_host]
|
63
|
+
url[/\/*$/] = ''
|
64
|
+
url += '/'
|
65
|
+
|
66
|
+
### 构造HTTP Body
|
67
|
+
post_data = {
|
68
|
+
:file => File.new(local_file, 'rb'),
|
69
|
+
:multipart => true,
|
70
|
+
}
|
71
|
+
if not uptoken.nil?
|
72
|
+
post_data[:token] = uptoken
|
73
|
+
end
|
74
|
+
if not key.nil?
|
75
|
+
post_data[:key] = key
|
76
|
+
end
|
77
|
+
if x_vars.is_a?(Hash)
|
78
|
+
post_data.merge!(x_vars)
|
79
|
+
end
|
80
|
+
|
81
|
+
### 发送请求
|
82
|
+
Utils.http_request url, post_data
|
83
|
+
end # upload_with_token_2
|
84
|
+
|
85
|
+
private
|
86
|
+
def _generate_action_params(local_file,
|
87
|
+
bucket,
|
88
|
+
key = nil,
|
89
|
+
mime_type = nil,
|
90
|
+
custom_meta = nil,
|
91
|
+
enable_crc32_check = false,
|
92
|
+
rotate = nil)
|
93
|
+
raise NoSuchFileError, local_file unless File.exist?(local_file)
|
94
|
+
|
95
|
+
if key.nil?
|
96
|
+
key = Digest::SHA1.hexdigest(local_file + Time.now.to_s)
|
97
|
+
end
|
98
|
+
|
99
|
+
entry_uri = bucket + ':' + key
|
100
|
+
if mime_type.nil? || mime_type.empty?
|
101
|
+
mime = MIME::Types.type_for local_file
|
102
|
+
mime_type = mime.empty? ? 'application/octet-stream' : mime[0].content_type
|
103
|
+
end
|
104
|
+
|
105
|
+
action_params = '/rs-put/' + Utils.urlsafe_base64_encode(entry_uri) + '/mimeType/' + Utils.urlsafe_base64_encode(mime_type)
|
106
|
+
action_params += '/meta/' + Utils.urlsafe_base64_encode(custom_meta) unless custom_meta.nil?
|
107
|
+
action_params += '/crc32/' + Utils.crc32checksum(local_file).to_s if enable_crc32_check
|
108
|
+
action_params += '/rotate/' + rotate if !rotate.nil? && rotate.to_i >= 0
|
109
|
+
action_params
|
110
|
+
end # _generate_action_params
|
111
|
+
|
112
|
+
end # class << self
|
113
|
+
end # module Storage
|
114
|
+
end # module Qiniu
|
data/lib/qiniu/utils.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'cgi'
|
5
|
+
require 'json'
|
6
|
+
require 'zlib'
|
7
|
+
require 'base64'
|
8
|
+
require 'rest_client'
|
9
|
+
require 'hmac-sha1'
|
10
|
+
require 'qiniu/exceptions'
|
11
|
+
|
12
|
+
module Qiniu
|
13
|
+
module Utils extend self
|
14
|
+
|
15
|
+
def urlsafe_base64_encode content
|
16
|
+
Base64.encode64(content).strip.gsub('+', '-').gsub('/','_').gsub(/\r?\n/, '')
|
17
|
+
end
|
18
|
+
|
19
|
+
def urlsafe_base64_decode encoded_content
|
20
|
+
Base64.decode64 encoded_content.gsub('_','/').gsub('-', '+')
|
21
|
+
end
|
22
|
+
|
23
|
+
def encode_entry_uri(bucket, key)
|
24
|
+
entry_uri = bucket + ':' + key
|
25
|
+
urlsafe_base64_encode(entry_uri)
|
26
|
+
end
|
27
|
+
|
28
|
+
def safe_json_parse(data)
|
29
|
+
JSON.parse(data)
|
30
|
+
rescue JSON::ParserError
|
31
|
+
{}
|
32
|
+
end
|
33
|
+
|
34
|
+
def is_response_ok?(status_code)
|
35
|
+
status_code/100 == 2
|
36
|
+
end
|
37
|
+
|
38
|
+
def response_error(status_code, errmsg)
|
39
|
+
[status_code, {"error" => errmsg}]
|
40
|
+
end
|
41
|
+
|
42
|
+
def debug(msg)
|
43
|
+
if Config.settings[:enable_debug]
|
44
|
+
Log.logger.debug(msg)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def send_request_with url, data = nil, options = {}
|
49
|
+
options[:method] = Config.settings[:method] unless options[:method]
|
50
|
+
options[:content_type] = Config.settings[:content_type] unless options[:content_type]
|
51
|
+
header_options = {
|
52
|
+
:accept => :json,
|
53
|
+
:user_agent => Config.settings[:user_agent]
|
54
|
+
}
|
55
|
+
auth_token = nil
|
56
|
+
if !options[:qbox_signature_token].nil? && !options[:qbox_signature_token].empty?
|
57
|
+
auth_token = 'QBox ' + options[:qbox_signature_token]
|
58
|
+
elsif !options[:upload_signature_token].nil? && !options[:upload_signature_token].empty?
|
59
|
+
auth_token = 'UpToken ' + options[:upload_signature_token]
|
60
|
+
elsif options[:access_token]
|
61
|
+
auth_token = 'Bearer ' + options[:access_token]
|
62
|
+
end
|
63
|
+
header_options.merge!('Authorization' => auth_token) unless auth_token.nil?
|
64
|
+
case options[:method]
|
65
|
+
when :get
|
66
|
+
response = RestClient.get(url, header_options)
|
67
|
+
when :post
|
68
|
+
header_options.merge!(:content_type => options[:content_type])
|
69
|
+
response = RestClient.post(url, data, header_options)
|
70
|
+
end
|
71
|
+
code = response.respond_to?(:code) ? response.code.to_i : 0
|
72
|
+
unless is_response_ok?(code)
|
73
|
+
raise RequestFailed.new("Request Failed", response)
|
74
|
+
else
|
75
|
+
data = {}
|
76
|
+
body = response.respond_to?(:body) ? response.body : {}
|
77
|
+
data = safe_json_parse(body) unless body.empty?
|
78
|
+
end
|
79
|
+
[code, data]
|
80
|
+
end
|
81
|
+
|
82
|
+
def http_request url, data = nil, options = {}
|
83
|
+
retry_times = 0
|
84
|
+
begin
|
85
|
+
retry_times += 1
|
86
|
+
send_request_with url, data, options
|
87
|
+
rescue Errno::ECONNRESET => err
|
88
|
+
if Config.settings[:auto_reconnect] && retry_times < Config.settings[:max_retry_times]
|
89
|
+
retry
|
90
|
+
else
|
91
|
+
Log.logger.error err
|
92
|
+
end
|
93
|
+
rescue => e
|
94
|
+
Log.logger.warn "#{e.message} => Utils.http_request('#{url}')"
|
95
|
+
code = 0
|
96
|
+
data = {}
|
97
|
+
body = {}
|
98
|
+
if e.respond_to? :response
|
99
|
+
res = e.response
|
100
|
+
code = res.code.to_i if res.respond_to? :code
|
101
|
+
body = res.respond_to?(:body) ? res.body : ""
|
102
|
+
data = safe_json_parse(body) unless body.empty?
|
103
|
+
end
|
104
|
+
[code, data]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def upload_multipart_data(url, filepath, action_string, callback_query_string = '', uptoken = nil)
|
109
|
+
post_data = {
|
110
|
+
:params => callback_query_string,
|
111
|
+
:action => action_string,
|
112
|
+
:file => File.new(filepath, 'rb'),
|
113
|
+
:multipart => true
|
114
|
+
}
|
115
|
+
post_data[:auth] = uptoken unless uptoken.nil?
|
116
|
+
http_request url, post_data
|
117
|
+
end
|
118
|
+
|
119
|
+
def generate_query_string(params)
|
120
|
+
return params if params.is_a?(String)
|
121
|
+
total_param = params.map { |key, value| %Q(#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s).gsub('+', '%20')}) }
|
122
|
+
total_param.join("&")
|
123
|
+
end
|
124
|
+
|
125
|
+
def crc32checksum(filepath)
|
126
|
+
File.open(filepath, "rb") { |f| Zlib.crc32 f.read }
|
127
|
+
end
|
128
|
+
|
129
|
+
def generate_qbox_signature(url, params, mime = nil)
|
130
|
+
access_key = Config.settings[:access_key]
|
131
|
+
secret_key = Config.settings[:secret_key]
|
132
|
+
uri = URI.parse(url)
|
133
|
+
signature = uri.path
|
134
|
+
query_string = uri.query
|
135
|
+
signature += '?' + query_string if !query_string.nil? && !query_string.empty?
|
136
|
+
signature += "\n"
|
137
|
+
if params.is_a?(Hash)
|
138
|
+
params_string = generate_query_string(params)
|
139
|
+
signature += params_string
|
140
|
+
end
|
141
|
+
if mime.is_a?(String) && mime == "application/x-www-form-urlencoded" && params.is_a?(String)
|
142
|
+
signature += params
|
143
|
+
end
|
144
|
+
hmac = HMAC::SHA1.new(secret_key)
|
145
|
+
hmac.update(signature)
|
146
|
+
encoded_digest = urlsafe_base64_encode(hmac.digest)
|
147
|
+
%Q(#{access_key}:#{encoded_digest})
|
148
|
+
end
|
149
|
+
|
150
|
+
end # module Utils
|
151
|
+
end # module Qiniu
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module Qiniu
|
4
|
+
module Version
|
5
|
+
MAJOR = 6
|
6
|
+
MINOR = 0
|
7
|
+
PATCH = 1
|
8
|
+
# Returns a version string by joining <tt>MAJOR</tt>, <tt>MINOR</tt>, and <tt>PATCH</tt> with <tt>'.'</tt>
|
9
|
+
#
|
10
|
+
# Example
|
11
|
+
#
|
12
|
+
# Version.to_s # '1.0.2'
|
13
|
+
def self.to_s
|
14
|
+
[MAJOR, MINOR, PATCH].join('.')
|
15
|
+
end
|
16
|
+
end # Version
|
17
|
+
end # module Qiniu
|
data/qiniu.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require File.expand_path('../lib/qiniu/version', __FILE__)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.authors = ["why404"]
|
7
|
+
gem.email = ["why404@gmail.com"]
|
8
|
+
gem.description = %q{Qiniu Resource (Cloud) Storage SDK for Ruby. See: http://developer.qiniu.com/docs/v6/sdk/ruby-sdk.html}
|
9
|
+
gem.summary = %q{Qiniu Resource (Cloud) Storage SDK for Ruby}
|
10
|
+
gem.homepage = "https://github.com/qiniu/ruby-sdk"
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.name = "qiniu"
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.version = Qiniu::Version.to_s
|
18
|
+
|
19
|
+
# specify any dependencies here; for example:
|
20
|
+
gem.add_development_dependency "rake", ">= 0.9"
|
21
|
+
gem.add_development_dependency "rspec", ">= 2.11"
|
22
|
+
gem.add_development_dependency "fakeweb", "~> 1.3"
|
23
|
+
gem.add_runtime_dependency "json", "~> 1.7"
|
24
|
+
gem.add_runtime_dependency "rest-client", "~> 1.6"
|
25
|
+
gem.add_runtime_dependency "mime-types", "~> 1.19"
|
26
|
+
gem.add_runtime_dependency "ruby-hmac", "~> 0.4"
|
27
|
+
gem.add_runtime_dependency "jruby-openssl", "~> 0.7" if RUBY_PLATFORM == "java"
|
28
|
+
end
|