qiniu 6.6.0 → 6.9.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 6156890d8118959d78f316edf9c7de45fd66affe
4
- data.tar.gz: b4750d7adf8b61b924af905c4fe91757e468cf97
2
+ SHA256:
3
+ metadata.gz: 1a186af33928bfc26c7918fa28e2d3b747c3ee0917f75feaded835d778d61cdd
4
+ data.tar.gz: ed06c6e414c438b98ad98ed258c542ccca9d424541b9378a8a9426f83ba79ec3
5
5
  SHA512:
6
- metadata.gz: 49ce22e5fdc92699eb5eed74f9c6c19db50896370c2704251bfb4aa8dd8dd65a575d6c64fe8dbcddbe37560cc29f7b8ba44697f5d531412767c5fec1c119acae
7
- data.tar.gz: 5d2df9eb2a1533d9fbf07cc16339779699b9f24f6a00c9a0a2b598206082d9ec742b2eacaa42cb268380f22dd4b064201c9067c2c825588a1c73d41375862e6e
6
+ metadata.gz: 21ea48d66bb48632d71195d87a2be48eaa1ac492d2033203599f8c82850c8502d1d1a1af21e64f749b9398e7d5762047a91e7b3d83fe997b50d4ff393ad0f4b8
7
+ data.tar.gz: 8d6cd1a2fe505c41ec3937a0d918d44315721103c39f49293ad4e1600c342068d4b41a5288caf6a5c539d2a60d4b6f23ba9fd1a86abe75f5d97439cabf0e28ab
@@ -1,14 +1,42 @@
1
1
  ## CHANGE LOG
2
2
 
