bunny 0.4.4 → 0.5.1

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.
Files changed (41) hide show
  1. data/Rakefile +21 -3
  2. data/bunny.gemspec +34 -20
  3. data/examples/{simple.rb → simple_08.rb} +0 -0
  4. data/examples/simple_09.rb +30 -0
  5. data/examples/{simple_ack.rb → simple_ack_08.rb} +0 -0
  6. data/examples/simple_ack_09.rb +33 -0
  7. data/examples/{simple_consumer.rb → simple_consumer_08.rb} +0 -0
  8. data/examples/simple_consumer_09.rb +55 -0
  9. data/examples/{simple_fanout.rb → simple_fanout_08.rb} +0 -0
  10. data/examples/simple_fanout_09.rb +39 -0
  11. data/examples/{simple_headers.rb → simple_headers_08.rb} +0 -0
  12. data/examples/simple_headers_09.rb +40 -0
  13. data/examples/{simple_publisher.rb → simple_publisher_08.rb} +0 -0
  14. data/examples/simple_publisher_09.rb +27 -0
  15. data/examples/{simple_topic.rb → simple_topic_08.rb} +0 -0
  16. data/examples/simple_topic_09.rb +59 -0
  17. data/lib/bunny.rb +19 -14
  18. data/lib/bunny/channel08.rb +38 -0
  19. data/lib/bunny/channel09.rb +38 -0
  20. data/lib/bunny/client08.rb +167 -74
  21. data/lib/bunny/{client091.rb → client09.rb} +195 -92
  22. data/lib/bunny/{exchange091.rb → exchange09.rb} +12 -11
  23. data/lib/bunny/queue08.rb +1 -0
  24. data/lib/bunny/{queue091.rb → queue09.rb} +38 -28
  25. data/lib/qrack/client.rb +7 -0
  26. data/lib/qrack/protocol/{protocol.rb → protocol08.rb} +1 -4
  27. data/lib/qrack/protocol/protocol09.rb +133 -0
  28. data/lib/qrack/protocol/{spec091.rb → spec09.rb} +5 -5
  29. data/lib/qrack/qrack08.rb +2 -10
  30. data/lib/qrack/qrack09.rb +20 -0
  31. data/lib/qrack/transport/{buffer.rb → buffer08.rb} +0 -0
  32. data/lib/qrack/transport/buffer09.rb +276 -0
  33. data/lib/qrack/transport/{frame091.rb → frame09.rb} +8 -8
  34. data/spec/{bunny_spec.rb → spec_08/bunny_spec.rb} +4 -4
  35. data/spec/{exchange_spec.rb → spec_08/exchange_spec.rb} +3 -10
  36. data/spec/{queue_spec.rb → spec_08/queue_spec.rb} +1 -1
  37. data/spec/spec_09/bunny_spec.rb +40 -0
  38. data/spec/spec_09/exchange_spec.rb +131 -0
  39. data/spec/spec_09/queue_spec.rb +106 -0
  40. metadata +38 -22
  41. data/lib/qrack/qrack091.rb +0 -28
@@ -0,0 +1,38 @@
1
+ module Bunny
2
+ class Channel
3
+ attr_accessor :number, :active
4
+ attr_reader :client
5
+
6
+ def initialize(client, zero = false)
7
+ @client = client
8
+ zero ? @number = 0 : @number = client.channels.size
9
+ @active = false
10
+ client.channels[@number] ||= self
11
+ end
12
+
13
+ def open
14
+ client.channel = self
15
+ client.send_frame(Qrack::Protocol::Channel::Open.new)
16
+ raise Bunny::ProtocolError, "Cannot open channel #{number}" unless client.next_method.is_a?(Qrack::Protocol::Channel::OpenOk)
17
+
18
+ @active = true
19
+ :open_ok
20
+ end
21
+
22
+ def close
23
+ client.channel = self
24
+ client.send_frame(
25
+ Qrack::Protocol::Channel::Close.new(:reply_code => 200, :reply_text => 'bye', :method_id => 0, :class_id => 0)
26
+ )
27
+ raise Bunny::ProtocolError, "Error closing channel #{number}" unless client.next_method.is_a?(Qrack::Protocol::Channel::CloseOk)
28
+
29
+ @active = false
30
+ :close_ok
31
+ end
32
+
33
+ def open?
34
+ active
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ module Bunny
2
+ class Channel09
3
+ attr_accessor :number, :active
4
+ attr_reader :client
5
+
6
+ def initialize(client, zero = false)
7
+ @client = client
8
+ zero ? @number = 0 : @number = client.channels.size
9
+ @active = false
10
+ client.channels[@number] ||= self
11
+ end
12
+
13
+ def open
14
+ client.channel = self
15
+ client.send_frame(Qrack::Protocol09::Channel::Open.new)
16
+ raise Bunny::ProtocolError, "Cannot open channel #{number}" unless client.next_method.is_a?(Qrack::Protocol09::Channel::OpenOk)
17
+
18
+ @active = true
19
+ :open_ok
20
+ end
21
+
22
+ def close
23
+ client.channel = self
24
+ client.send_frame(
25
+ Qrack::Protocol09::Channel::Close.new(:reply_code => 200, :reply_text => 'bye', :method_id => 0, :class_id => 0)
26
+ )
27
+ raise Bunny::ProtocolError, "Error closing channel #{number}" unless client.next_method.is_a?(Qrack::Protocol09::Channel::CloseOk)
28
+
29
+ @active = false
30
+ :close_ok
31
+ end
32
+
33
+ def open?
34
+ active
35
+ end
36
+
37
+ end
38
+ end
@@ -9,11 +9,8 @@ The Client class provides the major Bunny API methods.
9
9
  =end
