qinium 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 97006dadb420603b659536192b0d996ddb925d6ec024fc5553970b437b45553e
4
+ data.tar.gz: 2de51b37c7a5e8c314724c2594525885e086ea5d764888b922d6f91cec2e1c66
5
+ SHA512:
6
+ metadata.gz: 5f907d3494a958568d0aeabfc978133b1eabd46f04da4e55e536da7b8611e0bec2dc0f1a92772c4e588ad5c9f5f6f46c6abb6d5e9842abc79f091de5f4b5553e
7
+ data.tar.gz: ddc54d441f0dca3e48a6f7a14762f7b5d37624e10100a2561b1ef06bd8541c3156c5ed6d72fec2b194b5d307cb55803be874f67028349c848254a4c3127eb174
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: double_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2022-08-10
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in qinium.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rspec", "~> 3.0"
11
+
12
+ gem "rubocop", "~> 1.21"
13
+
14
+ gem "vcr", "~> 6.1"
15
+
16
+ gem "webmock", "~> 3.17"
data/Gemfile.lock ADDED
@@ -0,0 +1,68 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ qinium (0.1.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ addressable (2.8.0)
10
+ public_suffix (>= 2.0.2, < 5.0)
11
+ ast (2.4.2)
12
+ crack (0.4.5)
13
+ rexml
14
+ diff-lcs (1.5.0)
15
+ hashdiff (1.0.1)
16
+ parallel (1.22.1)
17
+ parser (3.1.1.0)
18
+ ast (~> 2.4.1)
19
+ public_suffix (4.0.7)
20
+ rainbow (3.1.1)
21
+ rake (13.0.6)
22
+ regexp_parser (2.5.0)
23
+ rexml (3.2.5)
24
+ rspec (3.11.0)
25
+ rspec-core (~> 3.11.0)
26
+ rspec-expectations (~> 3.11.0)
27
+ rspec-mocks (~> 3.11.0)
28
+ rspec-core (3.11.0)
29
+ rspec-support (~> 3.11.0)
30
+ rspec-expectations (3.11.0)
31
+ diff-lcs (>= 1.2.0, < 2.0)
32
+ rspec-support (~> 3.11.0)
33
+ rspec-mocks (3.11.1)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.11.0)
36
+ rspec-support (3.11.0)
37
+ rubocop (1.27.0)
38
+ parallel (~> 1.10)
39
+ parser (>= 3.1.0.0)
40
+ rainbow (>= 2.2.2, < 4.0)
41
+ regexp_parser (>= 1.8, < 3.0)
42
+ rexml
43
+ rubocop-ast (>= 1.16.0, < 2.0)
44
+ ruby-progressbar (~> 1.7)
45
+ unicode-display_width (>= 1.4.0, < 3.0)
46
+ rubocop-ast (1.17.0)
47
+ parser (>= 3.1.1.0)
48
+ ruby-progressbar (1.11.0)
49
+ unicode-display_width (2.1.0)
50
+ vcr (6.1.0)
51
+ webmock (3.17.1)
52
+ addressable (>= 2.8.0)
53
+ crack (>= 0.3.2)
54
+ hashdiff (>= 0.4.0, < 2.0.0)
55
+
56
+ PLATFORMS
57
+ ruby
58
+
59
+ DEPENDENCIES
60
+ qinium!
61
+ rake (~> 13.0)
62
+ rspec (~> 3.0)
63
+ rubocop (~> 1.21)
64
+ vcr (~> 6.1)
65
+ webmock (~> 3.17)
66
+
67
+ BUNDLED WITH
68
+ 2.3.9
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 张小辉
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # Qinium
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/qinium`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Install the gem and add to the application's Gemfile by executing:
10
+
11
+ $ bundle add qinium
12
+
13
+ If bundler is not being used to manage dependencies, install the gem by executing:
14
+
15
+ $ gem install qinium
16
+
17
+ ## Usage
18
+
19
+ TODO: Write usage instructions here
20
+
21
+ ## Development
22
+
23
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
24
+
25
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
26
+
27
+ ## Contributing
28
+
29
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/qinium.
30
+
31
+ ## License
32
+
33
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,36 @@
1
+ class Qinium
2
+ module Auth
3
+ extend self
4
+
5
+ def calculate_hmac_sha1_digest(secret_key, str)
6
+ OpenSSL::HMAC.digest(OpenSSL::Digest.new("sha1"), secret_key, str)
7
+ end
8
+
9
+ def generate_access_token(access_key, secret_key, url, body = {})
10
+ encoded_sign = generate_access_token_sign_with_mac(secret_key, url, body)
11
+
12
+ "#{access_key}:#{encoded_sign}"
13
+ end
14
+
15
+ def generate_access_token_sign_with_mac(secret_key, url, body)
16
+ ### 解析URL,生成待签名字符串
17
+ uri = URI.parse(url)
18
+ signing_str = uri.path
19
+
20
+ # 如有QueryString部分,则需要加上
21
+ query_string = uri.query
22
+ signing_str += "?" + query_string if query_string.is_a?(String) && !query_string.empty?
23
+
24
+ # 追加换行符
25
+ signing_str += "\n"
26
+
27
+ # 如果有Body,则也加上
28
+ # (仅限于mime == "application/x-www-form-urlencoded"的情况)
29
+ signing_str += body if body.is_a?(String) && !body.strip.empty?
30
+
31
+ ### 生成数字签名
32
+ sign = calculate_hmac_sha1_digest(secret_key, signing_str)
33
+ Utils.urlsafe_base64_encode(sign)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,138 @@
1
+ class Qinium
2
+ class Client
3
+ include Qinium::Utils
4
+
5
+ attr_reader :config
6
+
7
+ def initialize(config)
8
+ @config = config
9
+ end
10
+
11
+ # rubocop: disable Style/SingleLineMethods
12
+ def user_agent; config.user_agent end
13
+ def access_key; config.access_key end
14
+ def secret_key; config.secret_key end
15
+ # rubocop: enable Style/SingleLineMethods
16
+
17
+ def get(url, opts = {})
18
+ opts[:raise] = true unless opts.key?(:raise)
19
+ req_headers = {
20
+ connection: "close",
21
+ accept: "*/*",
22
+ user_agent: user_agent
23
+ }
24
+ req_headers.merge!(opts[:headers]) if opts[:headers].is_a?(Hash)
25
+
26
+ uri = URI(url)
27
+ http = Net::HTTP.new(uri.host, uri.port)
28
+ if uri.scheme == "https"
29
+ http.use_ssl = true
30
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
31
+ end
32
+
33
+ logger.debug "Get #{uri}"
34
+ logger.debug " options: #{opts.to_json}"
35
+
36
+ req = Net::HTTP::Get.new(uri)
37
+ req_headers.each_pair do |key, value|
38
+ req.add_field key, value
39
+ end
40
+ res = http.request(req)
41
+ code = res.code.to_i
42
+ body = res.body
43
+ headers = res.header.to_hash.transform_values do |v|
44
+ v.join(", ")
45
+ end
46
+
47
+ if headers["content-type"] == "application/json"
48
+ body = begin
49
+ JSON.parse(body)
50
+ rescue StandardError
51
+ {}
52
+ end
53
+ end
54
+ raise APIError.new(code, body, headers) if opts[:raise] && !success?(code)
55
+
56
+ [code, body, headers]
57
+ end
58
+
59
+ def post(url, req_body = "", opts = {})
60
+ opts[:raise] = true unless opts.key?(:raise)
61
+ req_headers = {
62
+ connection: "close",
63
+ accept: "*/*",
64
+ user_agent: user_agent
65
+ }
66
+ req_headers.merge!(opts[:headers]) if opts[:headers].is_a?(Hash)
67
+
68
+ uri = URI(url)
69
+ http = Net::HTTP.new(uri.host, uri.port)
70
+ if uri.scheme == "https"
71
+ http.use_ssl = true
72
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
73
+ end
74
+
75
+ logger.debug "POST #{uri}"
76
+ logger.debug " body: #{req_body[0, 50]}"
77
+ logger.debug " headers: #{opts.to_json}"
78
+
79
+ req = Net::HTTP::Post.new(uri)
80
+ req_headers.each_pair do |key, value|
81
+ req.add_field key, value
82
+ end
83
+ req.body = req_body
84
+ res = http.request(req)
85
+ code = res.code.to_i
86
+ body = res.body
87
+ headers = res.header.to_hash.transform_values do |v|
88
+ v.join(", ")
89
+ end
90
+ if headers["content-type"] == "application/json"
91
+ body = begin
92
+ JSON.parse(body)
93
+ rescue StandardError
94
+ nil
95
+ end
96
+ end
97
+ raise APIError.new(code, body, headers) if opts[:raise] && !success?(code)
98
+
99
+ [code, body, headers]
100
+ end
101
+
102
+ def management_get(url)
103
+ access_token = Auth.generate_access_token(access_key, secret_key, url)
104
+ get(url, headers: {
105
+ "Content-Type" => "application/x-www-form-urlencoded",
106
+ "Authorization" => "QBox " + access_token
107
+ })
108
+ end
109
+
110
+ def management_post(url, body = nil)
111
+ body = JSON.dump(body) if body && body.size > 0
112
+ access_token = Auth.generate_access_token(access_key, secret_key, url, body)
113
+ post(url, body, headers: {
114
+ "Content-Type" => "application/x-www-form-urlencoded",
115
+ "Authorization" => "QBox " + access_token
116
+ })
117
+ end
118
+
119
+ def self.success?(http_code)
120
+ http_code.between?(200, 299)
121
+ end
122
+
123
+ def success?(http_code)
124
+ self.class.success?(http_code)
125
+ end
126
+
127
+ def self.to_query(params)
128
+ if params.is_a?(Hash)
129
+ total_param = params.map do |key, value|
130
+ %(#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s).gsub("+", "%20")})
131
+ end
132
+ return total_param.join("&")
133
+ end
134
+
135
+ params
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,66 @@
1
+ class Qinium
2
+ class Config < Configurable
3
+ def initialize(options = {})
4
+ options[:protocol] ||= :https
5
+ options = if options[:protocol] == :http
6
+ http_options.merge(options)
7
+ else
8
+ https_options.merge(options)
9
+ end
10
+ super(default_options.merge(options))
11
+ end
12
+
13
+ def up_host(bucket = self.bucket)
14
+ HostManager.new(self).up_host(bucket)
15
+ end
16
+
17
+ def put_policy_options
18
+ @put_policy_options ||= self[:put_policy_options] || Configurable.new
19
+ end
20
+
21
+ private
22
+
23
+ def default_options
24
+ {
25
+ user_agent: "QiniumRuby/#{VERSION} (#{RUBY_PLATFORM}) Ruby/#{RUBY_VERSION}",
26
+ method: :post,
27
+ content_type: "application/x-www-form-urlencoded",
28
+ auth_url: "https://acc.qbox.me/oauth2/token",
29
+ access_key: "",
30
+ secret_key: "",
31
+ auto_reconnect: true,
32
+ max_retry_times: 3,
33
+ block_size: 1024 * 1024 * 4,
34
+ chunk_size: 1024 * 256,
35
+ enable_debug: true,
36
+ tmpdir: Dir.tmpdir + File::SEPARATOR + "QiniuRuby",
37
+ multi_region: false,
38
+ bucket_private: false
39
+ }.freeze
40
+ end
41
+
42
+ def http_options
43
+ {
44
+ rs_host: "http://rs.qiniu.com",
45
+ rsf_host: "http://rsf.qbox.me",
46
+ pub_host: "http://pu.qbox.me:10200",
47
+ eu_host: "http://eu.qbox.me",
48
+ uc_host: "http://uc.qbox.me",
49
+ api_host: "http://api.qiniu.com",
50
+ protocol: :http
51
+ }.freeze
52
+ end
53
+
54
+ def https_options
55
+ {
56
+ rs_host: "https://rs.qbox.me",
57
+ rsf_host: "https://rsf.qbox.me",
58
+ pub_host: "https://pu.qbox.me",
59
+ eu_host: "https://eu.qbox.me",
60
+ uc_host: "https://uc.qbox.me",
61
+ api_host: "https://api.qiniu.com",
62
+ protocol: :https
63
+ }.freeze
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,26 @@
1
+ class Qinium
2
+ class Configurable < Hash
3
+ def initialize(defaults = {})
4
+ defaults.each_pair do |k, v|
5
+ self[k.to_sym] = v.is_a?(Hash) ? Configurable.new(v) : v
6
+ end
7
+ end
8
+
9
+ def []=(k, v)
10
+ super(k.to_sym, v)
11
+ end
12
+
13
+ def method_missing(method, *args)
14
+ if method.to_s.end_with?("=")
15
+ self[method.to_s[0..-2].to_sym] = args[0]
16
+ else
17
+ fetch(method.to_sym)
18
+ end
19
+ end
20
+
21
+ def respond_to_missing?(method)
22
+ key = method.to_s.end_with?("=") ? method.to_s[0..-2].to_sym : method
23
+ key?(key)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,14 @@
1
+ class Qinium
2
+ Error = Class.new(StandardError)
3
+
4
+ class APIError < StandardError
5
+ attr_reader :code, :body, :headers
6
+
7
+ def initialize(code, body, headers)
8
+ @code = code
9
+ @body = body
10
+ @headers = headers
11
+ super(body)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,91 @@
1
+ class Qinium
2
+ class HostManager
3
+ class Cache
4
+ def initialize
5
+ @mutex = Mutex.new
6
+ @hosts = {}
7
+ end
8
+
9
+ def read(access_key, bucket, &block)
10
+ @mutex.synchronize do
11
+ key = cache_key(access_key, bucket)
12
+ data = @hosts[key]
13
+ if data && Time.now.to_i > data["expires_at"]
14
+ @hosts.delete key
15
+ data = nil
16
+ end
17
+ if data.nil?
18
+ data = block.call
19
+ data["expires_at"] = Time.now.to_i + data["ttl"]
20
+ @hosts[key] = data.freeze
21
+ end
22
+ data
23
+ end
24
+ end
25
+
26
+ def write(access_key, bucket, hosts)
27
+ @mutex.synchronize do
28
+ @hosts[cache_key(access_key, bucket)] = hosts
29
+ end
30
+ end
31
+
32
+ def delete(access_key, bucket)
33
+ @mutex.synchronize do
34
+ @hosts.delete(cache_key(access_key, bucket))
35
+ end
36
+ end
37
+
38
+ def cache_key(access_key, bucket)
39
+ Digest::SHA1.base64digest "#{access_key}-#{bucket}"
40
+ end
41
+ end
42
+
43
+ def self.cache
44
+ @cache ||= Cache.new
45
+ end
46
+
47
+ attr_reader :config
48
+
49
+ def initialize(config)
50
+ @config = config
51
+ end
52
+
53
+ def up_host(bucket, opts = {})
54
+ up_hosts(bucket, opts)[0]
55
+ end
56
+
57
+ def up_hosts(bucket, opts = {})
58
+ hosts = hosts(bucket)
59
+ hosts[extract_protocol(opts)]["up"]
60
+ end
61
+
62
+ def hosts(bucket)
63
+ raise Error, "access_key is missing" if Utils.blank?(access_key)
64
+ raise Error, "bucket is missing" if Utils.blank?(bucket)
65
+
66
+ cache.read(access_key, bucket) do
67
+ query = Client.to_query(ak: access_key, bucket: bucket)
68
+ url = "#{config.uc_host}/v1/query?#{query}"
69
+ http = Client.new(config)
70
+ code, body, headers = http.get(url)
71
+ raise APIError.new(code, body, headers) unless Client.success?(code)
72
+
73
+ body
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def cache
80
+ self.class.cache
81
+ end
82
+
83
+ def access_key
84
+ config.access_key
85
+ end
86
+
87
+ def extract_protocol(opts)
88
+ (opts[:protocol] || config.protocol).to_s
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,50 @@
1
+ class Qinium
2
+ class Object
3
+ include Qinium::Utils
4
+
5
+ attr_reader :client
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ # rubocop: disable Style/SingleLineMethods
12
+ def config; client.config end
13
+ def bucket; config.bucket end
14
+ # rubocop: enable Style/SingleLineMethods
15
+
16
+ def mkblk(blk, token:, host: nil)
17
+ host ||= config.up_host
18
+ client.post("#{host}/mkblk/#{blk.size}", blk, headers: {
19
+ "Content-Type" => "application/octet-stream",
20
+ "Content-Length" => blk.size,
21
+ "Authorization" => "UpToken #{token}"
22
+ })
23
+ end
24
+
25
+ def mkfile(token:, file_size:, blocks:, key: nil, fname: nil, mime_type: nil, user_vars: nil)
26
+ url = config.up_host
27
+ url += "/mkfile/#{file_size}"
28
+ url += "/key/#{urlsafe_base64_encode(key)}" if key
29
+ url += "/fname/#{urlsafe_base64_encode(fname)}" if fname
30
+ url += "/mimeType/#{urlsafe_base64_encode(mime_type)}" if mime_type
31
+ url += "/x:user-var/#{urlsafe_base64_encode(user_vars)}" if user_vars
32
+ client.post(url, blocks.join(","), headers: {
33
+ "Context-Type" => "text/plain",
34
+ "Authorization" => "UpToken #{token}"
35
+ })
36
+ end
37
+
38
+ def delete(key, bucket: self.bucket)
39
+ client.management_post(config.rs_host + "/delete/" + Utils.encode_entry_uri(
40
+ bucket, key
41
+ ))
42
+ end
43
+
44
+ def list(bucket: self.bucket, marker: "", limit: 1000, prefix: "", delimiter: "")
45
+ query_string = to_query_string(bucket: bucket, marker: marker, limit: limit, prefix: prefix,
46
+ delimiter: delimiter)
47
+ client.management_get(config.rsf_host + "/list?" + query_string)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,91 @@
1
+ class Qinium
2
+ class PutPolicy
3
+ include Qinium::Utils
4
+
5
+ DEFAULT_AUTH_SECONDS = 300
6
+
7
+ PARAMS = {
8
+ # 字符串类型参数
9
+ scope: "scope",
10
+ is_prefixal_scope: "isPrefixalScope",
11
+ save_key: "saveKey",
12
+ end_user: "endUser",
13
+ return_url: "returnUrl",
14
+ return_body: "returnBody",
15
+ callback_url: "callbackUrl",
16
+ callback_host: "callbackHost",
17
+ callback_body: "callbackBody",
18
+ callback_body_type: "callbackBodyType",
19
+ persistent_ops: "persistentOps",
20
+ persistent_notify_url: "persistentNotifyUrl",
21
+ persistent_pipeline: "persistentPipeline",
22
+
23
+ # 数值类型参数
24
+ deadline: "deadline",
25
+ insert_only: "insertOnly",
26
+ fsize_min: "fsizeMin",
27
+ fsize_limit: "fsizeLimit",
28
+ detect_mime: "detectMime",
29
+ mime_limit: "mimeLimit",
30
+ uphosts: "uphosts",
31
+ global: "global",
32
+ delete_after_days: "deleteAfterDays",
33
+ file_type: "fileType"
34
+ }
35
+
36
+ PARAMS.each_pair do |key, _|
37
+ attr_accessor key
38
+ end
39
+
40
+ attr_reader :config, :bucket, :key
41
+
42
+ def initialize(config, bucket: nil, key: nil, expires_in: DEFAULT_AUTH_SECONDS)
43
+ @config = config
44
+ scope!(bucket || config.bucket, key)
45
+ expires_in! expires_in
46
+ end
47
+
48
+ def scope!(bucket, key = nil)
49
+ @bucket = bucket
50
+ @key = key
51
+
52
+ @scope = if key.nil?
53
+ # 新增语义,文件已存在则失败
54
+ bucket
55
+ else
56
+ # 覆盖语义,文件已存在则直接覆盖
57
+ "#{bucket}:#{key}"
58
+ end
59
+ end
60
+
61
+ def expires_in!(seconds)
62
+ @deadline = Time.now.to_i + seconds
63
+ end
64
+
65
+ def to_json(*_args)
66
+ args = {}
67
+
68
+ PARAMS.each_pair do |key, fld|
69
+ val = __send__(key)
70
+ args[fld] = val unless val.nil?
71
+ end
72
+
73
+ args.to_json
74
+ end
75
+
76
+ def to_token
77
+ access_key = config.access_key
78
+ secret_key = config.secret_key
79
+
80
+ ### 生成待签名字符串
81
+ encoded_put_policy = urlsafe_base64_encode(to_json)
82
+
83
+ ### 生成数字签名
84
+ sign = Auth.calculate_hmac_sha1_digest(secret_key, encoded_put_policy)
85
+ encoded_sign = urlsafe_base64_encode(sign)
86
+
87
+ ### 生成上传授权凭证
88
+ "#{access_key}:#{encoded_sign}:#{encoded_put_policy}"
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,43 @@
1
+ class Qinium
2
+ module Utils
3
+ extend self
4
+
5
+ def urlsafe_base64_encode(content)
6
+ Base64.encode64(content).strip.gsub("+", "-").gsub("/", "_").gsub(/\r?\n/, "")
7
+ end
8
+
9
+ def urlsafe_base64_decode(encoded_content)
10
+ Base64.decode64 encoded_content.gsub("_", "/").gsub("-", "+")
11
+ end
12
+
13
+ def encode_entry_uri(bucket, key)
14
+ entry_uri = bucket + ":" + key
15
+ urlsafe_base64_encode(entry_uri)
16
+ end
17
+
18
+ def blank?(obj)
19
+ case obj
20
+ when String then obj.strip.empty?
21
+ when NilClass then true
22
+ when Array, Hash then obj.size.zero?
23
+ else
24
+ false
25
+ end
26
+ end
27
+
28
+ def to_query_string(hash)
29
+ args = []
30
+ hash.keys.sort_by(&:to_s).each do |key|
31
+ value = hash[key]
32
+ next if value.nil?
33
+
34
+ args.push("#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}")
35
+ end
36
+ args.join("&")
37
+ end
38
+
39
+ def logger
40
+ @logger ||= Logger.new(STDOUT, level: Qinium.logger_level)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,3 @@
1
+ class Qinium
2
+ VERSION = "0.1.1"
3
+ end
data/lib/qinium.rb ADDED
@@ -0,0 +1,39 @@
1
+ class Qinium
2
+ require "logger"
3
+ require "base64"
4
+ require "tempfile"
5
+ require "openssl"
6
+ require "digest/sha1"
7
+ require "cgi"
8
+ require "net/http"
9
+ require "json"
10
+ require "qinium/version"
11
+ require "qinium/errors"
12
+ require "qinium/utils"
13
+ require "qinium/configurable"
14
+ require "qinium/config"
15
+ require "qinium/client"
16
+ require "qinium/host_manager"
17
+ require "qinium/auth"
18
+ require "qinium/object"
19
+ require "qinium/put_policy"
20
+
21
+ @logger_level = :info
22
+ class << self
23
+ attr_accessor :logger_level
24
+ end
25
+
26
+ attr_reader :config
27
+
28
+ def initialize(options = {})
29
+ @config = Config.new(options)
30
+ end
31
+
32
+ def object
33
+ @object ||= Object.new(client)
34
+ end
35
+
36
+ def client
37
+ @client ||= Client.new(config)
38
+ end
39
+ end
data/qinium.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/qinium/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "qinium"
7
+ spec.version = Qinium::VERSION
8
+ spec.authors = ["xiaohui"]
9
+ spec.email = ["xiaohui@tanmer.com"]
10
+
11
+ spec.summary = "Qiniu Cloud Storage SDK for multi-tenant system"
12
+ spec.description = "Qiniu Cloud Storage SDK for multi-tenant system, can call API with multiple accounts"
13
+ spec.homepage = "https://github.com/xiaohui-zhangxh/qinium"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 2.6.0"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = spec.homepage
19
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
+ end
27
+ end
28
+
29
+ spec.require_paths = ["lib"]
30
+ end
data/sig/qinium.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Qinium
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qinium
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - xiaohui
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-08-10 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Qiniu Cloud Storage SDK for multi-tenant system, can call API with multiple
14
+ accounts
15
+ email:
16
+ - xiaohui@tanmer.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".rspec"
22
+ - ".rubocop.yml"
23
+ - CHANGELOG.md
24
+ - Gemfile
25
+ - Gemfile.lock
26
+ - LICENSE.txt
27
+ - README.md
28
+ - Rakefile
29
+ - lib/qinium.rb
30
+ - lib/qinium/auth.rb
31
+ - lib/qinium/client.rb
32
+ - lib/qinium/config.rb
33
+ - lib/qinium/configurable.rb
34
+ - lib/qinium/errors.rb
35
+ - lib/qinium/host_manager.rb
36
+ - lib/qinium/object.rb
37
+ - lib/qinium/put_policy.rb
38
+ - lib/qinium/utils.rb
39
+ - lib/qinium/version.rb
40
+ - qinium.gemspec
41
+ - sig/qinium.rbs
42
+ homepage: https://github.com/xiaohui-zhangxh/qinium
43
+ licenses:
44
+ - MIT
45
+ metadata:
46
+ homepage_uri: https://github.com/xiaohui-zhangxh/qinium
47
+ source_code_uri: https://github.com/xiaohui-zhangxh/qinium
48
+ changelog_uri: https://github.com/xiaohui-zhangxh/qinium/CHANGELOG.md
49
+ post_install_message:
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: 2.6.0
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubygems_version: 3.3.7
65
+ signing_key:
66
+ specification_version: 4
67
+ summary: Qiniu Cloud Storage SDK for multi-tenant system
68
+ test_files: []