amq-client 0.7.0.alpha34 → 0.7.0.alpha35

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.
Files changed (32) hide show
  1. data/.travis.yml +4 -0
  2. data/Gemfile +1 -1
  3. data/README.textile +1 -1
  4. data/bin/ci/before_build.sh +24 -0
  5. data/examples/eventmachine_adapter/extensions/rabbitmq/handling_confirm_select_ok.rb +2 -2
  6. data/examples/eventmachine_adapter/extensions/rabbitmq/publisher_confirmations_with_transient_messages.rb +1 -1
  7. data/examples/eventmachine_adapter/extensions/rabbitmq/publisher_confirmations_with_unroutable_message.rb +1 -1
  8. data/lib/amq/client.rb +29 -17
  9. data/lib/amq/client/adapter.rb +8 -504
  10. data/lib/amq/client/adapters/coolio.rb +4 -282
  11. data/lib/amq/client/adapters/event_machine.rb +4 -382
  12. data/lib/amq/client/async/adapter.rb +517 -0
  13. data/lib/amq/client/async/adapters/coolio.rb +291 -0
  14. data/lib/amq/client/async/adapters/event_machine.rb +392 -0
  15. data/lib/amq/client/async/adapters/eventmachine.rb +1 -0
  16. data/lib/amq/client/async/callbacks.rb +71 -0
  17. data/lib/amq/client/async/channel.rb +385 -0
  18. data/lib/amq/client/async/entity.rb +66 -0
  19. data/lib/amq/client/async/exchange.rb +157 -0
  20. data/lib/amq/client/async/extensions/rabbitmq/basic.rb +38 -0
  21. data/lib/amq/client/async/extensions/rabbitmq/confirm.rb +248 -0
  22. data/lib/amq/client/async/queue.rb +455 -0
  23. data/lib/amq/client/callbacks.rb +6 -65
  24. data/lib/amq/client/channel.rb +4 -376
  25. data/lib/amq/client/entity.rb +6 -57
  26. data/lib/amq/client/exchange.rb +4 -148
  27. data/lib/amq/client/extensions/rabbitmq/basic.rb +4 -28
  28. data/lib/amq/client/extensions/rabbitmq/confirm.rb +5 -240
  29. data/lib/amq/client/queue.rb +5 -450
  30. data/lib/amq/client/version.rb +1 -1
  31. data/spec/unit/client_spec.rb +10 -30
  32. metadata +16 -22
@@ -1,10 +1,14 @@
1
+ bundler_args: --without development
1
2
  script: "bundle exec rspec spec"
3
+ before_script: ./bin/ci/before_build.sh
2
4
  rvm:
3
5
  - 1.8.7
6
+ - 1.8.7-p174
4
7
  - ree
5
8
  - rbx
6
9
  - 1.9.2
7
10
  - jruby
11
+ - ruby-head
8
12
  gemfile:
9
13
  - Gemfile
10
14
  - gemfiles/eventmachine-pre
data/Gemfile CHANGED
@@ -22,7 +22,7 @@ custom_gem "amq-protocol", :git => "git://github.com/ruby-amqp/amq-protocol.git"
22
22
  group :development do
23
23
  gem "yard"
24
24
  # yard tags this buddy along
25
- gem "RedCloth"
25
+ gem "RedCloth", :platform => :mri
26
26
 
27
27
  gem "nake", :platform => :ruby_19
28
28
  gem "contributors", :platform => :ruby_19
@@ -71,7 +71,7 @@ h2. See also
71
71
 
72
72
  * "API documentation":http://rdoc.info/github/ruby-amqp/amq-client/master/frames
73
73
  * "Examples":https://github.com/ruby-amqp/amq-client/tree/master/examples/
74
- * "Jabber room for contributors":xmpp://amqp-dev@conf.netlab.cz
74
+ * Stop by #rabbitmq on irc.freenode.net. You can use "Web IRC client":http://webchat.freenode.net?channels=rabbitmq if you don't have IRC client installed.
75
75
  * "Ruby AMQP mailing list":http://groups.google.com/group/ruby-amqp
