amq-client 0.7.0.alpha25 → 0.7.0.alpha26

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.
data/.travis.yml CHANGED
@@ -4,7 +4,6 @@ rvm:
4
4
  - 1.9.2
5
5
  - ree
6
6
  - rbx
7
- - jruby
8
7
  gemfile:
9
8
  - Gemfile
10
9
  - gemfiles/eventmachine-pre
@@ -4,13 +4,13 @@
4
4
  __dir = File.dirname(File.expand_path(__FILE__))
5
5
  require File.join(__dir, "example_helper")
6
6
 
7
- amq_client_example "Set a queue up for message delivery" do |client|
8
- channel = AMQ::Client::Channel.new(client, 1)
7
+ amq_client_example "Set a queue up for message delivery" do |connection|
8
+ channel = AMQ::Client::Channel.new(connection, 1)
9
9
  channel.open do
10
10
  puts "Channel #{channel.id} is now open!"
11
11
  end
12
12
 
13
- queue = AMQ::Client::Queue.new(client, channel)
13
+ queue = AMQ::Client::Queue.new(connection, channel)
14
14
  queue.declare(false, false, false, true) do
15
15
  puts "Server-named, auto-deletable Queue #{queue.name.inspect} is ready"
16
16
  end
@@ -19,30 +19,34 @@ amq_client_example "Set a queue up for message delivery" do |client|
19
19
  puts "Queue #{queue.name} is now bound to amq.fanout"
20
20
  end
21
21
 
22
- queue.consume(true) do |consumer_tag|
23
- puts "Subscribed for messages routed to #{queue.name}, consumer tag is #{consumer_tag}, using no-ack mode"
22
+ show_stopper = Proc.new {
23
+ connection.disconnect do
24
+ puts
25
+ puts "AMQP connection is now properly closed"
26
+ Coolio::Loop.default.stop
27
+ end
28
+ }
29
+
30
+
31
+ queue.consume(true) do |consume_ok|
32
+ puts "Subscribed for messages routed to #{queue.name}, consumer tag is #{consume_ok.consumer_tag}, using no-ack mode"
24
33
  puts
25
34
 
26
- queue.on_delivery do |header, payload, consumer_tag, delivery_tag, redelivered, exchange, routing_key|
35
+ queue.on_delivery do |basic_deliver, header, payload|
27
36
  puts "Got a delivery:"
28
- puts " Delivery tag: #{delivery_tag}"
37
+ puts " Delivery tag: #{basic_deliver.delivery_tag}"
29
38
  puts " Header: #{header.inspect}"
30
39
  puts " Payload: #{payload.inspect}"
40
+
41
+ show_stopper.call if basic_deliver.delivery_tag == 100
31
42
  end
32
43
 
33
- exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout)
44
+ exchange = AMQ::Client::Exchange.new(connection, channel, "amq.fanout", :fanout)
34
45
  100.times do |i|
35
46
  exchange.publish("Message ##{i}")
36
47
  end
37
48
  end
38
49
 
39
- show_stopper = Proc.new {
40
- client.disconnect do
41
- puts
42
- puts "AMQP connection is now properly closed"
43
- Coolio::Loop.default.stop
44
- end
45
- }
46
50
 
47
51
  Signal.trap "INT", show_stopper
48
52
  Signal.trap "TERM", show_stopper
@@ -4,17 +4,17 @@
4
4
  __dir = File.dirname(File.expand_path(__FILE__))
5
5
  require File.join(__dir, "example_helper")
6
6
 
7
- amq_client_example "Open and then close AMQ channel" do |client|
8
- puts "AMQP connection is open: #{client.connection.server_properties.inspect}"
7
+ amq_client_example "Open and then close AMQ channel" do |connection|
8
+ puts "AMQP connection is open: #{connection.server_properties.inspect}"
9
9
 
10
- channel = AMQ::Client::Channel.new(client, 1)
10
+ channel = AMQ::Client::Channel.new(connection, 1)
11
11
  channel.open do
