bunny 0.8.0 → 0.9.0.pre1
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/.gitignore +7 -1
- data/.travis.yml +14 -4
- data/ChangeLog.md +72 -0
- data/Gemfile +17 -11
- data/README.md +82 -0
- data/bunny.gemspec +6 -13
- data/examples/connection/heartbeat.rb +17 -0
- data/lib/bunny.rb +40 -56
- data/lib/bunny/channel.rb +615 -19
- data/lib/bunny/channel_id_allocator.rb +59 -0
- data/lib/bunny/compatibility.rb +24 -0
- data/lib/bunny/concurrent/condition.rb +63 -0
- data/lib/bunny/consumer.rb +42 -26
- data/lib/bunny/consumer_tag_generator.rb +22 -0
- data/lib/bunny/consumer_work_pool.rb +67 -0
- data/lib/bunny/exceptions.rb +128 -0
- data/lib/bunny/exchange.rb +131 -136
- data/lib/bunny/framing.rb +53 -0
- data/lib/bunny/heartbeat_sender.rb +59 -0
- data/lib/bunny/main_loop.rb +70 -0
- data/lib/bunny/message_metadata.rb +126 -0
- data/lib/bunny/queue.rb +102 -275
- data/lib/bunny/session.rb +478 -0
- data/lib/bunny/socket.rb +44 -0
- data/lib/bunny/system_timer.rb +9 -9
- data/lib/bunny/transport.rb +179 -0
- data/lib/bunny/version.rb +1 -1
- data/spec/compatibility/queue_declare_spec.rb +40 -0
- data/spec/higher_level_api/integration/basic_ack_spec.rb +54 -0
- data/spec/higher_level_api/integration/basic_consume_spec.rb +51 -0
- data/spec/higher_level_api/integration/basic_get_spec.rb +47 -0
- data/spec/higher_level_api/integration/basic_nack_spec.rb +39 -0
- data/spec/higher_level_api/integration/basic_publish_spec.rb +105 -0
- data/spec/higher_level_api/integration/basic_qos_spec.rb +32 -0
- data/spec/higher_level_api/integration/basic_recover_spec.rb +18 -0
- data/spec/higher_level_api/integration/basic_reject_spec.rb +53 -0
- data/spec/higher_level_api/integration/basic_return_spec.rb +33 -0
- data/spec/higher_level_api/integration/channel_close_spec.rb +29 -0
- data/spec/higher_level_api/integration/channel_flow_spec.rb +24 -0
- data/spec/higher_level_api/integration/channel_open_spec.rb +57 -0
- data/spec/higher_level_api/integration/channel_open_stress_spec.rb +22 -0
- data/spec/higher_level_api/integration/confirm_select_spec.rb +19 -0
- data/spec/higher_level_api/integration/connection_spec.rb +340 -0
- data/spec/higher_level_api/integration/exchange_bind_spec.rb +31 -0
- data/spec/higher_level_api/integration/exchange_declare_spec.rb +183 -0
- data/spec/higher_level_api/integration/exchange_delete_spec.rb +37 -0
- data/spec/higher_level_api/integration/exchange_unbind_spec.rb +40 -0
- data/spec/higher_level_api/integration/queue_bind_spec.rb +109 -0
- data/spec/higher_level_api/integration/queue_declare_spec.rb +129 -0
- data/spec/higher_level_api/integration/queue_delete_spec.rb +38 -0
- data/spec/higher_level_api/integration/queue_purge_spec.rb +30 -0
- data/spec/higher_level_api/integration/queue_unbind_spec.rb +33 -0
- data/spec/higher_level_api/integration/tx_commit_spec.rb +21 -0
- data/spec/higher_level_api/integration/tx_rollback_spec.rb +21 -0
- data/spec/lower_level_api/integration/basic_cancel_spec.rb +57 -0
- data/spec/lower_level_api/integration/basic_consume_spec.rb +100 -0
- data/spec/spec_helper.rb +64 -0
- data/spec/unit/bunny_spec.rb +15 -0
- data/spec/unit/concurrent/condition_spec.rb +66 -0
- metadata +135 -93
- data/CHANGELOG +0 -21
- data/README.textile +0 -76
- data/Rakefile +0 -14
- data/examples/simple.rb +0 -32
- data/examples/simple_ack.rb +0 -35
- data/examples/simple_consumer.rb +0 -55
- data/examples/simple_fanout.rb +0 -41
- data/examples/simple_headers.rb +0 -42
- data/examples/simple_publisher.rb +0 -29
- data/examples/simple_topic.rb +0 -61
- data/ext/amqp-0.9.1.json +0 -389
- data/ext/config.yml +0 -4
- data/ext/qparser.rb +0 -426
- data/lib/bunny/client.rb +0 -370
- data/lib/bunny/subscription.rb +0 -92
- data/lib/qrack/amq-client-url.rb +0 -165
- data/lib/qrack/channel.rb +0 -20
- data/lib/qrack/client.rb +0 -247
- data/lib/qrack/errors.rb +0 -5
- data/lib/qrack/protocol/protocol.rb +0 -135
- data/lib/qrack/protocol/spec.rb +0 -525
- data/lib/qrack/qrack.rb +0 -20
- data/lib/qrack/queue.rb +0 -40
- data/lib/qrack/subscription.rb +0 -152
- data/lib/qrack/transport/buffer.rb +0 -305
- data/lib/qrack/transport/frame.rb +0 -102
- data/spec/spec_09/amqp_url_spec.rb +0 -19
- data/spec/spec_09/bunny_spec.rb +0 -76
- data/spec/spec_09/connection_spec.rb +0 -34
- data/spec/spec_09/exchange_spec.rb +0 -173
- data/spec/spec_09/queue_spec.rb +0 -240
@@ -0,0 +1,478 @@
|
|
1
|
+
require "socket"
|
2
|
+
require "thread"
|
3
|
+
|
4
|
+
require "bunny/transport"
|
5
|
+
require "bunny/channel_id_allocator"
|
6
|
+
require "bunny/heartbeat_sender"
|
7
|
+
require "bunny/main_loop"
|
8
|
+
|
9
|
+
require "bunny/concurrent/condition"
|
10
|
+
|
11
|
+
require "amq/protocol/client"
|
12
|
+
require "amq/settings"
|
13
|
+
|
14
|
+
module Bunny
|
15
|
+
class Session
|
16
|
+
|
17
|
+
DEFAULT_HOST = "127.0.0.1"
|
18
|
+
DEFAULT_VHOST = "/"
|
19
|
+
DEFAULT_USER = "guest"
|
20
|
+
DEFAULT_PASSWORD = "guest"
|
21
|
+
# 0 means "no heartbeat". This is the same default RabbitMQ Java client and amqp gem
|
22
|
+
# use.
|
23
|
+
DEFAULT_HEARTBEAT = 0
|
24
|
+
# 128K
|
25
|
+
DEFAULT_FRAME_MAX = 131072
|
26
|
+
|
27
|
+
# backwards compatibility
|
28
|
+
CONNECT_TIMEOUT = Transport::DEFAULT_CONNECTION_TIMEOUT
|
29
|
+
|
30
|
+
|
31
|
+
DEFAULT_CLIENT_PROPERTIES = {
|
32
|
+
# once we support AMQP 0.9.1 extensions, this needs to be updated. MK.
|
33
|
+
:capabilities => {},
|
34
|
+
:product => "Bunny",
|
35
|
+
:platform => ::RUBY_DESCRIPTION,
|
36
|
+
:version => Bunny::VERSION,
|
37
|
+
:information => "http://github.com/ruby-amqp/bunny"
|
38
|
+
}
|
39
|
+
|
40
|
+
DEFAULT_LOCALE = "en_GB"
|
41
|
+
|
42
|
+
|
43
|
+
#
|
44
|
+
# API
|
45
|
+
#
|
46
|
+
|
47
|
+
attr_reader :status, :host, :port, :heartbeat, :user, :pass, :vhost, :frame_max, :default_channel
|
48
|
+
attr_reader :server_capabilities, :server_properties, :server_authentication_mechanisms, :server_locales
|
49
|
+
attr_reader :default_channel
|
50
|
+
attr_reader :channel_id_allocator
|
51
|
+
|
52
|
+
def initialize(connection_string_or_opts = Hash.new, optz = Hash.new)
|
53
|
+
opts = case connection_string_or_opts
|
54
|
+
when String then
|
55
|
+
AMQ::Settings.parse_amqp_url(connection_string_or_opts)
|
56
|
+
when Hash then
|
57
|
+
connection_string_or_opts
|
58
|
+
end.merge(optz)
|
59
|
+
|
60
|
+
@opts = opts
|
61
|
+
@host = self.hostname_from(opts)
|
62
|
+
@port = self.port_from(opts)
|
63
|
+
@user = self.username_from(opts)
|
64
|
+
@pass = self.password_from(opts)
|
65
|
+
@vhost = self.vhost_from(opts)
|
66
|
+
@logfile = opts[:logfile]
|
67
|
+
@logging = opts[:logging] || false
|
68
|
+
|
69
|
+
@status = :not_connected
|
70
|
+
@frame_max = opts[:frame_max] || DEFAULT_FRAME_MAX
|
71
|
+
# currently ignored
|
72
|
+
@channel_max = opts[:channel_max] || 0
|
73
|
+
@heartbeat = self.heartbeat_from(opts)
|
74
|
+
|
75
|
+
@client_properties = opts[:properties] || DEFAULT_CLIENT_PROPERTIES
|
76
|
+
@mechanism = "PLAIN"
|
77
|
+
@locale = @opts.fetch(:locale, DEFAULT_LOCALE)
|
78
|
+
|
79
|
+
@channel_id_allocator = ChannelIdAllocator.new
|
80
|
+
@channel_mutex = Mutex.new
|
81
|
+
@channels = Hash.new
|
82
|
+
|
83
|
+
# Create channel 0
|
84
|
+
@channel0 = Bunny::Channel.new(self, 0)
|
85
|
+
|
86
|
+
@continuations = ::Queue.new
|
87
|
+
end
|
88
|
+
|
89
|
+
def hostname; self.host; end
|
90
|
+
def username; self.user; end
|
91
|
+
def password; self.pass; end
|
92
|
+
def virtual_host; self.vhost; end
|
93
|
+
|
94
|
+
def uses_tls?
|
95
|
+
@transport.uses_tls?
|
96
|
+
end
|
97
|
+
alias tls? uses_tls?
|
98
|
+
|
99
|
+
def uses_ssl?
|
100
|
+
@transport.uses_ssl?
|
101
|
+
end
|
102
|
+
alias ssl? uses_ssl?
|
103
|
+
|
104
|
+
def channel0
|
105
|
+
@channel0
|
106
|
+
end
|
107
|
+
|
108
|
+
def channel
|
109
|
+
@default_channel
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
def start
|
114
|
+
@status = :connecting
|
115
|
+
|
116
|
+
self.initialize_transport
|
117
|
+
|
118
|
+
self.init_connection
|
119
|
+
self.open_connection
|
120
|
+
|
121
|
+
self.start_main_loop
|
122
|
+
|
123
|
+
@default_channel = self.create_channel
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
def create_channel(n = nil)
|
128
|
+
if n && (ch = @channels[n])
|
129
|
+
ch
|
130
|
+
else
|
131
|
+
ch = Bunny::Channel.new(self, n)
|
132
|
+
ch.open
|
133
|
+
ch
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def close
|
138
|
+
if @transport.open?
|
139
|
+
close_all_channels
|
140
|
+
|
141
|
+
Bunny::Timer.timeout(@disconnect_timeout, ClientTimeout) do
|
142
|
+
self.close_connection(false)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
alias stop close
|
147
|
+
|
148
|
+
def with_channel(n = nil)
|
149
|
+
ch = create_channel(n)
|
150
|
+
yield ch
|
151
|
+
ch.close
|
152
|
+
|
153
|
+
self
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
def connecting?
|
158
|
+
status == :connecting
|
159
|
+
end
|
160
|
+
|
161
|
+
def closed?
|
162
|
+
status == :closed
|
163
|
+
end
|
164
|
+
|
165
|
+
def open?
|
166
|
+
status == :open || status == :connected
|
167
|
+
end
|
168
|
+
alias connected? open?
|
169
|
+
|
170
|
+
def prefetch(prefetch_count)
|
171
|
+
self.basic_qos(prefetch_count, true)
|
172
|
+
end
|
173
|
+
|
174
|
+
#
|
175
|
+
# Implementation
|
176
|
+
#
|
177
|
+
|
178
|
+
|
179
|
+
def open_channel(ch)
|
180
|
+
n = ch.number
|
181
|
+
self.register_channel(ch)
|
182
|
+
|
183
|
+
@transport.send_frame(AMQ::Protocol::Channel::Open.encode(n, AMQ::Protocol::EMPTY_STRING))
|
184
|
+
@last_channel_open_ok = @continuations.pop
|
185
|
+
raise_if_continuation_resulted_in_a_connection_error!
|
186
|
+
|
187
|
+
@last_channel_open_ok
|
188
|
+
end
|
189
|
+
|
190
|
+
def close_channel(ch)
|
191
|
+
n = ch.number
|
192
|
+
|
193
|
+
@transport.send_frame(AMQ::Protocol::Channel::Close.encode(n, 200, "Goodbye", 0, 0))
|
194
|
+
@last_channel_close_ok = @continuations.pop
|
195
|
+
raise_if_continuation_resulted_in_a_connection_error!
|
196
|
+
|
197
|
+
self.unregister_channel(ch)
|
198
|
+
@last_channel_close_ok
|
199
|
+
end
|
200
|
+
|
201
|
+
def close_all_channels
|
202
|
+
@channels.reject {|n, ch| n == 0 || !ch.open? }.each do |_, ch|
|
203
|
+
Bunny::Timer.timeout(@disconnect_timeout, ClientTimeout) { ch.close }
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def close_connection(sync = true)
|
208
|
+
@transport.send_frame(AMQ::Protocol::Connection::Close.encode(200, "Goodbye", 0, 0))
|
209
|
+
|
210
|
+
if @heartbeat_sender
|
211
|
+
@heartbeat_sender.stop
|
212
|
+
end
|
213
|
+
@status = :not_connected
|
214
|
+
|
215
|
+
if sync
|
216
|
+
@last_connection_close_ok = @continuations.pop
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def handle_frame(ch_number, method)
|
221
|
+
# puts "Session#handle_frame on #{ch_number}: #{method.inspect}"
|
222
|
+
case method
|
223
|
+
when AMQ::Protocol::Channel::OpenOk then
|
224
|
+
@continuations.push(method)
|
225
|
+
when AMQ::Protocol::Channel::CloseOk then
|
226
|
+
@continuations.push(method)
|
227
|
+
when AMQ::Protocol::Connection::Close then
|
228
|
+
@last_connection_error = instantiate_connection_level_exception(method)
|
229
|
+
@contunuations.push(method)
|
230
|
+
when AMQ::Protocol::Connection::CloseOk then
|
231
|
+
@last_connection_close_ok = method
|
232
|
+
begin
|
233
|
+
@continuations.clear
|
234
|
+
|
235
|
+
@event_loop.stop
|
236
|
+
@event_loop = nil
|
237
|
+
|
238
|
+
@transport.close
|
239
|
+
rescue Exception => e
|
240
|
+
puts e.class.name
|
241
|
+
puts e.message
|
242
|
+
puts e.backtrace
|
243
|
+
ensure
|
244
|
+
@active_continuation.notify_all if @active_continuation
|
245
|
+
@active_continuation = false
|
246
|
+
end
|
247
|
+
when AMQ::Protocol::Channel::Close then
|
248
|
+
begin
|
249
|
+
ch = @channels[ch_number]
|
250
|
+
ch.handle_method(method)
|
251
|
+
ensure
|
252
|
+
self.unregister_channel(ch)
|
253
|
+
end
|
254
|
+
when AMQ::Protocol::Basic::GetEmpty then
|
255
|
+
@channels[ch_number].handle_basic_get_empty(method)
|
256
|
+
else
|
257
|
+
@channels[ch_number].handle_method(method)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def raise_if_continuation_resulted_in_a_connection_error!
|
262
|
+
raise @last_connection_error if @last_connection_error
|
263
|
+
end
|
264
|
+
|
265
|
+
def handle_frameset(ch_number, frames)
|
266
|
+
method = frames.first
|
267
|
+
|
268
|
+
case method
|
269
|
+
when AMQ::Protocol::Basic::GetOk then
|
270
|
+
@channels[ch_number].handle_basic_get_ok(*frames)
|
271
|
+
when AMQ::Protocol::Basic::GetEmpty then
|
272
|
+
@channels[ch_number].handle_basic_get_empty(*frames)
|
273
|
+
when AMQ::Protocol::Basic::Return then
|
274
|
+
@channels[ch_number].handle_basic_return(*frames)
|
275
|
+
else
|
276
|
+
@channels[ch_number].handle_frameset(*frames)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def send_raw(*args)
|
281
|
+
@transport.write(*args)
|
282
|
+
end
|
283
|
+
|
284
|
+
def instantiate_connection_level_exception(frame)
|
285
|
+
case frame
|
286
|
+
when AMQ::Protocol::Connection::Close then
|
287
|
+
klass = case frame.reply_code
|
288
|
+
when 504 then
|
289
|
+
ChannelError
|
290
|
+
end
|
291
|
+
|
292
|
+
klass.new("Connection-level error: #{frame.reply_text}", self, frame)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def hostname_from(options)
|
297
|
+
options[:host] || options[:hostname] || DEFAULT_HOST
|
298
|
+
end
|
299
|
+
|
300
|
+
def port_from(options)
|
301
|
+
fallback = if options[:tls] || options[:ssl]
|
302
|
+
AMQ::Protocol::TLS_PORT
|
303
|
+
else
|
304
|
+
AMQ::Protocol::DEFAULT_PORT
|
305
|
+
end
|
306
|
+
|
307
|
+
options.fetch(:port, fallback)
|
308
|
+
end
|
309
|
+
|
310
|
+
def vhost_from(options)
|
311
|
+
options[:virtual_host] || options[:vhost] || DEFAULT_VHOST
|
312
|
+
end
|
313
|
+
|
314
|
+
def username_from(options)
|
315
|
+
options[:username] || options[:user] || DEFAULT_USER
|
316
|
+
end
|
317
|
+
|
318
|
+
def password_from(options)
|
319
|
+
options[:password] || options[:pass] || options [:pwd] || DEFAULT_PASSWORD
|
320
|
+
end
|
321
|
+
|
322
|
+
def heartbeat_from(options)
|
323
|
+
options[:heartbeat] || options[:heartbeat_interval] || options[:requested_heartbeat] || DEFAULT_HEARTBEAT
|
324
|
+
end
|
325
|
+
|
326
|
+
def next_channel_id
|
327
|
+
@channel_id_allocator.next_channel_id
|
328
|
+
end
|
329
|
+
|
330
|
+
def release_channel_id(i)
|
331
|
+
@channel_id_allocator.release_channel_id(i)
|
332
|
+
end
|
333
|
+
|
334
|
+
def register_channel(ch)
|
335
|
+
@channel_mutex.synchronize do
|
336
|
+
@channels[ch.number] = ch
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def unregister_channel(ch)
|
341
|
+
@channel_mutex.synchronize do
|
342
|
+
n = ch.number
|
343
|
+
|
344
|
+
self.release_channel_id(n)
|
345
|
+
@channels.delete(ch.number)
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def start_main_loop
|
350
|
+
@event_loop = MainLoop.new(@transport, self)
|
351
|
+
@event_loop.start
|
352
|
+
end
|
353
|
+
|
354
|
+
def signal_activity!
|
355
|
+
@heartbeat_sender.signal_activity! if @heartbeat_sender
|
356
|
+
end
|
357
|
+
|
358
|
+
|
359
|
+
# Sends frame to the peer, checking that connection is open.
|
360
|
+
# Exposed primarily for Bunny::Channel
|
361
|
+
#
|
362
|
+
# @raise [ConnectionClosedError]
|
363
|
+
# @private
|
364
|
+
def send_frame(frame)
|
365
|
+
if closed?
|
366
|
+
raise ConnectionClosedError.new(frame)
|
367
|
+
else
|
368
|
+
@transport.send_raw(frame.encode)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
# Sends multiple frames, one by one. For thread safety this method takes a channel
|
373
|
+
# object and synchronizes on it.
|
374
|
+
#
|
375
|
+
# @api public
|
376
|
+
def send_frameset(frames, channel)
|
377
|
+
# some developers end up sharing channels between threads and when multiple
|
378
|
+
# threads publish on the same channel aggressively, at some point frames will be
|
379
|
+
# delivered out of order and broker will raise 505 UNEXPECTED_FRAME exception.
|
380
|
+
# If we synchronize on the channel, however, this is both thread safe and pretty fine-grained
|
381
|
+
# locking. Note that "single frame" methods do not need this kind of synchronization. MK.
|
382
|
+
channel.synchronize do
|
383
|
+
frames.each { |frame| @transport.send_frame(frame) }
|
384
|
+
@transport.flush
|
385
|
+
end
|
386
|
+
end # send_frameset(frames)
|
387
|
+
|
388
|
+
protected
|
389
|
+
|
390
|
+
def socket_open?
|
391
|
+
!@socket.nil? && !@socket.closed?
|
392
|
+
end
|
393
|
+
|
394
|
+
def init_connection
|
395
|
+
self.send_preamble
|
396
|
+
|
397
|
+
connection_start = @transport.read_next_frame.decode_payload
|
398
|
+
|
399
|
+
@server_properties = connection_start.server_properties
|
400
|
+
@server_capabilities = @server_properties["capabilities"]
|
401
|
+
|
402
|
+
@server_authentication_mechanisms = (connection_start.mechanisms || "").split(" ")
|
403
|
+
@server_locales = Array(connection_start.locales)
|
404
|
+
|
405
|
+
@status = :connected
|
406
|
+
end
|
407
|
+
|
408
|
+
def open_connection
|
409
|
+
@transport.send_frame(AMQ::Protocol::Connection::StartOk.encode(@client_properties, @mechanism, self.encode_credentials(username, password), @locale))
|
410
|
+
|
411
|
+
frame = begin
|
412
|
+
@transport.read_next_frame
|
413
|
+
# frame timeout means the broker has closed the TCP connection, which it
|
414
|
+
# does per 0.9.1 spec.
|
415
|
+
rescue Errno::ECONNRESET, ClientTimeout, AMQ::Protocol::EmptyResponseError, EOFError => e
|
416
|
+
nil
|
417
|
+
end
|
418
|
+
if frame.nil?
|
419
|
+
@state = :closed
|
420
|
+
raise Bunny::PossibleAuthenticationFailureError.new(self.user, self.vhost, self.password.size)
|
421
|
+
end
|
422
|
+
|
423
|
+
connection_tune = frame.decode_payload
|
424
|
+
@frame_max = connection_tune.frame_max.freeze
|
425
|
+
@heartbeat ||= connection_tune.heartbeat
|
426
|
+
|
427
|
+
@transport.send_frame(AMQ::Protocol::Connection::TuneOk.encode(@channel_max, @frame_max, @heartbeat))
|
428
|
+
@transport.send_frame(AMQ::Protocol::Connection::Open.encode(self.vhost))
|
429
|
+
|
430
|
+
frame2 = begin
|
431
|
+
@transport.read_next_frame
|
432
|
+
# frame timeout means the broker has closed the TCP connection, which it
|
433
|
+
# does per 0.9.1 spec.
|
434
|
+
rescue Errno::ECONNRESET, ClientTimeout, AMQ::Protocol::EmptyResponseError, EOFError => e
|
435
|
+
nil
|
436
|
+
end
|
437
|
+
if frame2.nil?
|
438
|
+
@state = :closed
|
439
|
+
raise Bunny::PossibleAuthenticationFailureError.new(self.user, self.vhost, self.password.size)
|
440
|
+
end
|
441
|
+
connection_open_ok = frame2.decode_payload
|
442
|
+
|
443
|
+
@status = :open
|
444
|
+
if @heartbeat && @heartbeat > 0
|
445
|
+
initialize_heartbeat_sender
|
446
|
+
end
|
447
|
+
|
448
|
+
raise "could not open connection: server did not respond with connection.open-ok" unless connection_open_ok.is_a?(AMQ::Protocol::Connection::OpenOk)
|
449
|
+
end
|
450
|
+
|
451
|
+
def initialize_heartbeat_sender
|
452
|
+
@heartbeat_sender = HeartbeatSender.new(@transport)
|
453
|
+
@heartbeat_sender.start(@heartbeat)
|
454
|
+
end
|
455
|
+
|
456
|
+
|
457
|
+
def initialize_transport
|
458
|
+
@transport = Transport.new(@host, @port, @opts)
|
459
|
+
end
|
460
|
+
|
461
|
+
# Sends AMQ protocol header (also known as preamble).
|
462
|
+
def send_preamble
|
463
|
+
@transport.send_raw(AMQ::Protocol::PREAMBLE)
|
464
|
+
end
|
465
|
+
|
466
|
+
|
467
|
+
|
468
|
+
|
469
|
+
# @api plugin
|
470
|
+
# @see http://tools.ietf.org/rfc/rfc2595.txt RFC 2595
|
471
|
+
def encode_credentials(username, password)
|
472
|
+
"\0#{username}\0#{password}"
|
473
|
+
end # encode_credentials(username, password)
|
474
|
+
end # Session
|
475
|
+
|
476
|
+
# backwards compatibility
|
477
|
+
Client = Session
|
478
|
+
end
|