10
10
 
11
11
  class Client < Qrack::Client
12
- CONNECT_TIMEOUT = 1.0
13
- RETRY_DELAY = 10.0
14
-
15
- attr_reader :status, :host, :vhost, :port, :logging, :spec
16
- attr_accessor :channel, :logfile, :exchanges, :queues, :ticket
12
+
13
+ attr_accessor :ticket
17
14
 
18
15
  =begin rdoc
19
16
 
@@ -41,7 +38,7 @@ Sets up a Bunny::Client object ready for connection to a broker/server. _Client_
41
38
  =end
42
39
 
43
40
  def initialize(opts = {})
44
- @spec = opts[:spec] || '08'
41
+ @spec = '0-8'
45
42
  @host = opts[:host] || 'localhost'
46
43
  @port = opts[:port] || Qrack::Protocol::PORT
47
44
  @user = opts[:user] || 'guest'
@@ -51,8 +48,12 @@ Sets up a Bunny::Client object ready for connection to a broker/server. _Client_
51
48
  @logging = opts[:logging] || false
52
49
  @insist = opts[:insist]
53
50
  @status = :not_connected
51
+ @frame_max = opts[:frame_max] || 131072
52
+ @channel_max = opts[:channel_max] || 0
54
53
  @logger = nil
55
54
  create_logger if @logging
55
+ # Create channel 0
56
+ @channel = Bunny::Channel.new(self, true)
56
57
  end
57
58
 
58
59
  =begin rdoc
@@ -60,9 +61,8 @@ Sets up a Bunny::Client object ready for connection to a broker/server. _Client_
60
61
  === DESCRIPTION:
61
62
 
62
63
  Declares an exchange to the broker/server. If the exchange does not exist, a new one is created
63
- using the arguments passed in. If the exchange already exists, a reference to it is created, provided
64
- that the arguments passed in do not conflict with the existing attributes of the exchange. If an error
65
- occurs a _Bunny_::_ProtocolError_ is raised.
64
+ using the arguments passed in. If the exchange already exists, the existing object is returned.
65
+ If an error occurs a _Bunny_::_ProtocolError_ is raised.
66
66
 
67
67
  ==== OPTIONS:
68
68
 
@@ -83,7 +83,8 @@ Exchange
83
83
  =end
84
84
 
85
85
  def exchange(name, opts = {})
86
- exchanges[name] ||= Bunny::Exchange.new(self, name, opts)
86
+ return exchanges[name] if exchanges.has_key?(name)
87
+ Bunny::Exchange.new(self, name, opts)
87
88
  end
88
89
 
89
90
  =begin rdoc
@@ -141,7 +142,6 @@ Queue
141
142
  return queues[name] if queues.has_key?(name)
142
143
 
143
144
  queue = Bunny::Queue.new(self, name, opts)
144
- queues[queue.name] = queue
145
145
  end
146
146
 
147
147
  =begin rdoc
@@ -159,12 +159,13 @@ Returns hash of queues declared by Bunny.
159
159
  def send_frame(*args)
160
160
  args.each do |data|
