amq-client 0.7.0.alpha25 → 0.7.0.alpha26

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