76
76
  * "Issue tracker":http://github.com/ruby-amqp/amq-client/issues
77
77
  * "Continous integration server":http://travis-ci.org/#!/ruby-amqp/amq-client
@@ -0,0 +1,24 @@
1
+ #!/bin/sh
2
+
3
+ # guest:guest has full access to /
4
+
5
+ sudo rabbitmqctl add_vhost /
6
+ sudo rabbitmqctl add_user guest guest
7
+ sudo rabbitmqctl set_permissions -p / guest ".*" ".*" ".*"
8
+
9
+
10
+ # guest:guest has full access to amq_client_testbed
11
+ # amq_client_gem:amq_client_gem has full access to /amq_client_testbed
12
+
13
+ sudo rabbitmqctl delete_vhost "amq_client_testbed"
14
+ sudo rabbitmqctl add_vhost "amq_client_testbed"
15
+ sudo rabbitmqctl delete_user amq_client_gem
16
+ sudo rabbitmqctl add_user amq_client_gem amq_client_gem_password
17
+ sudo rabbitmqctl set_permissions -p amq_client_testbed guest ".*" ".*" ".*"
18
+ sudo rabbitmqctl set_permissions -p amq_client_testbed amq_client_gem ".*" ".*" ".*"
19
+
20
+
21
+ # amqp_gem_reader:reader_password has read access to amq_client_testbed
22
+
23
+ sudo rabbitmqctl add_user amq_client_gem_reader reader_password
24
+ sudo rabbitmqctl set_permissions -p amq_client_testbed amq_client_gem_reader "^---$" "^---$" ".*"
@@ -11,7 +11,7 @@ amq_client_example "confirm.select (a RabbitMQ extension)" do |client|
11
11
  channel.open do
12
12
  puts "Channel #{channel.id} is now open"
13
13
 
14
- channel.confirmations do |select_ok|
14
+ channel.confirm_select do |select_ok|
15
15
  puts "Broker replied with confirm.select_ok"
16
16
  end
17
17
 
@@ -28,4 +28,4 @@ amq_client_example "confirm.select (a RabbitMQ extension)" do |client|
28
28
 
29
29
  EM.add_timer(1, show_stopper)
30
30
  end
31
- end
31
+ end
@@ -24,7 +24,7 @@ amq_client_example "Publisher confirmations using RabbitMQ extension: routable m
24
24
  x = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout)
25
25
 
26
26
  q = AMQ::Client::Queue.new(client, channel, AMQ::Protocol::EMPTY_STRING)
27
- q.declare(false, false, true, true) do |_|
27
+ q.declare(false, false, true, true) do |_, declare_ok|
28
28
  puts "Defined a new server-named queue: #{q.name}"
29
29
 
