qpid_proton 0.18.1 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/ext/cproton/cproton.c +863 -75
  3. data/lib/codec/data.rb +589 -815
  4. data/lib/codec/mapping.rb +142 -126
  5. data/lib/core/condition.rb +89 -0
  6. data/lib/core/connection.rb +188 -228
  7. data/lib/core/connection_driver.rb +202 -0
  8. data/lib/core/container.rb +366 -0
  9. data/lib/core/delivery.rb +76 -251
  10. data/lib/core/disposition.rb +21 -35
  11. data/lib/core/endpoint.rb +21 -53
  12. data/lib/core/event.rb +156 -0
  13. data/lib/core/exceptions.rb +109 -106
  14. data/lib/core/link.rb +24 -49
  15. data/lib/core/listener.rb +82 -0
  16. data/lib/core/message.rb +59 -155
  17. data/lib/core/messaging_handler.rb +190 -0
  18. data/lib/core/receiver.rb +38 -7
  19. data/lib/core/sasl.rb +43 -46
  20. data/lib/core/sender.rb +55 -32
  21. data/lib/core/session.rb +58 -58
  22. data/lib/core/ssl.rb +5 -13
  23. data/lib/core/ssl_details.rb +1 -2
  24. data/lib/core/ssl_domain.rb +5 -8
  25. data/lib/core/terminus.rb +62 -30
  26. data/lib/core/tracker.rb +45 -0
  27. data/lib/core/transfer.rb +121 -0
  28. data/lib/core/transport.rb +62 -97
  29. data/lib/core/uri.rb +73 -0
  30. data/lib/core/url.rb +11 -7
  31. data/lib/handler/adapter.rb +78 -0
  32. data/lib/handler/messaging_adapter.rb +127 -0
  33. data/lib/handler/messaging_handler.rb +128 -178
  34. data/lib/handler/reactor_messaging_adapter.rb +158 -0
  35. data/lib/messenger/messenger.rb +9 -8
  36. data/lib/messenger/subscription.rb +1 -2
  37. data/lib/messenger/tracker.rb +1 -2
  38. data/lib/messenger/tracker_status.rb +1 -2
  39. data/lib/qpid_proton.rb +36 -66
  40. data/lib/reactor/container.rb +40 -234
  41. data/lib/types/array.rb +73 -130
  42. data/lib/types/described.rb +2 -44
  43. data/lib/types/hash.rb +19 -56
  44. data/lib/types/strings.rb +1 -2
  45. data/lib/types/type.rb +68 -0
  46. data/lib/util/{handler.rb → deprecation.rb} +22 -15
  47. data/lib/util/error_handler.rb +4 -25
  48. data/lib/util/timeout.rb +1 -2
  49. data/lib/util/version.rb +1 -2
  50. data/lib/util/wrapper.rb +58 -38
  51. metadata +16 -33
  52. data/lib/core/base_handler.rb +0 -31
  53. data/lib/core/selectable.rb +0 -130
  54. data/lib/event/collector.rb +0 -148
  55. data/lib/event/event.rb +0 -318
  56. data/lib/event/event_base.rb +0 -91
  57. data/lib/event/event_type.rb +0 -71
  58. data/lib/handler/acking.rb +0 -70
  59. data/lib/handler/c_adaptor.rb +0 -47
  60. data/lib/handler/c_flow_controller.rb +0 -33
  61. data/lib/handler/endpoint_state_handler.rb +0 -217
  62. data/lib/handler/incoming_message_handler.rb +0 -74
  63. data/lib/handler/outgoing_message_handler.rb +0 -100
  64. data/lib/handler/wrapped_handler.rb +0 -76
  65. data/lib/reactor/acceptor.rb +0 -41
  66. data/lib/reactor/backoff.rb +0 -41
  67. data/lib/reactor/connector.rb +0 -115
  68. data/lib/reactor/global_overrides.rb +0 -44
  69. data/lib/reactor/link_option.rb +0 -90
  70. data/lib/reactor/reactor.rb +0 -196
  71. data/lib/reactor/session_per_connection.rb +0 -45
  72. data/lib/reactor/ssl_config.rb +0 -41
  73. data/lib/reactor/task.rb +0 -39
  74. data/lib/reactor/urls.rb +0 -45
  75. data/lib/util/class_wrapper.rb +0 -54
  76. data/lib/util/condition.rb +0 -47
  77. data/lib/util/constants.rb +0 -85
  78. data/lib/util/engine.rb +0 -82
  79. data/lib/util/reactor.rb +0 -32
  80. data/lib/util/swig_helper.rb +0 -114
  81. data/lib/util/uuid.rb +0 -32