161
161
  data.ticket = ticket if ticket and data.respond_to?(:ticket=)
162
- data = data.to_frame(channel) unless data.is_a?(Qrack::Transport::Frame)
163
- data.channel = channel
162
+ data = data.to_frame(channel.number) unless data.is_a?(Qrack::Transport::Frame)
163
+ data.channel = channel.number
164
164
 
165
165
  @logger.info("send") { data } if @logging
166
166
  write(data.to_s)
167
167
  end
168
+
168
169
  nil
169
170
  end
170
171
 
@@ -174,15 +175,13 @@ Returns hash of queues declared by Bunny.
174
175
  frame
175
176
  end
176
177
 
177
- def next_method
178
- next_payload
179
- end
180
-
181
178
  def next_payload
182
179
  frame = next_frame
183
- frame and frame.payload
180
+ frame.payload
184
181
  end
185
182
 
183
+ alias next_method next_payload
184
+
186
185
  =begin rdoc
187
186
 
188
187
  === DESCRIPTION:
@@ -197,17 +196,18 @@ _Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to <
197
196
  =end
198
197
 
199
198
  def close
200
- send_frame(
201
- Qrack::Protocol::Channel::Close.new(:reply_code => 200, :reply_text => 'bye', :method_id => 0, :class_id => 0)
202
- )
203
- raise Bunny::ProtocolError, "Error closing channel #{channel}" unless next_method.is_a?(Qrack::Protocol::Channel::CloseOk)
199
+ # Close all active channels
200
+ channels.each_value do |c|
201
+ c.close if c.open?
202
+ end
203
+
204
+ # Set client channel to zero
205
+ self.channel = channels[0]
204
206
 
205
- self.channel = 0
206
- send_frame(
207
- Qrack::Protocol::Connection::Close.new(:reply_code => 200, :reply_text => 'Goodbye', :class_id => 0, :method_id => 0)
208
- )
209
- raise Bunny::ProtocolError, "Error closing connection" unless next_method.is_a?(Qrack::Protocol::Connection::CloseOk)
207
+ # Close connection to AMQP server
208
+ close_connection
210
209
 
210
+ # Close TCP Socket
211
211
  close_socket
212
212
  end
213
213
 
@@ -239,56 +239,19 @@ _Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to <
239
239
  # Create/get socket
240
240
  socket
241
241
 
242
- @channel = 0
243
- write(Qrack::Protocol::HEADER)
244
- write([1, 1, Qrack::Protocol::VERSION_MAJOR, Qrack::Protocol::VERSION_MINOR].pack('C4'))
245
- raise Bunny::ProtocolError, 'Connection initiation failed' unless next_method.is_a?(Qrack::Protocol::Connection::Start)
242
+ # Initiate connection
243
+ init_connection
246
244
 
247
- send_frame(
248
- Qrack::Protocol::Connection::StartOk.new(
249
- {:platform => 'Ruby', :product => 'Bunny', :information => 'http://github.com/celldee/bunny', :version => VERSION},
250
- 'AMQPLAIN',
251
- {:LOGIN => @user, :PASSWORD => @pass},
252
- 'en_US'
253
- )
254
- )
255
-
256
- method = next_method
257
- raise Bunny::ProtocolError, "Connection failed - user: #{@user}, pass: #{@pass}" if method.nil?
258
-
259
- if method.is_a?(Qrack::Protocol::Connection::Tune)
260
- send_frame(
261
- Qrack::Protocol::Connection::TuneOk.new( :channel_max => 0, :frame_max => 131072, :heartbeat => 0)
262
- )
263
- end
264
-
265
- send_frame(
266
- Qrack::Protocol::Connection::Open.new(:virtual_host => @vhost, :capabilities => '', :insist => @insist)
267
- )
268
-
269
- case method = next_method
270
- when Qrack::Protocol::Connection::OpenOk
271
- break
272
- when Qrack::Protocol::Connection::Redirect
273
- raise Bunny::ConnectionError, "Cannot connect to the specified server - host: #{@host}, port: #{@port}" if @insist
274
-
275
- @host, @port = method.host.split(':')
276
- close_socket
277
- else
278
- raise Bunny::ProtocolError, 'Cannot open connection'
279
- end
245
+ # Open connection
246
+ break if open_connection == :ok
280
247
  end
281
248
 