12
12
  puts "Channel #{channel.id} is now open!"
13
13
  puts "Lets close it."
14
14
  channel.close do
15
15
  puts "Closed channel ##{channel.id}"
16
16
  puts
17
- client.disconnect do
17
+ connection.disconnect do
18
18
  puts
19
19
  puts "AMQP connection is now properly closed"
20
20
  Coolio::Loop.default.stop
@@ -8,7 +8,7 @@ EM.run do
8
8
  AMQ::Client::EventMachineClient.connect(:port => 5672, :vhost => "/amq_client_testbed", :user => "guest", :password => "guest") do |client|
9
9
  puts "Connected, authenticated"
10
10
 
11
- puts client.authenticating?
11
+ puts "client.authenticating? => #{client.authenticating?}"
12
12
 
13
13
 
14
14
  show_stopper = Proc.new {
@@ -4,13 +4,13 @@
4
4
  __dir = File.dirname(File.expand_path(__FILE__))
5
5
  require File.join(__dir, "example_helper")
6
6
 
7
- amq_client_example "Set a queue up for message delivery" do |client|
8
- channel = AMQ::Client::Channel.new(client, 1)
7
+ amq_client_example "Set a queue up for message delivery" do |connection|
8
+ channel = AMQ::Client::Channel.new(connection, 1)
9
9
  channel.open do
10
10
  puts "Channel #{channel.id} is now open!"
11
11
  end
12
12
 
13
- queue = AMQ::Client::Queue.new(client, channel)
13
+ queue = AMQ::Client::Queue.new(connection, channel)
14
14
  queue.declare(false, false, false, true) do
15
15
  puts "Server-named, auto-deletable Queue #{queue.name.inspect} is ready"
16
16
  end
@@ -19,33 +19,35 @@ amq_client_example "Set a queue up for message delivery" do |client|
19
19
  puts "Queue #{queue.name} is now bound to amq.fanout"
20
20
  end
21
21
 
22
- queue.consume(true) do |method|
23
- puts "Subscribed for messages routed to #{queue.name}, consumer tag is #{method.consumer_tag}, using no-ack mode"
22
+ show_stopper = Proc.new {
23
+ connection.disconnect do
24
+ puts
25
+ puts "AMQP connection is now properly closed"
26
+ EM.stop
27
+ end
28
+ }
29
+
30
+ queue.consume(true) do |consume_ok|
31
+ puts "Subscribed for messages routed to #{queue.name}, consumer tag is #{consume_ok.consumer_tag}, using no-ack mode"
24
32
  puts
25
33
 
26
- queue.on_delivery do |method, header, payload|
34
+ queue.on_delivery do |basic_deliver, header, payload|
27
35
  puts "Got a delivery:"
28
- puts " Delivery tag: #{method.delivery_tag}"
36
+ puts " Delivery tag: #{basic_deliver.delivery_tag}"
29
37
  puts " Header: #{header.inspect}"
30
38
  puts " Payload: #{payload.inspect}"
39
+
40
+ show_stopper.call if basic_deliver.delivery_tag == 100
31
41
  end
32
42
 
33
- exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout)
43
+ exchange = AMQ::Client::Exchange.new(connection, channel, "amq.fanout", :fanout)
34
44
  100.times do |i|
35
45
  exchange.publish("Message ##{i}")
36
46
  end
37
47
  end
38
48
 
39
- show_stopper = Proc.new {
40
- client.disconnect do
41
- puts
42
- puts "AMQP connection is now properly closed"
43
- EM.stop
44
- end
45
- }
46
-
47
49
  Signal.trap "INT", show_stopper
48
50
  Signal.trap "TERM", show_stopper
49
51
 
50
- EM.add_timer(1, show_stopper)
52
+ EM.add_timer(1, show_stopper)
51
53
  end
@@ -4,15 +4,15 @@
4
4
  __dir = File.dirname(File.expand_path(__FILE__))
5
5
  require File.join(__dir, "example_helper")
6
6
 