@@ -0,0 +1,45 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+
19
+ module Qpid::Proton
20
+
21
+ # Track the {Transfer::State} of a sent message.
22
+ class Tracker < Transfer
23
+ # @return [Sender] The parent {Sender} link.
24
+ def sender() link; end
25
+
26
+ # Re-delivery modifications sent by the receiver in {Delivery#release}
27
+ # @return [Hash] See the {Delivery#release} +opts+ parameter.
28
+ # @return [nil] If no modifications were requested by the receiver.
29
+ def modifications()
30
+ return nil if (state != MODIFIED)
31
+ d = Cproton.pn_delivery_remote(@impl)
32
+ {
33
+ :failed => Cproton.pn_disposition_is_failed(d),
34
+ :undeliverable => Cproton.pn_disposition_is_undeliverable(d),
35
+ :annotations => Codec::Data.to_object(Cproton.pn_disposition_annotations(d))
36
+ }
37
+ end
38
+
39
+ # Abort a partially-sent message.
40
+ # The tracker can no longer be used after calling {#abort}.
41
+ def abort()
42
+ Cproton.pn_delivery_abort(@impl)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,121 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+
19
+ module Qpid::Proton
20
+
21
+ # Status of a message transfer on a {Link}
22
+ # Common base class for {Tracker} and {Delivery}.
23
+ class Transfer
24
+ include Util::Deprecation
25
+
26
+ # @!private
27
+ PROTON_METHOD_PREFIX = "pn_delivery"
28
+ # @!private
29
+ include Util::Wrapper
30
+
31
+ def self.wrap(impl)
32
+ return unless impl
33
+ self.fetch_instance(impl, :pn_delivery_attachments) ||
34
+ (Cproton.pn_link_is_sender(Cproton.pn_delivery_link(impl)) ? Tracker : Delivery).new(impl)
35
+ end
36
+
37
+ def initialize(impl)
38
+ @impl = impl
39
+ @inspect = nil
40
+ self.class.store_instance(self, :pn_delivery_attachments)
41
+ end
42
+
43
+ public
44
+
45
+ # AMQP Delivery States describing the outcome of a message transfer
46
+ module State
47
+ # Message was successfully processed by the receiver
48
+ ACCEPTED = Cproton::PN_ACCEPTED
49
+
50
+ # Message rejected as invalid and unprocessable by the receiver.
51
+ REJECTED = Cproton::PN_REJECTED
52
+
53
+ # Message was not (and will not be) processed by the receiver, but may be
54
+ # acceptable if re-delivered to another receiver
55
+ RELEASED = Cproton::PN_RELEASED
56
+
57
+ # Like {RELEASED}, but there are modifications (see {Tracker#modifications})
58
+ # that must be applied to the message by the {Sender} before re-delivering it.
59
+ MODIFIED = Cproton::PN_MODIFIED
60
+
61
+ # Partial message data received. Only used during link recovery.
62
+ RECEIVED = Cproton::PN_RECEIVED
63
+ end
64
+
65
+ include State
66
+
67
+ # @return [String] Unique ID for the transfer in the context of the {#link}
68
+ def id() Cproton.pn_delivery_tag(@impl); end
69
+
70
+ # @deprecated use {#id}
71
+ deprecated_alias :tag, :id
72
+
73
+ # @return [Boolean] True if the transfer has is remotely settled.
74
+ proton_caller :settled?
75
+
76
+ # @return [Integer] Remote state of the transfer, one of the values in {State}
77
+ def state() Cproton.pn_delivery_remote_state(@impl); end
78
+
79
+ # @return [Link] The parent link.
80
+ def link() Link.wrap(Cproton.pn_delivery_link(@impl)); end
81
+
82
+ # @return [Session] The parent session.
83
+ def session() link.session; end
84
+
85
+ # @return [Connection] The parent connection.
86
+ def connection() self.session.connection; end
87
+
88
+ # @return [Transport] The parent connection's transport.
89
+ def transport() self.connection.transport; end
90
+
91
+ # @deprecated internal use only
92
+ proton_caller :writable?
93
+ # @deprecated internal use only
94
+ proton_caller :readable?
95
+ # @deprecated internal use only
96
+ proton_caller :updated?
97
+ # @deprecated internal use only
98
+ proton_caller :clear
99
+ # @deprecated internal use only
100
+ proton_caller :pending
101
+ # @deprecated internal use only
102
+ proton_caller :partial?
103
+ # @deprecated internal use only
104
+ def update(state) Cproton.pn_delivery_update(@impl, state); end
105
+ # @deprecated internal use only
106
+ proton_caller :buffered?
107
+ # @deprecated internal use only
108
+ def local_state() Cproton.pn_delivery_local_state(@impl); end
109
+ # @deprecated use {#state}
110
+ deprecated_alias :remote_state, :state
111
+ # @deprecated internal use only
112
+ def settle(state = nil)
113
+ update(state) unless state.nil?
114
+ Cproton.pn_delivery_settle(@impl)
115
+ @inspect = inspect # Save the inspect string, the delivery pointer will go bad.
116
+ end
117
+
118
+ def inspect() @inspect || super; end
119
+ def to_s() inspect; end
120
+ end
121
+ end
@@ -1,4 +1,3 @@
1
- #--
2
1
  # Licensed to the Apache Software Foundation (ASF) under one