282
- @channel = 1
283
- send_frame(Qrack::Protocol::Channel::Open.new)
284
- raise Bunny::ProtocolError, "Cannot open channel #{channel}" unless next_method.is_a?(Qrack::Protocol::Channel::OpenOk)
285
-
286
- send_frame(
287
- Qrack::Protocol::Access::Request.new(:realm => '/data', :read => true, :write => true, :active => true, :passive => true)
288
- )
289
- method = next_method
290
- raise Bunny::ProtocolError, 'Access denied' unless method.is_a?(Qrack::Protocol::Access::RequestOk)
291
- self.ticket = method.ticket
249
+ # Open a channel
250
+ self.channel = get_channel
251
+ channel.open
252
+
253
+ # Get access ticket
254
+ request_access
292
255
 
293
256
  # return status
294
257
  status
@@ -360,11 +323,141 @@ true, they are applied to the entire connection.
360
323
  # return confirmation
361
324
  :qos_ok
362
325
  end
326
+
327
+ =begin rdoc
328
+
329
+ === DESCRIPTION:
330
+ This method sets the channel to use standard transactions. The
331
+ client must use this method at least once on a channel before
332
+ using the Commit or Rollback methods.
333
+
334
+ =end
335
+
336
+ def tx_select
337
+ send_frame(Qrack::Protocol::Tx::Select.new())
338
+
339
+ raise Bunny::ProtocolError,
340
+ "Error initiating transactions for current channel" unless
341
+ next_method.is_a?(Qrack::Protocol::Tx::SelectOk)
342
+
343
+ # return confirmation
344
+ :select_ok
345
+ end
346
+
347
+ =begin rdoc
348
+
349
+ === DESCRIPTION:
350
+ This method commits all messages published and acknowledged in
351
+ the current transaction. A new transaction starts immediately
352
+ after a commit.
353
+
354
+ =end
355
+
356
+ def tx_commit
357
+ send_frame(Qrack::Protocol::Tx::Commit.new())
358
+
359
+ raise Bunny::ProtocolError,
360
+ "Error commiting transaction" unless
361
+ next_method.is_a?(Qrack::Protocol::Tx::CommitOk)
362
+
363
+ # return confirmation
364
+ :commit_ok
365
+ end
366
+
367
+ =begin rdoc
368
+
369
+ === DESCRIPTION:
370
+ This method abandons all messages published and acknowledged in
371
+ the current transaction. A new transaction starts immediately
372
+ after a rollback.
373
+
374
+ =end
375
+
376
+ def tx_rollback
377
+ send_frame(Qrack::Protocol::Tx::Rollback.new())
378
+
379
+ raise Bunny::ProtocolError,
380
+ "Error rolling back transaction" unless
381
+ next_method.is_a?(Qrack::Protocol::Tx::RollbackOk)
382
+
383
+ # return confirmation
384
+ :rollback_ok
385
+ end
363
386
 
364
387
  def logging=(bool)
365
388
  @logging = bool
366
389
  create_logger if @logging
367
390
  end