7
- amq_client_example "Publish 100 messages using basic.publish" do |client|
8
- puts "AMQP connection is open: #{client.connection.server_properties.inspect}"
7
+ amq_client_example "Publish 100 messages using basic.publish" do |connection|
8
+ puts "AMQP connection is open: #{connection.server_properties.inspect}"
9
9
 
10
- channel = AMQ::Client::Channel.new(client, 1)
10
+ channel = AMQ::Client::Channel.new(connection, 1)
11
11
  channel.open do
12
12
  puts "Channel #{channel.id} is now open!"
13
13
  end
14
14
 
15
- exchange = AMQ::Client::Exchange.new(client, channel, "amqclient.adapters.em.exchange1", :fanout)
15
+ exchange = AMQ::Client::Exchange.new(connection, channel, "amqclient.adapters.em.exchange1", :fanout)
16
16
  exchange.declare do
17
17
  100.times do
18
18
  # exchange.publish("à bientôt!")
@@ -24,7 +24,7 @@ amq_client_example "Publish 100 messages using basic.publish" do |client|
24
24
  end
25
25
 
26
26
  show_stopper = Proc.new {
27
- client.disconnect do
27
+ connection.disconnect do
28
28
  puts
29
29
  puts "AMQP connection is now properly closed"
30
30
  EM.stop
@@ -4,17 +4,17 @@
4
4
  __dir = File.dirname(File.expand_path(__FILE__))
5
5
  require File.join(__dir, "example_helper")
6
6
 
7
- amq_client_example "Open and then close AMQ channel" do |client|
8
- puts "AMQP connection is open: #{client.connection.server_properties.inspect}"
7
+ amq_client_example "Open and then close AMQ channel" do |connection|
8
+ puts "AMQP connection is open: #{connection.server_properties.inspect}"
9
9
 
10
- channel = AMQ::Client::Channel.new(client, 1)
10
+ channel = AMQ::Client::Channel.new(connection, 1)
11
11
  channel.open do
12
12
  puts "Channel #{channel.id} is now open!"
13
13
  puts "Lets close it."
14
14
  channel.close do
15
15
  puts "Closed channel ##{channel.id}"
16
16
  puts
17
- client.disconnect do
17
+ connection.disconnect do
18
18
  puts
19
19
  puts "AMQP connection is now properly closed"
20
20
  EM.stop
@@ -4,24 +4,24 @@
4
4
  __dir = File.dirname(File.expand_path(__FILE__))
5
5
  require File.join(__dir, "example_helper")
6
6
 
7
- amq_client_example "Declare a new fanout exchange" do |client|
8
- puts "AMQP connection is open: #{client.connection.server_properties.inspect}"
7
+ amq_client_example "Declare a new fanout exchange" do |connection|
8
+ puts "AMQP connection is open: #{connection.server_properties.inspect}"
9
9
 
10
- channel = AMQ::Client::Channel.new(client, 1)
10
+ channel = AMQ::Client::Channel.new(connection, 1)
11
11
  channel.open do
12
12
  puts "Channel #{channel.id} is now open!"
13
13
 
14
14
  exchange_name = "amqclient.adapters.em.exchange"
15
15
 
16
16
  10.times do
17
- exchange = AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout)
17
+ exchange = AMQ::Client::Exchange.new(connection, channel, exchange_name, :fanout)
18
18
  exchange.declare
19
19
  end
20
20
 
21
- exchange2 = AMQ::Client::Exchange.new(client, channel, exchange_name + "-2", :fanout)
21
+ exchange2 = AMQ::Client::Exchange.new(connection, channel, exchange_name + "-2", :fanout)
22
22
  exchange2.declare
23
23
 
24
- AMQ::Client::Exchange.new(client, channel, exchange_name, :fanout).declare do |exchange, declare_ok|
24
+ AMQ::Client::Exchange.new(connection, channel, exchange_name, :fanout).declare do |exchange, declare_ok|
25
25
  puts "Channel is aware of the following exchanges: #{channel.exchanges.map { |e| e.name }.join(', ')}"