3
2
  # or more contributor license agreements. See the NOTICE file
4
3
  # distributed with this work for additional information
@@ -15,57 +14,18 @@
15
14
  # KIND, either express or implied. See the License for the
16
15
  # specific language governing permissions and limitations
17
16
  # under the License.
18
- #++
17
+
19
18
 
20
19
  module Qpid::Proton
21
20
 
22
- # A transport is used by a connection to interface with the network.
23
- #
24
- # A transport is associated with, at most, one Connection.
25
- #
26
- # == Client And Server Mode
27
- #
28
- # Initially, a transport is configured to be a client tranpsort. It can be
29
- # configured to act as a server when it is created.
30
- #
31
- # A client transport initiates outgoing connections.
32
- #
33
- # A client transport must be configured with the protocol layers to use and
34
- # cannot configure itself automatically.
35
- #
36
- # A server transport accepts incoming connections. It can automatically
37
- # configure itself to include the various protocol layers depending on the
38
- # incoming protocol headers.
39
- #
40
- # == Tracing Data
41
- #
42
- # Data can be traced into and out of the transport programmatically by setting
43
- # the #trace level to one of the defined trace values (TRACE_RAW, TRACE_FRM or
44
- # TRACE_DRV). Tracing can also be turned off programmatically by setting the
45
- # #trace level to TRACE_OFF.
46
- #
47
- # @example
48
- #
49
- # # turns on frame tracing
50
- # @transport.trace = Qpid::Proton::Transport::TRACE_FRM
51
- #
52
- # # ... do something where the frames are of interest, such as debugging
53
- #
54
- # # turn tracing off again
55
- # @transport.trace = Qpid::Proton::Transport::TRACE_NONE
56
- #
57
- # Tracing can also be enabled from the command line by defining the similarly
58
- # named environment variable before starting a Proton application:
59
- #
60
- # @example
61
- #
62
- # # enable tracing from the command line
63
- # PN_TRACE_FRM=1 ruby my_proton_app.rb
64
- #
21
+ # @deprecated all important features are available from {#Connection}
65
22
  class Transport