391
+
392
+ def channels
393
+ @channels ||= {}
394
+ end
395
+
396
+ def get_channel
397
+ channels.each_value do |c|
398
+ return c if (!c.open? and c.number != 0)
399
+ end
400
+ # If no channel to re-use instantiate new one
401
+ Bunny::Channel.new(self)
402
+ end
403
+
404
+ def init_connection
405
+ write(Qrack::Protocol::HEADER)
406
+ write([1, 1, Qrack::Protocol::VERSION_MAJOR, Qrack::Protocol::VERSION_MINOR].pack('C4'))
407
+ raise Bunny::ProtocolError, 'Connection initiation failed' unless next_method.is_a?(Qrack::Protocol::Connection::Start)
408
+ end
409
+
410
+ def open_connection
411
+ send_frame(
412
+ Qrack::Protocol::Connection::StartOk.new(
413
+ {:platform => 'Ruby', :product => 'Bunny', :information => 'http://github.com/celldee/bunny', :version => VERSION},
414
+ 'AMQPLAIN',
415
+ {:LOGIN => @user, :PASSWORD => @pass},
416
+ 'en_US'
417
+ )
418
+ )
419
+
420
+ method = next_method
421
+ raise Bunny::ProtocolError, "Connection failed - user: #{@user}, pass: #{@pass}" if method.nil?
422
+
423
+ if method.is_a?(Qrack::Protocol::Connection::Tune)
424
+ send_frame(
425
+ Qrack::Protocol::Connection::TuneOk.new( :channel_max => @channel_max, :frame_max => @frame_max, :heartbeat => 0)
426
+ )
427
+ end
428
+
429
+ send_frame(
430
+ Qrack::Protocol::Connection::Open.new(:virtual_host => @vhost, :capabilities => '', :insist => @insist)
431
+ )
432
+
433
+ case method = next_method
434
+ when Qrack::Protocol::Connection::OpenOk
435
+ return :ok
436
+ when Qrack::Protocol::Connection::Redirect
437
+ raise Bunny::ConnectionError, "Cannot connect to the specified server - host: #{@host}, port: #{@port}" if @insist
438
+
439
+ @host, @port = method.host.split(':')
440
+ close_socket
441
+ else
442
+ raise Bunny::ProtocolError, 'Cannot open connection'
443
+ end
444
+ end
445
+
446
+ def close_connection
447
+ send_frame(
448
+ Qrack::Protocol::Connection::Close.new(:reply_code => 200, :reply_text => 'Goodbye', :class_id => 0, :method_id => 0)
449
+ )
450
+ raise Bunny::ProtocolError, "Error closing connection" unless next_method.is_a?(Qrack::Protocol::Connection::CloseOk)
451
+ end
452
+
453
+ def request_access
454
+ send_frame(
455
+ Qrack::Protocol::Access::Request.new(:realm => '/data', :read => true, :write => true, :active => true, :passive => true)
456
+ )
457
+ method = next_method
458
+ raise Bunny::ProtocolError, 'Access denied' unless method.is_a?(Qrack::Protocol::Access::RequestOk)
459
+ self.ticket = method.ticket
460
+ end
368
461
 
369
462
  private
370
463
 
@@ -8,12 +8,7 @@ The Client class provides the major Bunny API methods.
8
8
 
9
9
  =end
10
10
 
11
- class Client < Qrack::Client
12
- CONNECT_TIMEOUT = 1.0
13
- RETRY_DELAY = 10.0
14
-
15
- attr_reader :status, :host, :vhost, :port, :logging, :spec
16
- attr_accessor :channel, :logfile, :exchanges, :queues, :ticket
11
+ class Client09 < Qrack::Client
17
12
 
18
13
  =begin rdoc
19
14
 
@@ -33,26 +28,25 @@ Sets up a Bunny::Client object ready for connection to a broker/server. _Client_
33
28
  * <tt>:logging => true or false (_default_)</tt> - If set to _true_, session information is sent
34
29
  to STDOUT if <tt>:logfile</tt> has not been specified. Otherwise, session information is written to
35
30
  <tt>:logfile</tt>.
36
- * <tt>:insist => true or false (_default_)</tt> - In a configuration with multiple load-sharing
37
- servers, the server may respond to a Connection::Open method with a Connection::Redirect. The insist
38
- option, if set to _true_, tells the server that the client is insisting on a connection to the
39
- specified server.
40
31
 
41
32
  =end
42
33
 
43
34
  def initialize(opts = {})
44
- @spec = opts[:spec] || '0-8'
35
+ @spec = '0-9-1'
45
36
  @host = opts[:host] || 'localhost'
46
- @port = opts[:port] || Qrack::Protocol::PORT
37
+ @port = opts[:port] || Qrack::Protocol09::PORT
47
38
  @user = opts[:user] || 'guest'
48
39
  @pass = opts[:pass] || 'guest'
49
40
  @vhost = opts[:vhost] || '/'
41
+ @frame_max = opts[:frame_max] || 131072
42
+ @channel_max = opts[:channel_max] || 5
50
43
  @logfile = opts[:logfile] || nil
51
44
  @logging = opts[:logging] || false
52
- @insist = opts[:insist]
53
45
  @status = :not_connected
54
46
  @logger = nil
55
47
  create_logger if @logging
48
+ # Create channel 0
49
+ @channel = Bunny::Channel09.new(self, true)
56
50
  end
57
51
 
58
52
  =begin rdoc
@@ -83,7 +77,8 @@ Exchange
83
77
  =end
84
78
 
85
79
  def exchange(name, opts = {})
86
- exchanges[name] ||= Bunny::Exchange.new(self, name, opts)
80
+ return exchanges[name] if exchanges.has_key?(name)
81
+ exchanges[name] ||= Bunny::Exchange09.new(self, name, opts)
87
82
  end
88
83
 
89
84
  =begin rdoc
@@ -140,8 +135,7 @@ Queue
140
135
 
