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