23
+ include Util::Deprecation
66
24
 
67
25
  # @private
68
- include Util::Engine
26
+ PROTON_METHOD_PREFIX = "pn_transport"
27
+ # @private
28
+ include Util::Wrapper
69
29
 
70
30
  # Turn logging off entirely.
71
31
  TRACE_OFF = Cproton::PN_TRACE_OFF
@@ -76,22 +36,13 @@ module Qpid::Proton
76
36
  # Log driver related events; i.e., initialization, end of stream, etc.
77
37
  TRACE_DRV = Cproton::PN_TRACE_DRV
78
38
 
79
- # @private
80
- CLIENT = 1
81
- # @private
82
- SERVER = 2
83
-
84
- # @private
85
- include Util::SwigHelper
86
-
87
- # @private
88
- PROTON_METHOD_PREFIX = "pn_transport"
39
+ proton_get :user
89
40
 
90
41
  # @!attribute channel_max
91
42
  #
92
43
  # @return [Integer] The maximum allowed channel.
93
44
  #
94
- proton_accessor :channel_max
45
+ proton_set_get :channel_max
95
46
 
96
47
  # @!attribute [r] remote_channel_max
97
48
  #
@@ -102,26 +53,34 @@ module Qpid::Proton
102
53
  # @!attribute max_frame_size
103
54
  #
104
55
  # @return [Integer] The maximum frame size.
105
- #
106
- proton_accessor :max_frame_size
56
+ proton_set_get :max_frame
57
+ proton_get :remote_max_frame
107
58
 
108
59
  # @!attribute [r] remote_max_frame_size
109
60
  #
110
61
  # @return [Integer] The maximum frame size of the transport's remote peer.
111
62
  #
112
- proton_reader :remote_max_frame_size
63
+ proton_get :remote_max_frame_size
113
64
 
114
65
  # @!attribute idle_timeout
115
66
  #
116
- # @return [Integer] The idle timeout.
67
+ # @deprecated use {Connection#open} with the +:idle_timeout+ option to set
68
+ # the timeout, and {Connection#idle_timeout} to query the remote timeout.
69
+ #
70
+ # The Connection timeout values are in *seconds* and are automatically
71
+ # converted.
72
+ #
73
+ # @return [Integer] The idle timeout in *milliseconds*.
117
74
  #
118
- proton_accessor :idle_timeout
75
+ proton_set_get :idle_timeout
119
76
 
120
- # @!attribute [r] remote_idle_timeout
77
+ # @!attribute [r] remote_idle_timeout in milliseconds
78
+ #
79
+ # @deprecated Use {Connection#idle_timeout} to query the remote timeout.
121
80
  #
122
81
  # @return [Integer] The idle timeout for the transport's remote peer.
123
82
  #
124
- proton_accessor :remote_idle_timeout
83
+ proton_set_get :remote_idle_timeout
125
84
 
126
85
  # @!attribute [r] capacity
127
86
  #
@@ -190,49 +149,34 @@ module Qpid::Proton
190
149
  #
191
150
  # @return [Integer] The number of frames output by a transport.
192
151
  #
193
- proton_reader :frames_output
152
+ proton_get :frames_output
194
153
 
195
154
  # @!attribute [r] frames_input
196
155
  #
197
156
  # @return [Integer] The number of frames input by a transport.
198
157
  #
199
- proton_reader :frames_input
158
+ proton_get :frames_input
200
159
 
201
160
  # @private