3
- ### V6.6.0
3
+ ### v6.9.0
4
+
5
+ - 增加 `Qiniu.establish_https_connection!` 方法,使所有七牛请求都使用 HTTPS 协议,保证连接的安全性。
6
+
7
+ - 重构随 gem 附带的 example 中的代码,使用更简洁易用的 API。
8
+
9
+ - 移除 `Qiniu::Config::DEFAULT_OPTIONS`,用户可以调用 `Qiniu::Config.settings` 获取七牛配置。
10
+
11
+ - 移除 `Qiniu.get`,`Qiniu.download` 和 `Qiniu::Storage.get` 方法以及它们的 `batch` 版本。
12
+
13
+ - 移除对于 Fixnum 的使用,支持 Ruby 2.4.x
14
+
15
+ ### v6.8.1
16
+
17
+ - 增加delafterdays 策略。[https://github.com/qiniu/ruby-sdk/pull/162](https://github.com/qiniu/ruby-sdk/pull/162)
18
+
19
+ - 调整依赖。[https://github.com/qiniu/ruby-sdk/pull/167](https://github.com/qiniu/ruby-sdk/pull/167)
20
+
21
+ ### v6.8.0
22
+
23
+ - 支持多存储区域,部分 API 需要额外的 bucket 参数。[https://github.com/qiniu/ruby-sdk/pull/161](https://github.com/qiniu/ruby-sdk/pull/161)
24
+
25
+ ### v6.7.0
26
+
27
+ - 放弃支持过时的 Ruby 1.9、Ruby 2.0 和 JRuby 1.7。[https://github.com/qiniu/ruby-sdk/pull/149](https://github.com/qiniu/ruby-sdk/pull/149)
28
+ - 更好地支持 Rails 4。
29
+ - 确保自动化测试在 CI 上完全通过,为下一步开发做准备。
30
+
31
+ ### v6.6.0
4
32
 
5
33
  - 添加 upload_buffer_with_put_policy() 方法,直接上传一块数据作为文件内容。[https://github.com/qiniu/ruby-sdk/pull/146](https://github.com/qiniu/ruby-sdk/pull/146)
6
34
 
7
- ### V6.5.2
35
+ ### v6.5.2
8
36
 
9
37
  - 修正无法触发加载异常类的问题;修正 batch_move 参数未正确打包的问题。[https://github.com/qiniu/ruby-sdk/pull/142](https://github.com/qiniu/ruby-sdk/pull/142)
10
38
 
11
- ### V6.5.1
39
+ ### v6.5.1
12
40
 
13
41
  - 为 Qiniu::Auth 添加验证七牛回调请求签名合法性的函数。[https://github.com/qiniu/ruby-sdk/pull/133](https://github.com/qiniu/ruby-sdk/pull/133)
14
42
 
data/README.md CHANGED
@@ -1,21 +1,35 @@
1
1
  # Qiniu Resource (Cloud) Storage SDK for Ruby
2
2
 
3
+ [![LICENSE](https://img.shields.io/github/license/qiniu/ruby-sdk.svg)](https://github.com/qiniu/ruby-sdk/blob/master/LICENSE)
4
+ [![Build Status](https://travis-ci.org/qiniu/ruby-sdk.svg?branch=develop)](https://travis-ci.org/qiniu/ruby-sdk)
5
+ [![GitHub release](https://img.shields.io/github/v/tag/qiniu/ruby-sdk.svg?label=release)](https://github.com/qiniu/ruby-sdk/releases)
6
+ [![Coverage Status](https://codecov.io/gh/qiniu/ruby-sdk/branch/develop/graph/badge.svg)](https://codecov.io/gh/qiniu/ruby-sdk)
7
+ [![Gem Version](https://badge.fury.io/rb/qiniu.svg)](http://badge.fury.io/rb/qiniu)
8
+ [![Dependency Status](https://gemnasium.com/qiniu/ruby-sdk.svg)](https://gemnasium.com/qiniu/ruby-sdk)
9
+ [![Code Climate](https://codeclimate.com/github/qiniu/ruby-sdk.svg)](https://codeclimate.com/github/qiniu/ruby-sdk)
10
+
3
11
  ## 关于
4
12
 
5
- 此 Ruby SDK 适用于 Ruby 1.9.x, 2.0.x, 2.1.x, jruby版本,基于 [七牛云存储官方API](http://developer.qiniu.com/docs/v6/index.html) 构建。使用此 SDK 构建您的网络应用程序,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。无论您的网络应用是一个网站程序,还是包括从云端(服务端程序)到终端(手持设备应用)的架构的服务或应用,通过七牛云存储及其 SDK,都能让您应用程序的终端用户高速上传和下载,同时也让您的服务端更加轻盈。
13
+ 此 Ruby SDK 基于 [七牛云存储官方API](http://developer.qiniu.com/docs/v6/index.html) 构建。使用此 SDK 构建您的网络应用程序,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。无论您的网络应用是一个网站程序,还是包括从云端(服务端程序)到终端(手持设备应用)的架构的服务或应用,通过七牛云存储及其 SDK,都能让您应用程序的终端用户高速上传和下载,同时也让您的服务端更加轻盈。
14
+
15
+ 支持的 Ruby 版本:
6
16
 
7
- ## 状态
17
+ * Ruby 2.1.x
18
+ * Ruby 2.2.x
19
+ * Ruby 2.3.x
20
+ * Ruby 2.4.x
21
+ * Ruby 2.5.x
22
+ * Ruby 2.6.x
23
+ * Ruby 2.7.x
24
+ * JRuby 9.x
8
25
 
9
- [![Build Status](https://api.travis-ci.org/qiniu/ruby-sdk.png?branch=master)](https://travis-ci.org/qiniu/ruby-sdk)
10
- [![Gem Version](https://badge.fury.io/rb/qiniu.png)](http://badge.fury.io/rb/qiniu)
11
- [![Dependency Status](https://gemnasium.com/qiniu/ruby-sdk.png)](https://gemnasium.com/qiniu/ruby-sdk)
12
- [![Code Climate](https://codeclimate.com/github/qiniu/ruby-sdk.png)](https://codeclimate.com/github/qiniu/ruby-sdk)
26
+ 如果您的应用程序需要在 Ruby 1.9、2.0 或 JRuby 1.7 上运行,请使用此 Ruby SDK 的 6.6.0 版本。
13
27
 
14
28
  ## 安装
15
29
 
16
30
  在您 Ruby 应用程序的 `Gemfile` 文件中,添加如下一行代码:
17
31
 
18
- gem 'qiniu', '=> 6.4.1', '<= 6.6.0'
32
+ gem 'qiniu', '>= 6.9.1'
19
33
 
20
34
  然后,在应用程序所在的目录下,可以运行 `bundle` 安装依赖包:
21
35
 
@@ -25,14 +39,6 @@
25
39
 
26
40
  $ gem install qiniu
27
41
 
28
- ## Rails 4 项目安装
29
-
30
- 在 Rails 4 项目的 `Gemfile` 里添加 `qiniu` 后执行 `bundle` 命令可能会失败,这是因为 Rails 4 项目默认会使用 `mime-types` 3.x 版本。需要使用以下命令将 `mime-types` 降级为满足 Qiniu Ruby SDK 的 2.6.x 版本。
31
-
32
- bundle update mime-types
33
-
34
- 由于 `mime-types` 3.0 要求的最低 Ruby 版本是 2.0,而 Qiniu Ruby SDK 支持 Ruby 1.9,因此我们不能通过简单修改对 `mime-types` 的版本依赖来解决此问题。
35
-
36
42
  ## 使用
37
43
 
38
44
  参考文档:[七牛云存储 Ruby SDK 使用指南](http://developer.qiniu.com/docs/v6/sdk/ruby-sdk.html)
@@ -3,19 +3,21 @@
3
3
  require 'qiniu/exceptions'
4
4
 
5
5
  module Qiniu
6
- autoload :Version, 'qiniu/version'
7
- autoload :Utils, 'qiniu/utils'
8
- autoload :Auth, 'qiniu/auth'
9
- autoload :Config, 'qiniu/config'
10
- autoload :Log, 'qiniu/log'
11
- autoload :AccessToken, 'qiniu/tokens/access_token'
12
- autoload :QboxToken, 'qiniu/tokens/qbox_token'
13
- autoload :UploadToken, 'qiniu/tokens/upload_token'
14
- autoload :DownloadToken, 'qiniu/tokens/download_token'
15
- autoload :Abstract, 'qiniu/abstract'
16
- autoload :Storage, 'qiniu/storage'
17
- autoload :Fop, 'qiniu/fop'
18
- autoload :Misc, 'qiniu/misc'
6
+ require_relative 'qiniu/version'
7
+ require_relative 'qiniu/utils'
8
+ require_relative 'qiniu/auth'
9
+ require_relative 'qiniu/config'
10
+ require_relative 'qiniu/log'
11
+ require_relative 'qiniu/tokens/access_token'
12
+ require_relative 'qiniu/tokens/qbox_token'
13
+ require_relative 'qiniu/tokens/upload_token'
14
+ require_relative 'qiniu/tokens/download_token'
15
+ require_relative 'qiniu/abstract'
16
+ require_relative 'qiniu/storage'
17
+ require_relative 'qiniu/fop'
18
+ require_relative 'qiniu/misc'
19
+ require_relative 'qiniu/host_manager'
20
+ require_relative 'qiniu/http'
19
21
 
20
22
  class << self
21
23
 
@@ -25,6 +27,18 @@ module Qiniu
25
27
  Config.initialize_connect opts
26
28
  end
27
29
 
30
+ def establish_https_connection!(opts = {})
31
+ Config.initialize_connect_https opts
32
+ end
33
+
34
+ def switch_to_http!
35
+ Config.switch_to_http
36
+ end
37
+
38
+ def switch_to_https!
39
+ Config.switch_to_https
40
+ end
41
+
28
42
  def mkbucket(bucket_name)
29
43
  code, data = Storage.mkbucket(bucket_name)
30
44
  code == StatusOK
@@ -93,16 +107,6 @@ module Qiniu
93
107
  code == StatusOK ? data : false
94
108
  end
95
109
 
96
- def get(bucket, key, save_as = nil, expires_in = nil, version = nil)
97
- code, data = Storage.get(bucket, key, save_as, expires_in, version)
98
- code == StatusOK ? data : false
99
- end
100
-
101
- def download(bucket, key, save_as = nil, expires_in = nil, version = nil)
102
- code, data = Storage.get(bucket, key, save_as, expires_in, version)
103
- code == StatusOK ? data["url"] : false
104
- end
105
-
106
110
  def copy(source_bucket, source_key, target_bucket, target_key)
107
111
  code, data = Storage.copy(source_bucket, source_key, target_bucket, target_key)
108
112
  code == StatusOK
@@ -133,11 +137,6 @@ module Qiniu
133
137
  code == StatusOK ? data : false
134
138
  end
135
139
 
136
- def batch_get(bucket, keys)
137
- code, data = Storage.batch_get(bucket, keys)
138
- code == StatusOK ? data : false
139
- end
140
-
141
140
  def batch_copy(*args)
142
141
  code, data = Storage.batch_copy(args)
143
142
  code == StatusOK
@@ -148,14 +147,6 @@ module Qiniu
148
147
  code == StatusOK
149
148
  end
150
149
 
151
- def batch_download(bucket, keys)
152
- code, data = Storage.batch_get(bucket, keys)
153
- return false unless code == StatusOK
154
- links = []
155
- data.each { |e| links << e["data"]["url"] }
156
- links
157
- end
158
-
159
150
  def batch_delete(bucket, keys)
160
151
  code, data = Storage.batch_delete(bucket, keys)
161
152
  code == StatusOK ? data : false
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  # vim: sw=2 ts=2
3
3
 
4
- require 'hmac-sha1'
4
+ require 'openssl'
5
5
  require 'uri'
6
6
  require 'cgi'
7
7
 
@@ -27,15 +27,8 @@ module Qiniu
27
27
  end # calculate_deadline
28
28
 
29
29
  def calculate_hmac_sha1_digest(sk, str)
30
- begin
31
- sign = HMAC::SHA1.new(sk).update(str).digest
32
- rescue RuntimeError => e
33
- raise RuntimeError, "Please set Qiniu's access_key and secret_key before authorize any tokens."
34
- rescue
35
- raise
36
- else
37
- return sign
38
- end
30
+ raise ArgumentError, "Please set Qiniu's access_key and secret_key before authorize any tokens." if sk.nil?
31
+ OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), sk, str)
39
32
  end
40
33
  end # class << self
41
34
 
@@ -56,6 +49,7 @@ module Qiniu
56
49
  PARAMS = {
57
50
  # 字符串类型参数
58
51
  :scope => "scope" ,
52
+ :is_prefixal_scope => "isPrefixalScope" ,
59
53
  :save_key => "saveKey" ,
60
54
  :end_user => "endUser" ,
61
55
  :return_url => "returnUrl" ,
@@ -71,10 +65,14 @@ module Qiniu
71
65
  # 数值类型参数
72
66
  :deadline => "deadline" ,
73
67
  :insert_only => "insertOnly" ,
68
+ :fsize_min => "fsizeMin" ,
74
69
  :fsize_limit => "fsizeLimit" ,
75
- :callback_fetch_key => "callbackFetchKey" ,
76
70
  :detect_mime => "detectMime" ,
77
- :mime_limit => "mimeLimit"
71
+ :mime_limit => "mimeLimit" ,
72
+ :uphosts => "uphosts" ,
73
+ :global => "global" ,
74
+ :delete_after_days => "deleteAfterDays" ,
75
+ :file_type => "fileType"
78
76
  } # PARAMS
79
77
 
80
78
  public
@@ -91,6 +89,15 @@ module Qiniu
91
89
  # 覆盖语义,文件已存在则直接覆盖
92
90
  @scope = "#{bucket}:#{key}"
93
91
  end
92
+
93
+ if Config.settings[:multi_region]
94
+ begin
95
+ @uphosts = Config.host_manager.up_hosts(bucket)
96
+ @global = Config.host_manager.global(bucket)
97
+ rescue
98
+ # Do nothing
99
+ end
100
+ end
94
101
  end # scope!
95
102
 
96
103
  def expires_in!(seconds)
@@ -159,7 +166,7 @@ module Qiniu
159
166
 
160
167
  ### URL变换:追加FOP指令
161
168
  if args[:fop].is_a?(String) && args[:fop] != '' then
162
- if download_url.index('?').is_a?(Fixnum) then
169
+ if download_url.include?('?')
163
170
  # 已有参数
164
171
  download_url = "#{download_url}&#{args[:fop]}"
165
172
  else
@@ -172,7 +179,7 @@ module Qiniu
172
179
  e = Auth.calculate_deadline(args[:expires_in], args[:deadline])
173
180
 
174
181
  ### URL变换:追加授权期参数
175
- if download_url.index('?').is_a?(Fixnum) then
182
+ if download_url.include?('?')
176
183
  # 已有参数
177
184
  download_url = "#{download_url}&e=#{e}"
178
185
  else
@@ -13,32 +13,7 @@ require 'tmpdir'
13
13
  module Qiniu
14
14
  module Config
15
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
- :fetch_host => "http://iovip.qbox.me",
24
- :rsf_host => "http://rsf.qbox.me",
25
- :up_host => "http://up.qiniu.com",
26
- :pub_host => "http://pu.qbox.me:10200",
27
- :eu_host => "http://eu.qbox.me",
28
- :iovip_host => "http://iovip.qbox.me",
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
- }
38
-
39
- REQUIRED_OPTION_KEYS = [:access_key, :secret_key, :up_host]
40
-
41
- attr_reader :settings, :default_params
16
+ attr_reader :settings, :default_params, :host_manager
42
17
 
43
18
  def load config_file
44
19
  if File.exist?(config_file)
@@ -51,12 +26,86 @@ module Qiniu
51
26
  end
52
27
 
53
28
  def initialize_connect options = {}
54
- @settings = DEFAULT_OPTIONS.merge!(options)
55
- REQUIRED_OPTION_KEYS.each do |opt|
29
+ options = if options[:protocol] == :https
30
+ https_options.merge(options)
31
+ else
32
+ http_options.merge(options)
33
+ end
34
+ @settings = default_options.merge(options)
35
+ required_options_keys.each do |opt|
56
36
  raise MissingArgsError, [opt] unless @settings.has_key?(opt)
57
37
  end
38
+ @host_manager = HostManager.new(@settings)
39
+ nil
40
+ end
41
+
42
+ def initialize_connect_https options = {}
43
+ initialize_connect(options.merge(:protocol => :https))
44
+ end
45
+
46
+ def switch_to_http
47
+ @settings.merge!(http_options)
58
48
  end
59
49
 
50
+ def switch_to_https
51
+ @settings.merge!(https_options)
52
+ end
53
+
54
+ def up_host(bucket, opts = {})
55
+ @settings[:up_host] || @host_manager.up_host(bucket, opts)
56
+ end
57
+
58
+ def fetch_host(bucket, opts = {})
59
+ @settings[:fetch_host] || @host_manager.fetch_host(bucket, opts)
60
+ end
61
+
62
+ private
63
+
64
+ def default_options
65
+ {
66
+ :user_agent => 'QiniuRuby/' + Version.to_s + ' ('+RUBY_PLATFORM+')' + ' Ruby/'+ RUBY_VERSION,
67
+ :method => :post,
68
+ :content_type => 'application/x-www-form-urlencoded',
69
+ :auth_url => "https://acc.qbox.me/oauth2/token",
70
+ :access_key => "",
71
+ :secret_key => "",
72
+ :auto_reconnect => true,
73
+ :max_retry_times => 3,
74
+ :block_size => 1024*1024*4,
75
+ :chunk_size => 1024*256,
76
+ :enable_debug => true,
77
+ :tmpdir => Dir.tmpdir + File::SEPARATOR + 'QiniuRuby',
78
+ :multi_region => true
79
+ }.freeze
80
+ end
81
+
82
+ def http_options
83
+ {
84
+ :rs_host => "http://rs.qiniu.com",
85
+ :rsf_host => "http://rsf.qbox.me",
86
+ :pub_host => "http://pu.qbox.me:10200",
87
+ :eu_host => "http://eu.qbox.me",
88
+ :uc_host => "http://uc.qbox.me",
89
+ :api_host => "http://api.qiniu.com",
90
+ :protocol => :http
91
+ }.freeze
92
+ end
93
+
94
+ def https_options
95
+ {
96
+ :rs_host => "https://rs.qbox.me",
97
+ :rsf_host => "https://rsf.qbox.me",
98
+ :pub_host => "https://pu.qbox.me",
99
+ :eu_host => "https://eu.qbox.me",
100
+ :uc_host => "https://uc.qbox.me",
101
+ :api_host => "https://api.qiniu.com",
102
+ :protocol => :https
103
+ }.freeze
104
+ end
105
+
106
+ def required_options_keys
107
+ [:access_key, :secret_key].freeze
108
+ end
60
109
  end
61
110
  end # module Config
62
111
  end # module Qiniu
@@ -0,0 +1,104 @@
1
+ require 'thread'
2
+ require 'cgi'
3
+
4
+ module Qiniu
5
+ class BucketIsMissing < RuntimeError; end
6
+
7
+ class HostManager
8
+ def initialize(config)
9
+ @config = config
10
+ @mutex = Mutex.new
11
+ @hosts = {}
12
+ end
13
+
14
+ def up_host(bucket, opts = {})
15
+ if !multi_region_support?
16
+ "#{extract_protocol(opts)}://up.qiniu.com"
17
+ elsif bucket
18
+ hosts(bucket)[extract_protocol(opts)]['up'][0] rescue "#{extract_protocol(opts)}://up.qiniu.com"
19
+ else
20
+ raise BucketIsMissing, 'HostManager#up_host: bucket is required when multi_region is enabled'
21
+ end
22
+ end
23
+
24
+ def fetch_host(bucket, opts = {})
25
+ if !multi_region_support?
26
+ "#{extract_protocol(opts)}://iovip.qbox.me"
27
+ elsif bucket
28
+ hosts(bucket)[extract_protocol(opts)]['io'][0] rescue "#{extract_protocol(opts)}://iovip.qbox.me"
29
+ else
30
+ raise BucketIsMissing, 'HostManager#fetch_host: bucket is required when multi_region is enabled'
31
+ end
32
+ end
33
+
34
+ def up_hosts(bucket, opts = {})
35
+ if multi_region_support?
36
+ hosts(bucket)[extract_protocol(opts)]['up']
37
+ else
38
+ raise 'HostManager#up_hosts: multi_region must be enabled'
39
+ end
40
+ end
41
+
42
+ def global(bucket, opts = {})
43
+ if multi_region_support?
44
+ !!hosts(bucket)['global']
45
+ else
46
+ raise 'HostManager#global: multi_region must be enabled'
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def extract_protocol(opts)
53
+ (opts[:protocol] || @config[:protocol]).to_s
54
+ end
55
+
56
+ def multi_region_support?
57
+ @config[:multi_region]
58
+ end
59
+
60
+ def hosts(bucket)
61
+ host = read_host(bucket)
62
+ if host
63
+ if host_expired?(host)
64
+ delete_host(bucket)
65
+ else
66
+ return host
67
+ end
68
+ end
69
+ url = @config[:uc_host] + '/v1/query?' + HTTP.generate_query_string(ak: @config[:access_key], bucket: bucket)
70
+ status, body = HTTP.api_get(url)
71
+ if HTTP.is_response_ok?(status)
72
+ Utils.debug("Query #{bucket} hosts Success: #{body}")
73
+ host = body.merge(:time => Time.now)
74
+ write_host(bucket, host)
75
+ host
76
+ else
77
+ Utils.debug("Query #{bucket} hosts Error: #{body}")
78
+ raise "Host query is failed"
79
+ end
80
+ end
81
+
82
+ def host_expired?(host)
83
+ host[:time] + host['ttl'] < Time.now
84
+ end
85
+
86
+ def read_host(bucket)
87
+ @mutex.synchronize do
88
+ @hosts[bucket]
89
+ end
90
+ end
91
+
92
+ def write_host(bucket, host)
93
+ @mutex.synchronize do
94
+ @hosts[bucket] = host
95
+ end
96
+ end
97
+
98
+ def delete_host(bucket)
99
+ @mutex.synchronize do
100
+ @hosts.delete(bucket)
101
+ end
102
+ end
103
+ end
104
+ end