141
136
  return queues[name] if queues.has_key?(name)
142
137
 
143
- queue = Bunny::Queue.new(self, name, opts)
144
- queues[queue.name] = queue
138
+ queue = Bunny::Queue09.new(self, name, opts)
145
139
  end
146
140
 
147
141
  =begin rdoc
@@ -158,9 +152,8 @@ Returns hash of queues declared by Bunny.
158
152
 
159
153
  def send_frame(*args)
160
154
  args.each do |data|
161
- data.ticket = ticket if ticket and data.respond_to?(:ticket=)
162
- data = data.to_frame(channel) unless data.is_a?(Qrack::Transport::Frame)
163
- data.channel = channel
155
+ data = data.to_frame(channel.number) unless data.is_a?(Qrack::Transport09::Frame)
156
+ data.channel = channel.number
164
157
 
165
158
  @logger.info("send") { data } if @logging
166
159
  write(data.to_s)
@@ -169,20 +162,18 @@ Returns hash of queues declared by Bunny.
169
162
  end
170
163
 
171
164
  def next_frame
172
- frame = Qrack::Transport::Frame.parse(buffer)
165
+ frame = Qrack::Transport09::Frame.parse(buffer)
173
166
  @logger.info("received") { frame } if @logging
174
167
  frame
175
168
  end
176
169
 
177
- def next_method
178
- next_payload
179
- end
180
-
181
170
  def next_payload
182
171
  frame = next_frame
183
- frame and frame.payload
172
+ frame.payload
184
173
  end
185
174
 
175
+ alias next_method next_payload
176
+
186
177
  =begin rdoc
187
178
 
188
179
  === DESCRIPTION:
@@ -197,17 +188,18 @@ _Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to <
197
188
  =end
198
189
 
199
190
  def close
200
- send_frame(
201
- Qrack::Protocol::Channel::Close.new(:reply_code => 200, :reply_text => 'bye', :method_id => 0, :class_id => 0)
202
- )
203
- raise Bunny::ProtocolError, "Error closing channel #{channel}" unless next_method.is_a?(Qrack::Protocol::Channel::CloseOk)
204
-
205
- self.channel = 0
206
- send_frame(
207
- Qrack::Protocol::Connection::Close.new(:reply_code => 200, :reply_text => 'Goodbye', :class_id => 0, :method_id => 0)
208
- )
209
- raise Bunny::ProtocolError, "Error closing connection" unless next_method.is_a?(Qrack::Protocol::Connection::CloseOk)
210
-
191
+ # Close all active channels
192
+ channels.each_value do |c|
193
+ c.close if c.open?
194
+ end
195
+
196
+ # Set client channel to zero
197
+ self.channel = channels[0]
198
+
199
+ # Close connection to AMQP server
200
+ close_connection
201
+
202
+ # Close TCP socket
211
203
  close_socket
212
204
  end
213
205
 
@@ -235,60 +227,18 @@ _Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to <
235
227
  =end
236
228
 
237
229
  def start_session