202
161
  include Util::ErrorHandler
203
162
 
204
- can_raise_error :process, :error_class => TransportError
205
- can_raise_error :close_tail, :error_class => TransportError
206
- can_raise_error :pending, :error_class => TransportError, :below => Error::EOS
207
- can_raise_error :close_head, :error_class => TransportError
208
-
209
- # @private
210
- include Util::Wrapper
211
-
212
163
  # @private
213
164
  def self.wrap(impl)
214
165
  return nil if impl.nil?
215
166
 
216
- self.fetch_instance(impl, :pn_transport_attachments) || Transport.new(nil, impl)
167
+ self.fetch_instance(impl, :pn_transport_attachments) || Transport.new(impl)
217
168
  end
218
169
 
219
170
  # Creates a new transport instance.
220
- #
221
- # @param mode [Integer] The transport mode, either CLIENT or SERVER
222
- # @param impl [pn_transport_t] Should not be used.
223
- #
224
- # @raise [TransportError] If the mode is invalid.
225
- #
226
- def initialize(mode = nil, impl = Cproton.pn_transport)
171
+ def initialize(impl = Cproton.pn_transport)
227
172
  @impl = impl
228
- if mode == SERVER
229
- Cproton.pn_transport_set_server(@impl)
230
- elsif (!mode.nil? && mode != CLIENT)
231
- raise TransportError.new("cannot create transport for mode: #{mode}")
232
- end
233
173
  self.class.store_instance(self, :pn_transport_attachments)
234
174
  end
235
175
 
176
+ # Set server mode for this tranport - enables protocol detection
177
+ # and server-side authentication for incoming connections
178
+ def set_server() Cproton.pn_transport_set_server(@impl); end
179
+
236
180
  # Returns whether the transport has any buffered data.
237
181
  #
238
182
  # @return [Boolean] True if the transport has no buffered data.
@@ -241,15 +185,15 @@ module Qpid::Proton
241
185
  Cproton.pn_transport_quiesced(@impl)
242
186
  end
243
187
 
244
- # Returns additional information about the condition of the transport.
245
- #
246
- # When a TRANSPORT_ERROR event occurs, this operaiton can be used to
247
- # access the details of the error condition.
248
- #
249
- # The object returned is valid until the Transport is discarded.
250
- #
188
+ # @return [Condition, nil] transport error condition or nil if there is no error.
251
189
  def condition
252
- condition_to_object Cproton.pn_transport_condition(@impl)
190
+ Condition.convert(Cproton.pn_transport_condition(@impl))
191
+ end
192
+
193
+ # Set the error condition for the transport.
194
+ # @param c [Condition] The condition to set
195
+ def condition=(c)
196
+ Condition.assign(Cproton.pn_transport_condition(@impl), c)
253
197
  end
254
198
 
255
199
  # Binds to the given connection.
@@ -400,7 +344,7 @@ module Qpid::Proton
400
344
  # @return [SSL] The SSL object.
401
345
  #
402
346
  def ssl(domain = nil, session_details = nil)
403
- @ssl ||= SSL.create(self, domain, session_details) if @ssl.nil?
347
+ @ssl ||= SSL.create(self, domain, session_details)
404
348
  end
405
349
 
406
350
  # @private
@@ -408,6 +352,27 @@ module Qpid::Proton
408
352
  !@ssl.nil?
409
353
  end
410
354
 
