amq-client 0.7.0.alpha34 → 0.7.0.alpha35

Sign up to get free protection for your applications and to get access to all the features.
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