238
- loop do
239
- # Create/get socket
240
- socket
241
-
242
- @channel = 0
243
- write(Qrack::Protocol::HEADER)
244
- write([1, 1, Qrack::Protocol::VERSION_MINOR, Qrack::Protocol::VERSION_MAJOR].pack('C4'))
245
- raise Bunny::ProtocolError, 'Connection initiation failed' unless next_method.is_a?(Qrack::Protocol::Connection::Start)
246
-
247
- send_frame(
248
- Qrack::Protocol::Connection::StartOk.new(
249
- {:platform => 'Ruby', :product => 'Bunny', :information => 'http://github.com/celldee/bunny', :version => VERSION},
250
- 'AMQPLAIN',
251
- {:LOGIN => @user, :PASSWORD => @pass},
252
- 'en_US'
253
- )
254
- )
255
-
256
- method = next_method
257
- raise Bunny::ProtocolError, "Connection failed - user: #{@user}, pass: #{@pass}" if method.nil?
258
-
259
- if method.is_a?(Qrack::Protocol::Connection::Tune)
260
- send_frame(
261
- Qrack::Protocol::Connection::TuneOk.new( :channel_max => 0, :frame_max => 131072, :heartbeat => 0)
262
- )
263
- end
264
-
265
- send_frame(
266
- Qrack::Protocol::Connection::Open.new(:virtual_host => @vhost, :capabilities => '', :insist => @insist)
267
- )
268
-
269
- case method = next_method
270
- when Qrack::Protocol::Connection::OpenOk
271
- break
272
- when Qrack::Protocol::Connection::Redirect
273
- raise Bunny::ConnectionError, "Cannot connect to the specified server - host: #{@host}, port: #{@port}" if @insist
274
-
275
- @host, @port = method.host.split(':')
276
- close_socket
277
- else
278
- raise Bunny::ProtocolError, 'Cannot open connection'
279
- end
280
- end
281
-
282
- @channel = 1
283
- send_frame(Qrack::Protocol::Channel::Open.new)
284
- raise Bunny::ProtocolError, "Cannot open channel #{channel}" unless next_method.is_a?(Qrack::Protocol::Channel::OpenOk)
285
-
286
- send_frame(
287
- Qrack::Protocol::Access::Request.new(:realm => '/data', :read => true, :write => true, :active => true, :passive => true)
288
- )
289
- method = next_method
290
- raise Bunny::ProtocolError, 'Access denied' unless method.is_a?(Qrack::Protocol::Access::RequestOk)
291
- self.ticket = method.ticket
230
+ # Create/get socket
231
+ socket
232
+
233
+ # Initiate connection
234
+ init_connection
235
+
236
+ # Open connection
237
+ open_connection
238
+
239
+ # Open a channel
240
+ self.channel = get_channel
241
+ channel.open
292
242
 
293
243
  # return status
294
244
  status
@@ -314,20 +264,173 @@ the message, potentially then delivering it to an alternative subscriber.
314
264
  def recover(opts = {})
315
265
 
316
266
  send_frame(
317
- Qrack::Protocol::Basic::Recover.new({ :requeue => false }.merge(opts))
267
+ Qrack::Protocol09::Basic::Recover.new({ :requeue => false }.merge(opts))
318
268
  )
319
269
 
320
270
  end
321
271
 
272
+ =begin rdoc
273
+
274
+ === DESCRIPTION:
275
+
276
+ Requests a specific quality of service. The QoS can be specified for the current channel
277
+ or for all channels on the connection. The particular properties and semantics of a QoS
278
+ method always depend on the content class semantics. Though the QoS method could in principle
279
+ apply to both peers, it is currently meaningful only for the server.
280
+
281
+ ==== Options:
282
+
283
+ * <tt>:prefetch_size => size in no. of octets (default = 0)</tt> - The client can request that
284
+ messages be sent in advance so that when the client finishes processing a message, the following
285
+ message is already held locally, rather than needing to be sent down the channel. Prefetching gives
286
+ a performance improvement. This field specifies the prefetch window size in octets. The server
287
+ will send a message in advance if it is equal to or smaller in size than the available prefetch
288
+ size (and also falls into other prefetch limits). May be set to zero, meaning "no specific limit",
289
+ although other prefetch limits may still apply. The prefetch-size is ignored if the no-ack option
290
+ is set.
291
+ * <tt>:prefetch_count => no. messages (default = 1)</tt> - Specifies a prefetch window in terms
292
+ of whole messages. This field may be used in combination with the prefetch-size field; a message
293
+ will only be sent in advance if both prefetch windows (and those at the channel and connection level)
294
+ allow it. The prefetch-count is ignored if the no-ack option is set.
295
+ * <tt>:global => true or false (_default_)</tt> - By default the QoS settings apply to the current channel only. If set to
296
+ true, they are applied to the entire connection.
297
+
298
+ =end
299
+
300
+ def qos(opts = {})
301
+
302
+ send_frame(
303
+ Qrack::Protocol09::Basic::Qos.new({ :prefetch_size => 0, :prefetch_count => 1, :global => false }.merge(opts))
304
+ )
305
+
306
+ raise Bunny::ProtocolError,
307
+ "Error specifying Quality of Service" unless
308
+ next_method.is_a?(Qrack::Protocol09::Basic::QosOk)
309
+
310
+ # return confirmation
311
+ :qos_ok
312
+ end
313
+
314
+ =begin rdoc
315
+
316
+ === DESCRIPTION:
317
+ This method sets the channel to use standard transactions. The
318
+ client must use this method at least once on a channel before
319
+ using the Commit or Rollback methods.
320
+
321
+ =end
322
+
323
+ def tx_select
324
+ send_frame(Qrack::Protocol09::Tx::Select.new())
325
+
326
+ raise Bunny::ProtocolError,
327
+ "Error initiating transactions for current channel" unless
328
+ next_method.is_a?(Qrack::Protocol09::Tx::SelectOk)
329
+
330
+ # return confirmation
331
+ :select_ok
332
+ end
333
+
334
+ =begin rdoc
335
+
336
+ === DESCRIPTION:
337
+ This method commits all messages published and acknowledged in
338
+ the current transaction. A new transaction starts immediately
339
+ after a commit.
340
+
341
+ =end
342
+
343
+ def tx_commit
344
+ send_frame(Qrack::Protocol09::Tx::Commit.new())
345
+
346
+ raise Bunny::ProtocolError,
347
+ "Error commiting transaction" unless
348
+ next_method.is_a?(Qrack::Protocol09::Tx::CommitOk)
349
+
350
+ # return confirmation
351
+ :commit_ok
352
+ end
353
+
354
+ =begin rdoc
355
+
356
+ === DESCRIPTION:
357
+ This method abandons all messages published and acknowledged in
358
+ the current transaction. A new transaction starts immediately
359
+ after a rollback.
360
+
361
+ =end
362
+
363
+ def tx_rollback
364
+ send_frame(Qrack::Protocol09::Tx::Rollback.new())
365
+
366
+ raise Bunny::ProtocolError,
367
+ "Error rolling back transaction" unless
368
+ next_method.is_a?(Qrack::Protocol09::Tx::RollbackOk)
369
+
370
+ # return confirmation
371
+ :rollback_ok
372
+ end
373
+
322
374
  def logging=(bool)