26
26
 
27
27
  exchange.delete do
@@ -29,7 +29,7 @@ amq_client_example "Declare a new fanout exchange" do |client|
29
29
  exchange2.delete do
30
30
  puts "Exchange #{exchange2.name} was successfully deleted"
31
31
 
32
- client.disconnect do
32
+ connection.disconnect do
33
33
  puts
34
34
  puts "AMQP connection is now properly closed"
35
35
  EM.stop
@@ -39,7 +39,7 @@ amq_client_example "Declare a new fanout exchange" do |client|
39
39
  end
40
40
 
41
41
  show_stopper = Proc.new {
42
- client.disconnect do
42
+ connection.disconnect do
43
43
  puts
44
44
  puts "AMQP connection is now properly closed"
45
45
  EM.stop
@@ -4,37 +4,37 @@
4
4
  __dir = File.dirname(File.expand_path(__FILE__))
5
5
  require File.join(__dir, "example_helper")
6
6
 
7
- amq_client_example "An example that combines several AMQ operations" do |client|
8
- puts "AMQP connection is open: #{client.connection.server_properties.inspect}"
7
+ amq_client_example "An example that combines several AMQ operations" do |connection|
8
+ puts "AMQP connection is open: #{connection.server_properties.inspect}"
9
9
 
10
- channel = AMQ::Client::Channel.new(client, 1)
10
+ channel = AMQ::Client::Channel.new(connection, 1)
11
11
  channel.open do
12
12
  puts "Channel #{channel.id} is now open!"
13
13
  end
14
14
 
15
- queue = AMQ::Client::Queue.new(client, channel, "amqclient.queue2")
15
+ queue = AMQ::Client::Queue.new(connection, channel, "amqclient.queue2")
16
16
  queue.declare(false, false, false, true) do
17
17
  puts "Queue #{queue.name.inspect} is now declared!"
18
18
  end
19
19
 
20
- exchange = AMQ::Client::Exchange.new(client, channel, "amqclient.adapters.em.exchange1", :fanout)
20
+ exchange = AMQ::Client::Exchange.new(connection, channel, "amqclient.adapters.em.exchange1", :fanout)
21
21
  exchange.declare { puts "Exchange #{exchange.name.inspect} is now declared!" }
22
22
 
23
- queue.consume do |msg|
24
- puts msg
23
+ queue.consume do |consume_ok|
24
+ puts "basic.consume_ok callback has fired for #{queue.name}, consumer_tag = #{consume_ok.consumer_tag}"
25
25
  end
26
26
 
27
27
 
28
28
  show_stopper = Proc.new {
29
29
  puts
30
30
  puts "Deleting queue #{queue.name}"
31
- queue.delete do |message_count|
31
+ queue.delete do |delete_ok|
32
32
  puts
33
- puts "Deleted #{queue.name}. It had #{message_count} messages in it."
33
+ puts "Deleted #{queue.name}. It had #{delete_ok.message_count} messages in it."
34
34
  puts
35
35
  puts "Deleting exchange #{exchange.name}"
36
36
  exchange.delete do
37
- client.disconnect do
37
+ connection.disconnect do
38
38
  puts
39
39
  puts "AMQP connection is now properly closed"
40
40
  EM.stop
@@ -3,12 +3,13 @@
3
3
  require "amq/client/logging"
4
4
  require "amq/client/settings"
5
5
  require "amq/client/entity"
6
- require "amq/client/connection"
7
6
  require "amq/client/channel"
8
7
 
9
8
  module AMQ
10
9
  # For overview of AMQP client adapters API, see {AMQ::Client::Adapter}
11
10
  module Client
11
+
12
+
12
13
  # Base adapter class. Specific implementations (for example, EventMachine-based, Cool.io-based or
13
14
  # sockets-based) subclass it and must implement Adapter API methods:
14
15
  #
@@ -20,22 +21,69 @@ module AMQ
20
21
  module Adapter
21
22
 
22
23
  def self.included(host)
23
- host.extend(ClassMethods)
24
+ host.extend ClassMethods
25
+ host.extend ProtocolMethodHandlers
24
26
 
25
27
  host.class_eval do
26
- attr_accessor :logger, :settings, :connection
27
28
 
28
- # Authentication mechanism
29
- attr_accessor :mechanism
29
+ #
30
+ # Behaviors
31
+ #
32
+
33
+ include Entity
34
+
30
35
 
31
- # Security response data
32
- attr_accessor :response
36
+
37
+ #
38
+ # API
39
+ #
40
+
41
+ attr_accessor :logger
42
+ attr_accessor :settings
43
+ attr_accessor :connection
33
44
 
34
45
  # The locale defines the language in which the server will send reply texts.
35
46
  #
36
47
  # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.2)
37
48
  attr_accessor :locale
38
49
 
50
+ # Client capabilities
51
+ #
52
+ # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.2.1)
53
+ attr_accessor :client_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_properties
59
+
60
+ # Authentication mechanism used.
61
+ #
62
+ # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.2)
63
+ attr_reader :mechanism
64
+
65
+ # Channels within this connection.
66
+ #
67
+ # @see http://bit.ly/hw2ELX AMQP 0.9.1 specification (Section 2.2.5)
68
+ attr_reader :channels
69
+
70
+ # Maximum channel number that the server permits this connection to use.
71
+ # Usable channel numbers are in the range 1..channel_max.
72
+ # Zero indicates no specified limit.
73
+ #
74
+ # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Sections 1.4.2.5.1 and 1.4.2.6.1)
75
+ attr_accessor :channel_max
76
+
77
+ # Maximum frame size that the server permits this connection to use.
78
+ #
79
+ # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Sections 1.4.2.5.2 and 1.4.2.6.2)
80
+ attr_accessor :frame_max
81
+
82
+
83
+ attr_reader :known_hosts
84
+
85
+
86
+
39
87
  # @api plugin
40
88
  # @see #disconnect
41
89
  # @note Adapters must implement this method but it is NOT supposed to be used directly.
@@ -92,9 +140,7 @@ module AMQ
92
140
  # @param [Hash] Connection parameters, including :adapter to use.
93
141
  # @api public
94
142
  def connect(settings = nil, &block)
95
- # TODO: this doesn't look very nice, do we need it?
96
- # Let's make it an instance thing by instance = self.new(settings)
97
- @settings = settings = Settings.configure(settings)
143
+ @settings = Settings.configure(settings)
98
144
 
99
145
  instance = self.new
100
146
  instance.establish_connection(settings)
@@ -132,20 +178,11 @@ module AMQ
132
178
 
133
179
  register_entity :channel, AMQ::Client::Channel
134
180
 
181
+
135
182
  #
136
183
  # API
137
184
  #
138
185
 
139
- def initialize(*args)
140
- super(*args)
141
-
142
- self.logger = self.class.logger
143
- self.settings = self.class.settings
144
-
145
- @frames = Array.new
146
- end
147
-
148
-
149
186
 
150
187
  # Establish socket connection to the server.
151
188
  #
@@ -154,30 +191,26 @@ module AMQ
154
191
  raise MissingInterfaceMethodError.new("AMQ::Client#establish_connection(settings)")
155
192
  end
156
193
 
157
- def handshake(mechanism = "PLAIN", response = "\0guest\0guest", locale = "en_GB")
158
- self.send_preamble
159
- self.connection = AMQ::Client::Connection.new(self, mechanism, response, locale)
160
- end
161
-
162
194
  # Properly close connection with AMQ broker, as described in
163
195
  # section 2.2.4 of the {http://bit.ly/hw2ELX AMQP 0.9.1 specification}.
164
196
  #
165
197
  # @api plugin
166
198
  # @see #close_connection
167
- def disconnect(reply_code = 200, reply_text = "Goodbye", &block)
199
+ def disconnect(reply_code = 200, reply_text = "Goodbye", class_id = 0, method_id = 0, &block)
168
200
  @intentionally_closing_connection = true
169
-
170
201
  self.on_disconnection(&block)
171
- closing!
172
202
 
173
203
  # ruby-amqp/amqp#66, MK.
174
- if self.connection
175
- self.connection.close(reply_code, reply_text)
204
+ if self.open?
205
+ closing!
206
+ self.send Protocol::Connection::Close.encode(reply_code, reply_text, class_id, method_id)
207
+ elsif self.closing?
208
+ # no-op
176
209
  else
177
210
  self.disconnection_successful
178
211
  end
179
212
  end
180
- alias close disconnect
213
+
181
214
 
182
215
  # Sends AMQ protocol header (also known as preamble).
183
216
  #
@@ -188,19 +221,61 @@ module AMQ
188
221
  self.send_raw(AMQ::Protocol::PREAMBLE)
189
222
  end
190
223
 
224
+ # Sends frame to the peer, checking that connection is open.
225
+ #
226
+ # @raise [ConnectionClosedError]
191
227
  def send(frame)
192
- if self.connection.closed?
228
+ if closed?
193
229
  raise ConnectionClosedError.new(frame)
194
230
  else
195
231
  self.send_raw(frame.encode)
196
232
  end
197
233
  end
198
234
 
235
+ # Sends multiple frames, one by one.
236
+ #
237
+ # @api public
199
238
  def send_frameset(frames)
200
239
  frames.each { |frame| self.send(frame) }
201
240
  end # send_frameset(frames)
202
241
 
203
242
 
243
+
244
+ # Returns heartbeat interval this client uses, in seconds.
245
+ # This value may or may not be used depending on broker capabilities.
246
+ # Zero means the server does not want a heartbeat.
247
+ #
248
+ # @return [Fixnum] Heartbeat interval this client uses, in seconds.
249
+ # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.6)
250
+ def heartbeat_interval
251
+ @settings[:heartbeat] || @settings[:heartbeat_interval] || 0
252
+ end # heartbeat_interval
253
+
254
+
255
+ def vhost
256
+ @settings.fetch(:vhost, "/")
257
+ end # vhost
258
+
259
+
260
+ # Called when previously established TCP connection fails.
261
+ # @api public
262
+ def tcp_connection_lost
263
+ @on_tcp_connection_loss.call(self, @settings) if @on_tcp_connection_loss
264
+ end
265
+
266
+ # Called when initial TCP connection fails.
267
+ # @api public
268
+ def tcp_connection_failed
269
+ @on_tcp_connection_failure.call(@settings) if @on_tcp_connection_failure
270
+ end
271
+
272
+
273
+
274
+ #
275
+ # Implementation
276
+ #
277
+
278
+
204
279
  # Sends opaque data to AMQ broker over active connection.
205
280
  #
206
281
  # @note This must be implemented by all AMQP clients.
@@ -209,6 +284,35 @@ module AMQ
209
284
  raise MissingInterfaceMethodError.new("AMQ::Client#send_raw(data)")
210
285
  end
211
286
 
287
+ # Sends connection preamble to the broker.
288
+ def handshake
289
+ @authenticating = true
290
+ self.send_preamble
291
+ end
292
+
293
+
294
+ # Sends connection.open to the server.
295
+ #
296
+ # @api plugin
297
+ # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.7)
298
+ def open(vhost = "/")
299
+ self.send Protocol::Connection::Open.encode(vhost)
300
+ end
301
+
302
+ # Resets connection state.
303
+ #
304
+ # @api plugin
305
+ def reset_state!
306
+ # no-op by default
307
+ end # reset_state!
308
+
309
+ # @api plugin
310
+ # @see http://tools.ietf.org/rfc/rfc2595.txt RFC 2595
311
+ def encode_credentials(username, password)
312
+ "\0#{username}\0#{password}"
313
+ end # encode_credentials(username, password)
314
+
315
+
212
316
  def receive_frame(frame)
213
317
  @frames << frame
214
318
  if frameset_complete?(@frames)
@@ -251,17 +355,100 @@ module AMQ
251
355
  end # send_heartbeat
252
356
 
253
357
 
254
- # Returns heartbeat interval this client uses, in seconds.
255
- # This value may or may not be used depending on broker capabilities.
358
+
359
+ # Handles Connection.Start.
256
360
  #
257
- # @return [Fixnum] Heartbeat interval this client uses, in seconds.
361
+ # @api plugin
362
+ # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.1.)
363
+ def start_ok(method)
364
+ @server_properties = method.server_properties
365
+
366
+ username = @settings[:user] || @settings[:username]
367
+ password = @settings[:pass] || @settings[:password]
368
+
369
+ # It's not clear whether we should transition to :opening state here
370
+ # or in #open but in case authentication fails, it would be strange to have
371
+ # @status undefined. So lets do this. MK.
372
+ opening!
373
+
374
+ self.send Protocol::Connection::StartOk.encode(@client_properties, @mechanism, self.encode_credentials(username, password), @locale)
375
+ end
376
+
377
+
378
+ # Handles Connection.Open-Ok.
379
+ #
380
+ # @api plugin
381
+ # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.8.)
382
+ def handle_open_ok(method)
383
+ @known_hosts = method.known_hosts
384
+
385
+ opened!
386
+ self.connection_successful if self.respond_to?(:connection_successful)
387
+ end
388
+
389
+ # Handles Connection.Tune-Ok.
390
+ #
391
+ # @api plugin
258
392
  # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.6)
259
- def heartbeat_interval
260
- @settings[:heartbeat] || @settings[:heartbeat_interval] || 0
261
- end # heartbeat_interval
393
+ def handle_tune(method)
394
+ @channel_max = method.channel_max
395
+ @frame_max = method.frame_max
396
+ @heartbeat_interval = self.heartbeat_interval || method.heartbeat
397
+
398
+ self.send Protocol::Connection::TuneOk.encode(@channel_max, [settings[:frame_max], @frame_max].min, @heartbeat_interval)
399
+ end # handle_tune(method)
400
+
401
+
402
+ # Handles connection.close. When broker detects a connection level exception, this method is called.
403
+ #
404
+ # @api plugin
405
+ # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.5.2.9)
406
+ def handle_close(method)
407
+ self.handle_connection_interruption
408
+
409
+ closed!
410
+ # TODO: use proper exception class, provide protocol class (we know method.class_id and method.method_id) as well!
411
+ error = RuntimeError.new(method.reply_text)
412
+ self.error(error)
413
+ end
414
+
415
+
416
+ # Handles Connection.Close-Ok.
417
+ #
418
+ # @api plugin
419
+ # @see http://bit.ly/htCzCX AMQP 0.9.1 protocol documentation (Section 1.4.2.10)
420
+ def handle_close_ok(method)
421
+ closed!
422
+ self.disconnection_successful
423
+ end # handle_close_ok(method)
424
+
425
+ # @api plugin
426
+ def handle_connection_interruption
427
+ @channels.each { |n, c| c.handle_connection_interruption }
428
+ end # handle_connection_interruption
429
+
430
+
262
431
 
263
432
  protected
264
433
 
434
+ # Returns next frame from buffer whenever possible
435
+ #
436
+ # @api private
437
+ def get_next_frame
438
+ return nil unless @chunk_buffer.size > 7 # otherwise, cannot read the length
439
+ # octet + short
440
+ offset = 3 # 1 + 2
441
+ # length
442
+ payload_length = @chunk_buffer[offset, 4].unpack('N')[0]
443
+ # 4 bytes for long payload length, 1 byte final octet
444
+ frame_length = offset + 4 + payload_length + 1
445
+ if frame_length <= @chunk_buffer.size
446
+ @chunk_buffer.slice!(0, frame_length)
447
+ else
448
+ nil
449
+ end
450
+ end # def get_next_frame
451
+
265
452
  # Utility methods
266
453
 
267
454
  # Determines, whether the received frameset is ready to be further processed