411
- end
355
+ # @private
356
+ # Options are documented {Connection#open}, keep that consistent with this
357
+ def apply opts
358
+ sasl if opts[:sasl_enabled] # Explicitly enabled
359
+ unless opts.include?(:sasl_enabled) && !opts[:sasl_enabled] # Not explicitly disabled
360
+ sasl.allowed_mechs = opts[:sasl_allowed_mechs] if opts.include? :sasl_allowed_mechs
361
+ sasl.allow_insecure_mechs = opts[:sasl_allow_insecure_mechs] if opts.include? :sasl_allow_insecure_mechs
362
+ end
363
+ self.channel_max= opts[:max_sessions] if opts.include? :max_sessions
364
+ self.max_frame = opts[:max_frame_size] if opts.include? :max_frame_size
365
+ # NOTE: The idle_timeout option is in Numeric *seconds*, can be Integer, Float or Rational.
366
+ # This is consistent with idiomatic ruby.
367
+ # The transport #idle_timeout property is in *milliseconds* passed direct to C.
368
+ # Direct use of the transport is deprecated.
369
+ self.idle_timeout= (opts[:idle_timeout]*1000).round if opts.include? :idle_timeout
370
+ self.ssl(opts[:ssl_domain]) if opts[:ssl_domain]
371
+ end
412
372
 
373
+ can_raise_error :process, :error_class => TransportError
374
+ can_raise_error :close_tail, :error_class => TransportError
375
+ can_raise_error :pending, :error_class => TransportError, :below => Error::EOS
376
+ can_raise_error :close_head, :error_class => TransportError
377
+ end
413
378
  end
data/lib/core/uri.rb ADDED
@@ -0,0 +1,73 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+
19
+ require 'uri'
20
+
21
+ # Extend the standard ruby {URI} with AMQP and AMQPS schemes
22
+ module URI
23
+ # AMQP URI scheme for the AMQP protocol
24
+ class AMQP < Generic
25
+ DEFAULT_PORT = 5672
26
+
27
+ # @return [String] The AMQP address is the {#path} stripped of any leading "/"
28
+ def amqp_address() path[0] == "/" ? path[1..-1] : path; end
29
+ end
30
+ @@schemes['AMQP'] = AMQP
31
+
32
+ # AMQPS URI scheme for the AMQP protocol over TLS
33
+ class AMQPS < AMQP
34
+ DEFAULT_PORT = 5671
35
+ end
36
+ @@schemes['AMQPS'] = AMQPS
37
+ end
38
+
39
+ module Qpid::Proton
40
+ # Returns +s+ converted to a {URI::AMQP} or {URI::AMQPS} object
41
+ #
42
+ # Shortcut strings are allowed: an "amqp://" prefix is added if +s+ does
43
+ # not already look like an 'amqp:', 'amqps:' URI.
44
+ #
45
+ # @note this does not give the same result as a standard URI parser in all cases.
46
+ # For standard conversion to a URI use: {#URI}(s)
47
+ #
48
+ # @param s [String,URI] String to convert to a URI, or a URI object.
49
+ # A URI object with no scheme will be converted to {URI::AMQP}
50
+ # @return [URI::AMQP] A valid {URI::AMQP} or {URI::AMQPS} object
51
+ # @raise [BadURIError] s is a URI object with a non-AMQP scheme
52
+ # @raise [InvalidURIError] s cannot be parsed as a URI or shortcut
53
+ # @raise [::ArgumentError] s is not a string or URI
54
+ #
55
+ def self.uri(s)
56
+ case s
57
+ when URI::AMQP then s # Pass-thru
58
+ when URI::Generic
59
+ s.scheme ||= 'amqp'
60
+ u = URI.parse(s.to_s) # Re-parse as amqp
61
+ raise URI::BadURIError, "Not an AMQP URI: '#{u}'" unless u.is_a? URI::AMQP
62
+ u
63
+ else
64
+ s = String.try_convert s
65
+ raise ::ArgumentError, "bad argument (expected URI object or URI string)" unless s
66
+ case s
67
+ when %r{^amqps?:} then URI.parse(s) # Looks like an AMQP URI
68
+ when %r{^//} then URI.parse("amqp:#{s}") # Looks like a scheme-less URI
69
+ else URI.parse("amqp://#{s}") # Treat as a bare host:port/path string
70
+ end
71
+ end
72
+ end
73
+ end