323
375
  @logging = bool
324
376
  create_logger if @logging
325
377
  end
378
+
379
+ def channels
380
+ @channels ||= {}
381
+ end
382
+
383
+ def get_channel
384
+ channels.each_value do |c|
385
+ return c if (!c.open? and c.number != 0)
386
+ end
387
+ # If no channel to re-use instantiate new one
388
+ Bunny::Channel09.new(self)
389
+ end
390
+
391
+ def init_connection
392
+ write(Qrack::Protocol09::HEADER)
393
+ write([0, Qrack::Protocol09::VERSION_MAJOR, Qrack::Protocol09::VERSION_MINOR, Qrack::Protocol09::REVISION].pack('C4'))
394
+ raise Bunny::ProtocolError, 'Connection initiation failed' unless next_method.is_a?(Qrack::Protocol09::Connection::Start)
395
+ end
396
+
397
+ def open_connection
398
+ send_frame(
399
+ Qrack::Protocol09::Connection::StartOk.new(
400
+ :client_properties => {:platform => 'Ruby', :product => 'Bunny', :information => 'http://github.com/celldee/bunny', :version => VERSION},
401
+ :mechanism => 'PLAIN',
402
+ :response => "\0" + @user + "\0" + @pass,
403
+ :locale => 'en_US'
404
+ )
405
+ )
406
+
407
+ method = next_method
408
+ raise Bunny::ProtocolError, "Connection failed - user: #{@user}, pass: #{@pass}" if method.nil?
409
+
410
+ if method.is_a?(Qrack::Protocol09::Connection::Tune)
411
+ send_frame(
412
+ Qrack::Protocol09::Connection::TuneOk.new( :channel_max => @channel_max, :frame_max => @frame_max, :heartbeat => 0)
413
+ )
414
+ end
415
+
416
+ send_frame(
417
+ Qrack::Protocol09::Connection::Open.new(:virtual_host => @vhost, :reserved_1 => 0, :reserved_2 => false)
418
+ )
419
+
420
+ raise Bunny::ProtocolError, 'Cannot open connection' unless next_method.is_a?(Qrack::Protocol09::Connection::OpenOk)
421
+ end
422
+
423
+ def close_connection
424
+ send_frame(
425
+ Qrack::Protocol09::Connection::Close.new(:reply_code => 200, :reply_text => 'Goodbye', :class_id => 0, :method_id => 0)
426
+ )
427
+ raise Bunny::ProtocolError, "Error closing connection" unless next_method.is_a?(Qrack::Protocol09::Connection::CloseOk)
428
+ end
326
429
 
327
430
  private
328
431
 
329
432
  def buffer
330
- @buffer ||= Qrack::Transport::Buffer.new(self)
433
+ @buffer ||= Qrack::Transport09::Buffer.new(self)
331
434
  end
332
435
 
333
436
  def send_command(cmd, *args)