30
30
  q.bind("amq.fanout").consume(false, true, true) { |consume_ok|
@@ -22,7 +22,7 @@ amq_client_example "Publisher confirmations using RabbitMQ extension: unroutable
22
22
  end
23
23
 
24
24
  x = AMQ::Client::Exchange.new(client, channel, AMQ::Protocol::EMPTY_STRING, :direct)
25
- x.on_return { |basic_return|
25
+ x.on_return { |basic_return, metadata, payload|
26
26
  puts "Received basic.return: reply_text = #{basic_return.reply_text}, reply_code = #{basic_return.reply_code}"
27
27
  }
28
28
 
@@ -12,7 +12,7 @@ begin
12
12
  require "amq/protocol/client"
13
13
  rescue LoadError => exception
14
14
  if exception.message.match("amq/protocol")
15
- raise LoadError.new("You have to install amq-protocol library first!")
15
+ raise LoadError.new("amq-client could not load amq-protocol.")
16
16
  else
17
17
  raise exception
18
18
  end
@@ -20,26 +20,38 @@ end
20
20
 
21
21
  module AMQ
22
22
  module Client
23
- # List all the available as a hash of {adapter_name: metadata},
23
+ # List available adapters as a hash of { :adapter_name => metadata },
24
24
  # where metadata are hash with :path and :const_name keys.
25
25
  #
26
- # @example
27
- # AMQ::Client.adapters[:event_machine] # => {path: "...", const_name: "EventMachineClient"}}
28
- #
29
26
  # @return [Hash]
30
- # @api public
27
+ # @api plugin
31
28
  def self.adapters
32
- @adapters ||= begin
33
- root = File.expand_path("../client/adapters", __FILE__)
34
- Dir.glob("#{root}/*.rb").inject(Hash.new) do |buffer, path|
35
- name = path.match(/([^\/]+)\.rb$/)[1]
36
- const_base = name.to_s.gsub(/(^|_)(.)/) { $2.upcase! }
37
- meta = {:path => path, :const_name => "#{const_base}Client"}
38
- buffer.merge!(name.to_sym => meta)
39
- end
40
- end
29
+ @adapters ||= (self.async_adapters)
30
+ end
31
+
32
+ # List available asynchronous adapters.
33
+ #
34
+ # @return [Hash]
35
+ # @api plugin
36
+ # @see AMQ::Client.adapters
37
+ def self.async_adapters
38
+ @async_adapters ||= {
39
+ :eventmachine => {
40
+ :path => "amq/client/async/adapters/eventmachine",
41
+ :const_name => "Async::EventMachineClient"
42
+ },
43
+ :event_machine => {
44
+ :path => "amq/client/async/adapters/eventmachine",
45
+ :const_name => "Async::EventMachineClient"
46
+ },
47
+ :coolio => {
48
+ :path => "amq/client/async/adapters/coolio",
49
+ :const_name => "Async::CoolioClient"
50
+ }
51
+ }
41
52
  end
42
53
 
54
+
43
55
  # Establishes connection to AMQ broker using given adapter
44
56
  # (defaults to the socket adapter) and returns it. The new
45
57
  # connection object is yielded to the block if it is given.
@@ -56,14 +68,14 @@ module AMQ
56
68
  adapter.connect(settings, &block)
57
69
  end
58
70
 
59
- # Loads adapter from amq/client/adapters.
71
+ # Loads adapter given its name as a Symbol.
60
72
  #
61
73
  # @raise [InvalidAdapterNameError] When loading attempt failed (LoadError was raised).
62
74
  def self.load_adapter(adapter)
63
75
  meta = self.adapters[adapter.to_sym]
64
76
 
65
77
  require meta[:path]
66
- const_get(meta[:const_name])
78
+ eval(meta[:const_name])
67
79
  rescue LoadError
68
80
  raise InvalidAdapterNameError.new(adapter)
69
81
  end
@@ -2,514 +2,18 @@
2
2
 
3
3
  require "amq/client/logging"
4
4
  require "amq/client/settings"
5
- require "amq/client/entity"
6
- require "amq/client/channel"
5
+
6
+ require "amq/client/async/queue"
7
+ require "amq/client/async/exchange"
8
+ require "amq/client/async/channel"
9
+ require "amq/client/async/adapter"
7
10
 
8
11
  module AMQ
9
12
  # For overview of AMQP client adapters API, see {AMQ::Client::Adapter}
10
13
  module Client
11
14
 
12
-
13
- # Base adapter class. Specific implementations (for example, EventMachine-based, Cool.io-based or
14
- # sockets-based) subclass it and must implement Adapter API methods:
15
- #
16
- # * #send_raw(data)
17
- # * #estabilish_connection(settings)
18
- # * #close_connection
19
- #
20
- # @abstract
21
- module Adapter
22
-
23
- def self.included(host)
24
- host.extend ClassMethods
25
- host.extend ProtocolMethodHandlers
26
-
27
- host.class_eval do
28
-
29
- #
30
- # API
31
- #
32
-
33
- attr_accessor :logger
34
- attr_accessor :settings
35
-
36
- # @return [Array<#call>]
37
- attr_reader :callbacks
38
-
39
-
40
- # The locale defines the language in which the server will send reply texts.
41
- #
42
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.2)
43
- attr_accessor :locale
44
-
45
- # Client capabilities
46
- #
47
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.2.1)
48
- attr_accessor :client_properties
49
-
50
- # Server properties
51
- #
52
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.1.3)
53
- attr_reader :server_properties
54
-
55
- # Server capabilities
56
- #
57
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.1.3)
58
- attr_reader :server_capabilities
59
-
60
- # Locales server supports
61
- #
62
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.1.3)
63
- attr_reader :server_locales
64
-
65
- # Authentication mechanism used.
66
- #
67
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.2)
68
- attr_reader :mechanism
69
-
70
- # Authentication mechanisms broker supports.
71
- #
72
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.2)
73
- attr_reader :server_authentication_mechanisms
74
-
75
- # Channels within this connection.
76
- #
77
- # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 2.2.5)
78
- attr_reader :channels
79
-
80
- # Maximum channel number that the server permits this connection to use.
81
- # Usable channel numbers are in the range 1..channel_max.
82
- # Zero indicates no specified limit.
83
- #
84
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Sections 1.4.2.5.1 and 1.4.2.6.1)
85
- attr_accessor :channel_max
86
-
87
- # Maximum frame size that the server permits this connection to use.
88
- #
89
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Sections 1.4.2.5.2 and 1.4.2.6.2)
90
- attr_accessor :frame_max
91
-
92
-
93
- attr_reader :known_hosts
94
-
95
-
96
-
97
- # @api plugin
98
- # @see #disconnect
99
- # @note Adapters must implement this method but it is NOT supposed to be used directly.
100
- # AMQ protocol defines two-step process of closing connection (send Connection.Close
101
- # to the peer and wait for Connection.Close-Ok), implemented by {Adapter#disconnect}
102
- def close_connection
103
- raise MissingInterfaceMethodError.new("AMQ::Client.close_connection")
104
- end unless defined?(:close_connection) # since it is a module, this method may already be defined
105
- end
106
- end # self.included(host)
107
-
108
-
109
-
110
- module ClassMethods
111
- # Settings
112
- def settings
113
- @settings ||= AMQ::Client::Settings.default
114
- end
115
-
116
- def logger
117
- @logger ||= begin
118
- require "logger"
119
- Logger.new(STDERR)
120
- end
121
- end
122
-
123
- def logger=(logger)
124
- methods = AMQ::Client::Logging::REQUIRED_METHODS
125
- unless methods.all? { |method| logger.respond_to?(method) }
126
- raise AMQ::Client::Logging::IncompatibleLoggerError.new(methods)
127
- end
128
-
129
- @logger = logger
130
- end
131
-
132
- # @return [Boolean] Current value of logging flag.
133
- def logging
134
- settings[:logging]
135
- end
136
-
137
- # Turns loggin on or off.
138
- def logging=(boolean)
139
- settings[:logging] = boolean
140
- end
141
-
142
-
143
- # Establishes connection to AMQ broker and returns it. New connection object is yielded to
144
- # the block if it is given.
145
- #
146
- # @example Specifying adapter via the :adapter option
147
- # AMQ::Client::Adapter.connect(:adapter => "socket")
148
- # @example Specifying using custom adapter class
149
- # AMQ::Client::SocketClient.connect
150
- # @param [Hash] Connection parameters, including :adapter to use.
151
- # @api public
152
- def connect(settings = nil, &block)
153
- @settings = Settings.configure(settings)
154
-
155
- instance = self.new
156
- instance.establish_connection(settings)
157
- instance.register_connection_callback(&block)
158
-
159
- instance
160
- end
161
-
162
-
163
- # Can be overriden by higher-level libraries like amqp gem or bunny.
164
- # Defaults to AMQ::Client::TCPConnectionFailed.
165
- #
166
- # @return [Class]
167
- def tcp_connection_failure_exception_class
168
- @tcp_connection_failure_exception_class ||= AMQ::Client::TCPConnectionFailed
169
- end # tcp_connection_failure_exception_class
170
-
171
- # Can be overriden by higher-level libraries like amqp gem or bunny.
172
- # Defaults to AMQ::Client::PossibleAuthenticationFailure.
173
- #
174
- # @return [Class]
175
- def authentication_failure_exception_class
176
- @authentication_failure_exception_class ||= AMQ::Client::PossibleAuthenticationFailureError
177
- end # authentication_failure_exception_class
178
- end # ClassMethods
179
-
180
-
181
- #
182
- # Behaviors
183
- #
184
-
185
- include Openable
186
- include Callbacks
187
-
188
-
189
- extend RegisterEntityMixin
190
-
191
- register_entity :channel, AMQ::Client::Channel
192
-
193
-
194
- #
195
- # API
196
- #
197
-
198
-
199
- # Establish socket connection to the server.
200
- #
201
- # @api plugin
202
- def establish_connection(settings)
203
- raise MissingInterfaceMethodError.new("AMQ::Client#establish_connection(settings)")
204
- end
205
-
206
- # Properly close connection with AMQ broker, as described in
207
- # section 2.2.4 of the {http://bit.ly/hw2ELX AMQP 0.9.1 specification}.
208
- #
209
- # @api plugin
210
- # @see #close_connection
211
- def disconnect(reply_code = 200, reply_text = "Goodbye", class_id = 0, method_id = 0, &block)
212
- @intentionally_closing_connection = true
213
- self.on_disconnection(&block)
214
-
215
- # ruby-amqp/amqp#66, MK.
216
- if self.open?
217
- closing!
218
- self.send_frame(Protocol::Connection::Close.encode(reply_code, reply_text, class_id, method_id))
219
- elsif self.closing?
220
- # no-op
221
- else
222
- self.disconnection_successful
223
- end
224
- end
225
-
226
-
227
- # Sends AMQ protocol header (also known as preamble).
228
- #
229
- # @note This must be implemented by all AMQP clients.
230
- # @api plugin
231
- # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 2.2)
232
- def send_preamble
233
- self.send_raw(AMQ::Protocol::PREAMBLE)
234
- end
235
-
236
- # Sends frame to the peer, checking that connection is open.
237
- #
238
- # @raise [ConnectionClosedError]
239
- def send_frame(frame)
240
- if closed?
241
- raise ConnectionClosedError.new(frame)
242
- else
243
- self.send_raw(frame.encode)
244
- end
245
- end
246
-
247
- # Sends multiple frames, one by one.
248
- #
249
- # @api public
250
- def send_frameset(frames)
251
- frames.each { |frame| self.send_frame(frame) }
252
- end # send_frameset(frames)
253
-
254
-
255
-
256
- # Returns heartbeat interval this client uses, in seconds.
257
- # This value may or may not be used depending on broker capabilities.
258
- # Zero means the server does not want a heartbeat.
259
- #
260
- # @return [Fixnum] Heartbeat interval this client uses, in seconds.
261
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.6)
262
- def heartbeat_interval
263
- @settings[:heartbeat] || @settings[:heartbeat_interval] || 0
264
- end # heartbeat_interval
265
-
266
-
267
- # vhost this connection uses. Default is "/", a historically estabilished convention
268
- # of RabbitMQ and amqp gem.
269
- #
270
- # @return [String] vhost this connection uses
271
- # @api public
272
- def vhost
273
- @settings.fetch(:vhost, "/")
274
- end # vhost
275
-
276
-
277
- # Called when previously established TCP connection fails.
278
- # @api public
279
- def tcp_connection_lost
280
- @on_tcp_connection_loss.call(self, @settings) if @on_tcp_connection_loss
281
- end
282
-
283
- # Called when initial TCP connection fails.
284
- # @api public
285
- def tcp_connection_failed
286
- @on_tcp_connection_failure.call(@settings) if @on_tcp_connection_failure
287
- end
288
-
289
-
290
-
291
- #
292
- # Implementation
293
- #
294
-
295
-
296
- # Sends opaque data to AMQ broker over active connection.
297
- #
298
- # @note This must be implemented by all AMQP clients.
299
- # @api plugin
300
- def send_raw(data)
301
- raise MissingInterfaceMethodError.new("AMQ::Client#send_raw(data)")
302
- end
303
-
304
- # Sends connection preamble to the broker.
305
- # @api plugin
306
- def handshake
307
- @authenticating = true
308
- self.send_preamble
309
- end
310
-
311
-
312
- # Sends connection.open to the server.
313
- #
314
- # @api plugin
315
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.7)
316
- def open(vhost = "/")
317
- self.send_frame(Protocol::Connection::Open.encode(vhost))
318
- end
319
-
320
- # Resets connection state.
321
- #
322
- # @api plugin
323
- def reset_state!
324
- # no-op by default
325
- end # reset_state!
326
-
327
- # @api plugin
328
- # @see http://tools.ietf.org/rfc/rfc2595.txt RFC 2595
329
- def encode_credentials(username, password)
330
- "\0#{username}\0#{password}"
331
- end # encode_credentials(username, password)
332
-
333
-
334
- # Processes a single frame.
335
- #
336
- # @param [AMQ::Protocol::Frame] frame
337
- # @api plugin
338
- def receive_frame(frame)
339
- @frames << frame
340
- if frameset_complete?(@frames)
341
- receive_frameset(@frames)
342
- @frames.clear
343
- else
344
- # puts "#{frame.inspect} is NOT final"
345
- end
346
- end
347
-
348
- # Processes a frameset by finding and invoking a suitable handler.
349
- # Heartbeat frames are treated in a special way: they simply update @last_server_heartbeat
350
- # value.
351
- #
352
- # @param [Array<AMQ::Protocol::Frame>] frames
353
- # @api plugin
354
- def receive_frameset(frames)
355
- frame = frames.first
356
-
357
- if Protocol::HeartbeatFrame === frame
358
- @last_server_heartbeat = Time.now
359
- else
360
- if callable = AMQ::Client::HandlersRegistry.find(frame.method_class)
361
- callable.call(self, frames.first, frames[1..-1])
362
- else
363
- raise MissingHandlerError.new(frames.first)
364
- end
365
- end
366
- end
367
-
368
- # Sends a heartbeat frame if connection is open.
369
- # @api plugin
370
- def send_heartbeat
371
- if tcp_connection_established?
372
- if @last_server_heartbeat < (Time.now - (self.heartbeat_interval * 2))
373
- logger.error "Reconnecting due to missing server heartbeats"
374
- # TODO: reconnect
375
- end
376
- send_frame(Protocol::HeartbeatFrame)
377
- end
378
- end # send_heartbeat
379
-
380
-
381
-
382
-
383
- # @group Error handling
384
-
385
- # Defines a callback that will be executed when channel is closed after
386
- # channel-level exception. Only one callback can be added (the one added last
387
- # replaces previous added ones).
388
- #
389
- # @api public
390
- def on_error(&block)
391
- self.redefine_callback(:error, &block)
392
- end
393
-
394
- # @endgroup
395
-
396
-
397
-
398
-
399
- # Handles connection.start.
400
- #
401
- # @api plugin
402
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.1.)
403
- def handle_start(connection_start)
404
- @server_properties = connection_start.server_properties
405
- @server_capabilities = @server_properties["capabilities"]
406
-
407
- @server_authentication_mechanisms = (connection_start.mechanisms || "").split(" ")
408
- @server_locales = Array(connection_start.locales)
409
-
410
- username = @settings[:user] || @settings[:username]
411
- password = @settings[:pass] || @settings[:password]
412
-
413
- # It's not clear whether we should transition to :opening state here
414
- # or in #open but in case authentication fails, it would be strange to have
415
- # @status undefined. So lets do this. MK.
416
- opening!
417
-
418
- self.send_frame(Protocol::Connection::StartOk.encode(@client_properties, @mechanism, self.encode_credentials(username, password), @locale))
419
- end
420
-
421
-
422
- # Handles Connection.Tune-Ok.
423
- #
424
- # @api plugin
425
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.6)
426
- def handle_tune(tune_ok)
427
- @channel_max = tune_ok.channel_max.freeze
428
- @frame_max = tune_ok.frame_max.freeze
429
- @heartbeat_interval = self.heartbeat_interval || tune_ok.heartbeat
430
-
431
- self.send_frame(Protocol::Connection::TuneOk.encode(@channel_max, [settings[:frame_max], @frame_max].min, @heartbeat_interval))
432
- end # handle_tune(method)
433
-
434
-
435
- # Handles Connection.Open-Ok.
436
- #
437
- # @api plugin
438
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.8.)
439
- def handle_open_ok(open_ok)
440
- @known_hosts = open_ok.known_hosts.dup.freeze
441
-
442
- opened!
443
- self.connection_successful if self.respond_to?(:connection_successful)
444
- end
445
-
446
-
447
- # Handles connection.close. When broker detects a connection level exception, this method is called.
448
- #
449
- # @api plugin
450
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.5.2.9)
451
- def handle_close(conn_close)
452
- self.handle_connection_interruption
453
-
454
- closed!
455
- # TODO: use proper exception class, provide protocol class (we know conn_close.class_id and conn_close.method_id) as well!
456
- self.exec_callback_yielding_self(:error, conn_close)
457
- end
458
-
459
-
460
- # Handles Connection.Close-Ok.
461
- #
462
- # @api plugin
463
- # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.10)
464
- def handle_close_ok(close_ok)
465
- closed!
466
- self.disconnection_successful
467
- end # handle_close_ok(close_ok)
468
-
469
- # @api plugin
470
- def handle_connection_interruption
471
- @channels.each { |n, c| c.handle_connection_interruption }
472
- end # handle_connection_interruption
473
-
474
-
475
-
476
- protected
477
-
478
- # Returns next frame from buffer whenever possible
479
- #
480
- # @api private
481
- def get_next_frame
482
- return nil unless @chunk_buffer.size > 7 # otherwise, cannot read the length
483
- # octet + short
484
- offset = 3 # 1 + 2
485
- # length
486
- payload_length = @chunk_buffer[offset, 4].unpack(AMQ::Protocol::PACK_UINT32).first
487
- # 4 bytes for long payload length, 1 byte final octet
488
- frame_length = offset + payload_length + 5
489
- if frame_length <= @chunk_buffer.size
490
- @chunk_buffer.slice!(0, frame_length)
491
- else
492
- nil
493
- end
494
- end # def get_next_frame
495
-
496
- # Utility methods
497
-
498
- # Determines, whether the received frameset is ready to be further processed
499
- def frameset_complete?(frames)
500
- return false if frames.empty?
501
- first_frame = frames[0]
502
- first_frame.final? || (first_frame.method_class.has_content? && content_complete?(frames[1..-1]))
503
- end
504
-
505
- # Determines, whether given frame array contains full content body
506
- def content_complete?(frames)
507
- return false if frames.empty?
508
- header = frames[0]
509
- raise "Not a content header frame first: #{header.inspect}" unless header.kind_of?(AMQ::Protocol::HeaderFrame)
510
- header.body_size == frames[1..-1].inject(0) {|sum, frame| sum + frame.payload.size }
511
- end
512
-
513
- end # Adapter
15
+ # backwards compatibility
16
+ # @private
17
+ Adapter = Async::Adapter
514
18
  end # Client
515
19
  end # AMQ