bunny 1.0.0.pre4 → 1.0.0.pre5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/ChangeLog.md +20 -0
- data/lib/bunny.rb +1 -14
- data/lib/bunny/channel.rb +18 -18
- data/lib/bunny/concurrent/continuation_queue.rb +1 -1
- data/lib/bunny/exchange.rb +1 -1
- data/lib/bunny/session.rb +19 -4
- data/lib/bunny/timeout.rb +18 -0
- data/lib/bunny/transport.rb +10 -6
- data/lib/bunny/version.rb +1 -1
- data/spec/higher_level_api/integration/tls_connection_spec.rb +42 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1727f4dbfca01835cbc22019086dda09c7696033
|
4
|
+
data.tar.gz: 3ef0c8e3ea1a1f3b9dbe7ec00a171d30c196ec98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba745b6f58a1eeca8f3064c3f11d17df8b2b306d0ccdcb83dd9d109b312b5408d6f83bd9e0735a5e077ea7290995dc4ef2392b1fd6753aa7ec55cc6ae570d41a
|
7
|
+
data.tar.gz: 6debdd81bc52d31937e78cab8fcfa6922d2df2143c27b6e698b2b5f5a5e42826e22e7bfe8d551a3479cc118417cde5e8e6863f3a587c9c8f8424e4f4b2b7daea
|
data/.travis.yml
CHANGED
data/ChangeLog.md
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
## Changes between Bunny 1.0.0.pre4 and 1.0.0.pre5
|
2
|
+
|
3
|
+
### Bunny::Session.parse_uri
|
4
|
+
|
5
|
+
`Bunny::Session.parse_uri` is a new method that parses
|
6
|
+
connection URIs into hashes that `Bunny::Session#initialize`
|
7
|
+
accepts.
|
8
|
+
|
9
|
+
``` ruby
|
10
|
+
Bunny::Session.parse_uri("amqp://user:pwd@broker.eng.megacorp.local/myapp_qa")
|
11
|
+
```
|
12
|
+
|
13
|
+
### Default Paths for TLS/SSL CA's on All OS'es
|
14
|
+
|
15
|
+
Bunny now uses OpenSSL to detect default TLS/SSL CA's paths, extending
|
16
|
+
this feature to OS'es other than Linux.
|
17
|
+
|
18
|
+
Contributed by Jingwen Owen Ou.
|
19
|
+
|
20
|
+
|
1
21
|
## Changes between Bunny 1.0.0.pre3 and 1.0.0.pre4
|
2
22
|
|
3
23
|
### Default Paths for TLS/SSL CA's on Linux
|
data/lib/bunny.rb
CHANGED
@@ -9,6 +9,7 @@ require "amq/protocol/extensions"
|
|
9
9
|
require "bunny/framing"
|
10
10
|
require "bunny/exceptions"
|
11
11
|
require "bunny/socket"
|
12
|
+
require "bunny/timeout"
|
12
13
|
|
13
14
|
begin
|
14
15
|
require "openssl"
|
@@ -33,20 +34,6 @@ module Bunny
|
|
33
34
|
# AMQP protocol version Bunny implements
|
34
35
|
PROTOCOL_VERSION = AMQ::Protocol::PROTOCOL_VERSION
|
35
36
|
|
36
|
-
# unifies Ruby standard library's Timeout (which is not accurate on
|
37
|
-
# Ruby 1.8 and has other issues) and SystemTimer (the gem)
|
38
|
-
Timer = if RUBY_VERSION < "1.9"
|
39
|
-
begin
|
40
|
-
require "bunny/system_timer"
|
41
|
-
Bunny::SystemTimer
|
42
|
-
rescue LoadError
|
43
|
-
Timeout
|
44
|
-
end
|
45
|
-
else
|
46
|
-
Timeout
|
47
|
-
end
|
48
|
-
|
49
|
-
|
50
37
|
#
|
51
38
|
# API
|
52
39
|
#
|
data/lib/bunny/channel.rb
CHANGED
@@ -602,7 +602,7 @@ module Bunny
|
|
602
602
|
|
603
603
|
@connection.send_frame(AMQ::Protocol::Basic::Qos.encode(@id, 0, prefetch_count, global))
|
604
604
|
|
605
|
-
Bunny::
|
605
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
606
606
|
@last_basic_qos_ok = wait_on_continuations
|
607
607
|
end
|
608
608
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -621,7 +621,7 @@ module Bunny
|
|
621
621
|
raise_if_no_longer_open!
|
622
622
|
|
623
623
|
@connection.send_frame(AMQ::Protocol::Basic::Recover.encode(@id, requeue))
|
624
|
-
Bunny::
|
624
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
625
625
|
@last_basic_recover_ok = wait_on_continuations
|
626
626
|
end
|
627
627
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -823,7 +823,7 @@ module Bunny
|
|
823
823
|
arguments))
|
824
824
|
|
825
825
|
begin
|
826
|
-
Bunny::
|
826
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
827
827
|
@last_basic_consume_ok = wait_on_continuations
|
828
828
|
end
|
829
829
|
rescue Exception => e
|
@@ -873,7 +873,7 @@ module Bunny
|
|
873
873
|
consumer.arguments))
|
874
874
|
|
875
875
|
begin
|
876
|
-
Bunny::
|
876
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
877
877
|
@last_basic_consume_ok = wait_on_continuations
|
878
878
|
end
|
879
879
|
rescue Exception => e
|
@@ -908,7 +908,7 @@ module Bunny
|
|
908
908
|
def basic_cancel(consumer_tag)
|
909
909
|
@connection.send_frame(AMQ::Protocol::Basic::Cancel.encode(@id, consumer_tag, false))
|
910
910
|
|
911
|
-
Bunny::
|
911
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
912
912
|
@last_basic_cancel_ok = wait_on_continuations
|
913
913
|
end
|
914
914
|
|
@@ -982,7 +982,7 @@ module Bunny
|
|
982
982
|
opts[:if_unused],
|
983
983
|
opts[:if_empty],
|
984
984
|
false))
|
985
|
-
Bunny::
|
985
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
986
986
|
@last_queue_delete_ok = wait_on_continuations
|
987
987
|
end
|
988
988
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -1002,7 +1002,7 @@ module Bunny
|
|
1002
1002
|
|
1003
1003
|
@connection.send_frame(AMQ::Protocol::Queue::Purge.encode(@id, name, false))
|
1004
1004
|
|
1005
|
-
Bunny::
|
1005
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
1006
1006
|
@last_queue_purge_ok = wait_on_continuations
|
1007
1007
|
end
|
1008
1008
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -1038,7 +1038,7 @@ module Bunny
|
|
1038
1038
|
opts[:routing_key],
|
1039
1039
|
false,
|
1040
1040
|
opts[:arguments]))
|
1041
|
-
Bunny::
|
1041
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
1042
1042
|
@last_queue_bind_ok = wait_on_continuations
|
1043
1043
|
end
|
1044
1044
|
|
@@ -1073,7 +1073,7 @@ module Bunny
|
|
1073
1073
|
exchange_name,
|
1074
1074
|
opts[:routing_key],
|
1075
1075
|
opts[:arguments]))
|
1076
|
-
Bunny::
|
1076
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
1077
1077
|
@last_queue_unbind_ok = wait_on_continuations
|
1078
1078
|
end
|
1079
1079
|
|
@@ -1112,7 +1112,7 @@ module Bunny
|
|
1112
1112
|
false,
|
1113
1113
|
false,
|
1114
1114
|
opts[:arguments]))
|
1115
|
-
Bunny::
|
1115
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
1116
1116
|
@last_exchange_declare_ok = wait_on_continuations
|
1117
1117
|
end
|
1118
1118
|
|
@@ -1137,7 +1137,7 @@ module Bunny
|
|
1137
1137
|
name,
|
1138
1138
|
opts[:if_unused],
|
1139
1139
|
false))
|
1140
|
-
Bunny::
|
1140
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
1141
1141
|
@last_exchange_delete_ok = wait_on_continuations
|
1142
1142
|
end
|
1143
1143
|
|
@@ -1181,7 +1181,7 @@ module Bunny
|
|
1181
1181
|
opts[:routing_key],
|
1182
1182
|
false,
|
1183
1183
|
opts[:arguments]))
|
1184
|
-
Bunny::
|
1184
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
1185
1185
|
@last_exchange_bind_ok = wait_on_continuations
|
1186
1186
|
end
|
1187
1187
|
|
@@ -1225,7 +1225,7 @@ module Bunny
|
|
1225
1225
|
opts[:routing_key],
|
1226
1226
|
false,
|
1227
1227
|
opts[:arguments]))
|
1228
|
-
Bunny::
|
1228
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
1229
1229
|
@last_exchange_unbind_ok = wait_on_continuations
|
1230
1230
|
end
|
1231
1231
|
|
@@ -1253,7 +1253,7 @@ module Bunny
|
|
1253
1253
|
raise_if_no_longer_open!
|
1254
1254
|
|
1255
1255
|
@connection.send_frame(AMQ::Protocol::Channel::Flow.encode(@id, active))
|
1256
|
-
Bunny::
|
1256
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
1257
1257
|
@last_channel_flow_ok = wait_on_continuations
|
1258
1258
|
end
|
1259
1259
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -1274,7 +1274,7 @@ module Bunny
|
|
1274
1274
|
raise_if_no_longer_open!
|
1275
1275
|
|
1276
1276
|
@connection.send_frame(AMQ::Protocol::Tx::Select.encode(@id))
|
1277
|
-
Bunny::
|
1277
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
1278
1278
|
@last_tx_select_ok = wait_on_continuations
|
1279
1279
|
end
|
1280
1280
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -1289,7 +1289,7 @@ module Bunny
|
|
1289
1289
|
raise_if_no_longer_open!
|
1290
1290
|
|
1291
1291
|
@connection.send_frame(AMQ::Protocol::Tx::Commit.encode(@id))
|
1292
|
-
Bunny::
|
1292
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
1293
1293
|
@last_tx_commit_ok = wait_on_continuations
|
1294
1294
|
end
|
1295
1295
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -1304,7 +1304,7 @@ module Bunny
|
|
1304
1304
|
raise_if_no_longer_open!
|
1305
1305
|
|
1306
1306
|
@connection.send_frame(AMQ::Protocol::Tx::Rollback.encode(@id))
|
1307
|
-
Bunny::
|
1307
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
1308
1308
|
@last_tx_rollback_ok = wait_on_continuations
|
1309
1309
|
end
|
1310
1310
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -1344,7 +1344,7 @@ module Bunny
|
|
1344
1344
|
@confirms_callback = callback
|
1345
1345
|
|
1346
1346
|
@connection.send_frame(AMQ::Protocol::Confirm::Select.encode(@id, false))
|
1347
|
-
Bunny::
|
1347
|
+
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
1348
1348
|
@last_confirm_select_ok = wait_on_continuations
|
1349
1349
|
end
|
1350
1350
|
raise_if_continuation_resulted_in_a_channel_error!
|
data/lib/bunny/exchange.rb
CHANGED
data/lib/bunny/session.rb
CHANGED
@@ -98,18 +98,23 @@ module Bunny
|
|
98
98
|
# @option connection_string_or_opts [String] :password ("guest") Password
|
99
99
|
# @option connection_string_or_opts [String] :vhost ("/") Virtual host to use
|
100
100
|
# @option connection_string_or_opts [Integer] :heartbeat (600) Heartbeat interval. 0 means no heartbeat.
|
101
|
+
# @option connection_string_or_opts [Boolean] :tls (false) Should TLS/SSL be used?
|
102
|
+
# @option connection_string_or_opts [String] :tls_cert (nil) Path to client TLS/SSL certificate file (.pem)
|
103
|
+
# @option connection_string_or_opts [String] :tls_key (nil) Path to client TLS/SSL private key file (.pem)
|
104
|
+
# @option connection_string_or_opts [Array<String>] :tls_ca_certificates Array of paths to TLS/SSL CA files (.pem), by default detected from OpenSSL configuration
|
101
105
|
#
|
102
106
|
# @option optz [String] :auth_mechanism ("PLAIN") Authentication mechanism, PLAIN or EXTERNAL
|
103
107
|
# @option optz [String] :locale ("PLAIN") Locale RabbitMQ should use
|
104
108
|
#
|
105
109
|
# @see http://rubybunny.info/articles/connecting.html Connecting to RabbitMQ guide
|
110
|
+
# @see http://rubybunny.info/articles/tls.html TLS/SSL guide
|
106
111
|
# @api public
|
107
112
|
def initialize(connection_string_or_opts = Hash.new, optz = Hash.new)
|
108
113
|
opts = case (ENV["RABBITMQ_URL"] || connection_string_or_opts)
|
109
114
|
when nil then
|
110
115
|
Hash.new
|
111
116
|
when String then
|
112
|
-
|
117
|
+
self.class.parse_uri(connection_string_or_opts)
|
113
118
|
when Hash then
|
114
119
|
connection_string_or_opts
|
115
120
|
end.merge(optz)
|
@@ -195,6 +200,8 @@ module Bunny
|
|
195
200
|
# @private
|
196
201
|
attr_reader :mutex_impl
|
197
202
|
|
203
|
+
# Provides a way to fine tune the socket used by connection.
|
204
|
+
# Accepts a block that the socket will be yielded to.
|
198
205
|
def configure_socket(&block)
|
199
206
|
raise ArgumentError, "No block provided!" if block.nil?
|
200
207
|
|
@@ -270,7 +277,7 @@ module Bunny
|
|
270
277
|
if @transport.open?
|
271
278
|
close_all_channels
|
272
279
|
|
273
|
-
Bunny::
|
280
|
+
Bunny::Timeout.timeout(@transport.disconnect_timeout, ClientTimeout) do
|
274
281
|
self.close_connection(true)
|
275
282
|
end
|
276
283
|
|
@@ -375,6 +382,14 @@ module Bunny
|
|
375
382
|
@blocked
|
376
383
|
end
|
377
384
|
|
385
|
+
# Parses an amqp[s] URI into a hash that {Bunny::Session#initialize} accepts.
|
386
|
+
#
|
387
|
+
# @param [String] uri amqp or amqps URI to parse
|
388
|
+
# @return [Hash] Parsed URI as a hash
|
389
|
+
def self.parse_uri(uri)
|
390
|
+
AMQ::Settings.parse_amqp_url(uri)
|
391
|
+
end
|
392
|
+
|
378
393
|
|
379
394
|
#
|
380
395
|
# Implementation
|
@@ -409,7 +424,7 @@ module Bunny
|
|
409
424
|
# @private
|
410
425
|
def close_all_channels
|
411
426
|
@channels.reject {|n, ch| n == 0 || !ch.open? }.each do |_, ch|
|
412
|
-
Bunny::
|
427
|
+
Bunny::Timeout.timeout(@transport.disconnect_timeout, ClientTimeout) { ch.close }
|
413
428
|
end
|
414
429
|
end
|
415
430
|
|
@@ -674,7 +689,7 @@ module Bunny
|
|
674
689
|
# a native method that cannot be (easily) interrupted.
|
675
690
|
# So we use this ugly hack or else our test suite takes forever
|
676
691
|
# to run on JRuby (a new connection is opened/closed per example). MK.
|
677
|
-
if
|
692
|
+
if defined?(JRUBY_VERSION)
|
678
693
|
sleep 0.075
|
679
694
|
else
|
680
695
|
@reader_loop.join
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Bunny
|
2
|
+
# Unifies Ruby standard library's Timeout (which is not accurate on
|
3
|
+
# Ruby 1.8) and SystemTimer (the gem)
|
4
|
+
Timeout = if RUBY_VERSION < "1.9"
|
5
|
+
begin
|
6
|
+
require "bunny/system_timer"
|
7
|
+
Bunny::SystemTimer
|
8
|
+
rescue LoadError
|
9
|
+
Timeout
|
10
|
+
end
|
11
|
+
else
|
12
|
+
Timeout
|
13
|
+
end
|
14
|
+
|
15
|
+
# Backwards compatibility
|
16
|
+
# @private
|
17
|
+
Timer = Timeout
|
18
|
+
end
|
data/lib/bunny/transport.rb
CHANGED
@@ -41,11 +41,14 @@ module Bunny
|
|
41
41
|
@tls_certificate = opts[:tls_certificate] || opts[:ssl_cert_string]
|
42
42
|
@tls_key = opts[:tls_key] || opts[:ssl_key_string]
|
43
43
|
@tls_certificate_store = opts[:tls_certificate_store]
|
44
|
+
|
45
|
+
default_ca_file = ENV[OpenSSL::X509::DEFAULT_CERT_FILE_ENV] || OpenSSL::X509::DEFAULT_CERT_FILE
|
46
|
+
default_ca_path = ENV[OpenSSL::X509::DEFAULT_CERT_DIR_ENV] || OpenSSL::X509::DEFAULT_CERT_DIR
|
44
47
|
@tls_ca_certificates = opts.fetch(:tls_ca_certificates, [
|
45
|
-
|
46
|
-
'
|
47
|
-
'
|
48
|
-
'
|
48
|
+
default_ca_file,
|
49
|
+
File.join(default_ca_path, 'ca-certificates.crt'), # Ubuntu/Debian
|
50
|
+
File.join(default_ca_path, 'ca-bundle.crt'), # Amazon Linux & Fedora/RHEL
|
51
|
+
File.join(default_ca_path, 'ca-bundle.pem') # OpenSUSE
|
49
52
|
])
|
50
53
|
@verify_peer = opts[:verify_ssl] || opts[:verify_peer]
|
51
54
|
|
@@ -109,7 +112,7 @@ module Bunny
|
|
109
112
|
def write(data)
|
110
113
|
begin
|
111
114
|
if @read_write_timeout
|
112
|
-
Bunny::
|
115
|
+
Bunny::Timeout.timeout(@read_write_timeout, Bunny::ClientTimeout) do
|
113
116
|
if open?
|
114
117
|
@writes_mutex.synchronize { @socket.write(data) }
|
115
118
|
@socket.flush
|
@@ -247,7 +250,7 @@ module Bunny
|
|
247
250
|
|
248
251
|
def initialize_socket
|
249
252
|
begin
|
250
|
-
@socket = Bunny::
|
253
|
+
@socket = Bunny::Timeout.timeout(@connect_timeout, ConnectionTimeout) do
|
251
254
|
Bunny::Socket.open(@host, @port,
|
252
255
|
:keepalive => @opts[:keepalive],
|
253
256
|
:socket_timeout => @connect_timeout)
|
@@ -345,6 +348,7 @@ module Bunny
|
|
345
348
|
|
346
349
|
def initialize_tls_certificate_store(certs)
|
347
350
|
certs = certs.select { |path| File.readable? path }
|
351
|
+
@logger.debug "Using CA certificates at #{certs.join(', ')}"
|
348
352
|
if certs.empty?
|
349
353
|
@logger.error "No CA certificates found, add one with :tls_ca_certificates"
|
350
354
|
end
|
data/lib/bunny/version.rb
CHANGED
@@ -86,4 +86,46 @@ unless ENV["CI"]
|
|
86
86
|
ch.close
|
87
87
|
end
|
88
88
|
end
|
89
|
+
|
90
|
+
|
91
|
+
describe "TLS connection to RabbitMQ with a connection string" do
|
92
|
+
let(:connection) do
|
93
|
+
c = Bunny.new("amqps://bunny_gem:bunny_password@127.0.0.1/bunny_testbed",
|
94
|
+
:tls_cert => "spec/tls/client_cert.pem",
|
95
|
+
:tls_key => "spec/tls/client_key.pem",
|
96
|
+
:tls_ca_certificates => ["./spec/tls/cacert.pem"])
|
97
|
+
c.start
|
98
|
+
c
|
99
|
+
end
|
100
|
+
|
101
|
+
after :each do
|
102
|
+
connection.close
|
103
|
+
end
|
104
|
+
|
105
|
+
it "provides the same API as a regular connection" do
|
106
|
+
connection.should be_tls
|
107
|
+
ch = connection.create_channel
|
108
|
+
|
109
|
+
q = ch.queue("", :exclusive => true)
|
110
|
+
x = ch.default_exchange
|
111
|
+
|
112
|
+
x.publish("xyzzy", :routing_key => q.name).
|
113
|
+
publish("xyzzy", :routing_key => q.name).
|
114
|
+
publish("xyzzy", :routing_key => q.name).
|
115
|
+
publish("xyzzy", :routing_key => q.name)
|
116
|
+
|
117
|
+
sleep 0.5
|
118
|
+
q.message_count.should == 4
|
119
|
+
|
120
|
+
i = 0
|
121
|
+
q.subscribe do |delivery_info, _, payload|
|
122
|
+
i += 1
|
123
|
+
end
|
124
|
+
sleep 1.0
|
125
|
+
i.should == 4
|
126
|
+
q.message_count.should == 0
|
127
|
+
|
128
|
+
ch.close
|
129
|
+
end
|
130
|
+
end
|
89
131
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bunny
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.pre5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Duncan
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2013-08-
|
15
|
+
date: 2013-08-27 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: amq-protocol
|
@@ -124,6 +124,7 @@ files:
|
|
124
124
|
- lib/bunny/ssl_socket.rb
|
125
125
|
- lib/bunny/system_timer.rb
|
126
126
|
- lib/bunny/test_kit.rb
|
127
|
+
- lib/bunny/timeout.rb
|
127
128
|
- lib/bunny/transport.rb
|
128
129
|
- lib/bunny/version.rb
|
129
130
|
- lib/bunny/versioned_delivery_tag.rb
|