fotonauts-bunny 0.4.0
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/LICENSE +20 -0
- data/README +52 -0
- data/Rakefile +6 -0
- data/bunny.gemspec +38 -0
- data/examples/simple.rb +30 -0
- data/examples/simple_ack.rb +33 -0
- data/examples/simple_consumer.rb +55 -0
- data/examples/simple_fanout.rb +39 -0
- data/examples/simple_publisher.rb +27 -0
- data/examples/simple_topic.rb +59 -0
- data/lib/bunny/client.rb +324 -0
- data/lib/bunny/exchange.rb +158 -0
- data/lib/bunny/queue.rb +410 -0
- data/lib/bunny.rb +37 -0
- data/lib/qrack/client.rb +5 -0
- data/lib/qrack/protocol/protocol.rb +135 -0
- data/lib/qrack/protocol/spec.rb +822 -0
- data/lib/qrack/qrack.rb +28 -0
- data/lib/qrack/transport/buffer.rb +267 -0
- data/lib/qrack/transport/frame.rb +100 -0
- data/spec/bunny_spec.rb +36 -0
- data/spec/exchange_spec.rb +117 -0
- data/spec/queue_spec.rb +90 -0
- metadata +76 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Chris Duncan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
= Bunny: A synchronous Ruby AMQP client
|
2
|
+
|
3
|
+
*GitHub* *repo*: http://github.com/celldee/bunny
|
4
|
+
*Rubyforge*: http://rubyforge.org/projects/bunny-amqp
|
5
|
+
*Twitter*: http://twitter.com/bunny_amqp
|
6
|
+
*Google* *Group*: http://groups.google.com/group/bunny-amqp
|
7
|
+
|
8
|
+
=== DESCRIPTION:
|
9
|
+
|
10
|
+
Bunny is an AMQP[http://www.amqp.org] (Advanced Message Queuing Protocol) client, written in Ruby, that is intended to allow you to interact with AMQP-compliant message brokers/servers such as RabbitMQ[http://www.rabbitmq.com] in a synchronous fashion.
|
11
|
+
|
12
|
+
It is based on a great deal of useful code from amqp[http://github.com/tmm1/amqp] by Aman Gupta and Carrot[http://github.com/famoseagle/carrot] by Amos Elliston.
|
13
|
+
|
14
|
+
You can use Bunny to -
|
15
|
+
|
16
|
+
* Create and delete exchanges
|
17
|
+
* Create and delete queues
|
18
|
+
* Publish and consume messages
|
19
|
+
|
20
|
+
Bunny is known to work with RabbitMQ version 1.5.4 and version 0-8 of the AMQP specification.
|
21
|
+
|
22
|
+
=== INSTALL:
|
23
|
+
|
24
|
+
*Rubyforge*: <tt>gem install bunny</tt>
|
25
|
+
|
26
|
+
*GitHub*: <tt>gem install celldee-bunny</tt>
|
27
|
+
|
28
|
+
=== QUICK START:
|
29
|
+
|
30
|
+
require 'bunny'
|
31
|
+
|
32
|
+
b = Bunny.new(:logging => true)
|
33
|
+
|
34
|
+
# start a communication session with the amqp server
|
35
|
+
b.start
|
36
|
+
|
37
|
+
# declare a queue
|
38
|
+
q = b.queue('test1')
|
39
|
+
|
40
|
+
# publish a message to the queue
|
41
|
+
q.publish('Hello everybody!')
|
42
|
+
|
43
|
+
# get message from the queue
|
44
|
+
msg = q.pop
|
45
|
+
|
46
|
+
puts 'This is the message: ' + msg + "\n\n"
|
47
|
+
|
48
|
+
# close the connection
|
49
|
+
b.stop
|
50
|
+
|
51
|
+
=== OTHER:
|
52
|
+
Please see the _examples_ directory for additional usage information.
|
data/Rakefile
ADDED
data/bunny.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{bunny}
|
3
|
+
s.version = "0.4.0"
|
4
|
+
|
5
|
+
s.authors = ["Chris Duncan"]
|
6
|
+
s.date = %q{2009-05-15}
|
7
|
+
s.description = %q{Another synchronous Ruby AMQP client}
|
8
|
+
s.email = %q{celldee@gmail.com}
|
9
|
+
s.rubyforge_project = %q{bunny-amqp}
|
10
|
+
s.has_rdoc = true
|
11
|
+
s.extra_rdoc_files = [ "README" ]
|
12
|
+
s.rdoc_options = [ "--main", "README" ]
|
13
|
+
s.homepage = %q{http://github.com/celldee/bunny}
|
14
|
+
s.summary = %q{A synchronous Ruby AMQP client that enables interaction with AMQP-compliant brokers/servers.}
|
15
|
+
s.files = ["LICENSE",
|
16
|
+
"README",
|
17
|
+
"Rakefile",
|
18
|
+
"bunny.gemspec",
|
19
|
+
"examples/simple.rb",
|
20
|
+
"examples/simple_ack.rb",
|
21
|
+
"examples/simple_consumer.rb",
|
22
|
+
"examples/simple_fanout.rb",
|
23
|
+
"examples/simple_publisher.rb",
|
24
|
+
"examples/simple_topic.rb",
|
25
|
+
"lib/bunny.rb",
|
26
|
+
"lib/bunny/client.rb",
|
27
|
+
"lib/bunny/exchange.rb",
|
28
|
+
"lib/bunny/queue.rb",
|
29
|
+
"lib/qrack/client.rb",
|
30
|
+
"lib/qrack/protocol/protocol.rb",
|
31
|
+
"lib/qrack/protocol/spec.rb",
|
32
|
+
"lib/qrack/qrack.rb",
|
33
|
+
"lib/qrack/transport/buffer.rb",
|
34
|
+
"lib/qrack/transport/frame.rb",
|
35
|
+
"spec/bunny_spec.rb",
|
36
|
+
"spec/exchange_spec.rb",
|
37
|
+
"spec/queue_spec.rb"]
|
38
|
+
end
|
data/examples/simple.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# simple.rb
|
2
|
+
|
3
|
+
# Assumes that target message broker/server has a user called 'guest' with a password 'guest'
|
4
|
+
# and that it is running on 'localhost'.
|
5
|
+
|
6
|
+
# If this is not the case, please change the 'Bunny.new' call below to include
|
7
|
+
# the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar')
|
8
|
+
|
9
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
10
|
+
|
11
|
+
require 'bunny'
|
12
|
+
|
13
|
+
b = Bunny.new(:logging => true)
|
14
|
+
|
15
|
+
# start a communication session with the amqp server
|
16
|
+
b.start
|
17
|
+
|
18
|
+
# declare a queue
|
19
|
+
q = b.queue('test1')
|
20
|
+
|
21
|
+
# publish a message to the queue
|
22
|
+
q.publish('Hello everybody!')
|
23
|
+
|
24
|
+
# get message from the queue
|
25
|
+
msg = q.pop
|
26
|
+
|
27
|
+
puts 'This is the message: ' + msg + "\n\n"
|
28
|
+
|
29
|
+
# close the client connection
|
30
|
+
b.stop
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# simple_ack.rb
|
2
|
+
|
3
|
+
# Assumes that target message broker/server has a user called 'guest' with a password 'guest'
|
4
|
+
# and that it is running on 'localhost'.
|
5
|
+
|
6
|
+
# If this is not the case, please change the 'Bunny.new' call below to include
|
7
|
+
# the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar')
|
8
|
+
|
9
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
10
|
+
|
11
|
+
require 'bunny'
|
12
|
+
|
13
|
+
b = Bunny.new(:logging => true)
|
14
|
+
|
15
|
+
# start a communication session with the amqp server
|
16
|
+
b.start
|
17
|
+
|
18
|
+
# declare a queue
|
19
|
+
q = b.queue('test1')
|
20
|
+
|
21
|
+
# publish a message to the queue
|
22
|
+
q.publish('Testing acknowledgements')
|
23
|
+
|
24
|
+
# get message from the queue
|
25
|
+
msg = q.pop(:ack => true)
|
26
|
+
|
27
|
+
# acknowledge receipt of message
|
28
|
+
q.ack
|
29
|
+
|
30
|
+
puts 'This is the message: ' + msg + "\n\n"
|
31
|
+
|
32
|
+
# close the client connection
|
33
|
+
b.stop
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# consumer.rb
|
2
|
+
|
3
|
+
# N.B. To be used in conjunction with simple_publisher.rb
|
4
|
+
|
5
|
+
# Assumes that target message broker/server has a user called 'guest' with a password 'guest'
|
6
|
+
# and that it is running on 'localhost'.
|
7
|
+
|
8
|
+
# If this is not the case, please change the 'Bunny.new' call below to include
|
9
|
+
# the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar')
|
10
|
+
|
11
|
+
# How this example works
|
12
|
+
#=======================
|
13
|
+
#
|
14
|
+
# Open up two console windows start this program in one of them by typing -
|
15
|
+
#
|
16
|
+
# ruby simple_consumer.rb
|
17
|
+
#
|
18
|
+
# Then switch to the other console window and type -
|
19
|
+
#
|
20
|
+
# ruby simple_publisher.rb
|
21
|
+
#
|
22
|
+
# A message will be printed out by the simple_consumer and it will wait for the next message
|
23
|
+
#
|
24
|
+
# Run simple_publisher 3 more times. After the last run simple_consumer will stop.
|
25
|
+
|
26
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
27
|
+
|
28
|
+
require 'bunny'
|
29
|
+
|
30
|
+
b = Bunny.new(:logging => true)
|
31
|
+
|
32
|
+
# start a communication session with the amqp server
|
33
|
+
b.start
|
34
|
+
|
35
|
+
# create/get queue
|
36
|
+
q = b.queue('po_box')
|
37
|
+
|
38
|
+
# create/get exchange
|
39
|
+
exch = b.exchange('sorting_room')
|
40
|
+
|
41
|
+
# bind queue to exchange
|
42
|
+
q.bind(exch, :key => 'fred')
|
43
|
+
|
44
|
+
# initialize counter
|
45
|
+
i = 1
|
46
|
+
|
47
|
+
# subscribe to queue
|
48
|
+
q.subscribe(:consumer_tag => 'testtag1') do |msg|
|
49
|
+
puts i.to_s + ': ' + msg
|
50
|
+
i+=1
|
51
|
+
q.unsubscribe(:consumer_tag => 'testtag1') if i == 5
|
52
|
+
end
|
53
|
+
|
54
|
+
# close the connection
|
55
|
+
b.stop
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# fanout.rb
|
2
|
+
|
3
|
+
# Assumes that target message broker/server has a user called 'guest' with a password 'guest'
|
4
|
+
# and that it is running on 'localhost'.
|
5
|
+
|
6
|
+
# If this is not the case, please change the 'Bunny.new' call below to include
|
7
|
+
# the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar')
|
8
|
+
|
9
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
10
|
+
|
11
|
+
require 'bunny'
|
12
|
+
|
13
|
+
b = Bunny.new(:logging => true)
|
14
|
+
|
15
|
+
# start a communication session with the amqp server
|
16
|
+
b.start
|
17
|
+
|
18
|
+
# declare queues
|
19
|
+
q1 = b.queue('test_fan1')
|
20
|
+
q2 = b.queue('test_fan2')
|
21
|
+
|
22
|
+
# create a fanout exchange
|
23
|
+
exch = b.exchange('test_fan', :type => :fanout)
|
24
|
+
|
25
|
+
# bind the queues to the exchange
|
26
|
+
q1.bind(exch)
|
27
|
+
q2.bind(exch)
|
28
|
+
|
29
|
+
# publish a message to the exchange
|
30
|
+
exch.publish('This message will be fanned out')
|
31
|
+
|
32
|
+
# get message from the queues
|
33
|
+
msg = q1.pop
|
34
|
+
puts 'This is the message from q1: ' + msg + "\n\n"
|
35
|
+
msg = q2.pop
|
36
|
+
puts 'This is the message from q2: ' + msg + "\n\n"
|
37
|
+
|
38
|
+
# close the client connection
|
39
|
+
b.stop
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# simple_publisher.rb
|
2
|
+
|
3
|
+
# N.B. To be used in conjunction with simple_consumer.rb. See simple_consumer.rb for explanation.
|
4
|
+
|
5
|
+
# Assumes that target message broker/server has a user called 'guest' with a password 'guest'
|
6
|
+
# and that it is running on 'localhost'.
|
7
|
+
|
8
|
+
# If this is not the case, please change the 'Bunny.new' call below to include
|
9
|
+
# the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar')
|
10
|
+
|
11
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
12
|
+
|
13
|
+
require 'bunny'
|
14
|
+
|
15
|
+
b = Bunny.new(:logging => true)
|
16
|
+
|
17
|
+
# start a communication session with the amqp server
|
18
|
+
b.start
|
19
|
+
|
20
|
+
# create/get exchange
|
21
|
+
exch = b.exchange('sorting_room')
|
22
|
+
|
23
|
+
# publish message to exchange
|
24
|
+
exch.publish('This is a message from the publisher', :key => 'fred')
|
25
|
+
|
26
|
+
# message should now be picked up by the consumer so we can stop
|
27
|
+
b.stop
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# simple_topic.rb
|
2
|
+
|
3
|
+
# Assumes that target message broker/server has a user called 'guest' with a password 'guest'
|
4
|
+
# and that it is running on 'localhost'.
|
5
|
+
|
6
|
+
# If this is not the case, please change the 'Bunny.new' call below to include
|
7
|
+
# the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar')
|
8
|
+
|
9
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
10
|
+
|
11
|
+
require 'bunny'
|
12
|
+
|
13
|
+
b = Bunny.new
|
14
|
+
|
15
|
+
# start a communication session with the amqp server
|
16
|
+
b.start
|
17
|
+
|
18
|
+
# declare queues
|
19
|
+
soccer = b.queue('topic_soccer')
|
20
|
+
cricket = b.queue('topic_cricket')
|
21
|
+
rugby = b.queue('topic_rugby')
|
22
|
+
allsport = b.queue('topic_allsport')
|
23
|
+
|
24
|
+
# create a topic exchange
|
25
|
+
sports_results = b.exchange('sports_results', :type => :topic)
|
26
|
+
|
27
|
+
# bind the queues to the exchange
|
28
|
+
soccer.bind(sports_results, :key => 'soccer.*')
|
29
|
+
cricket.bind(sports_results, :key => 'cricket.*')
|
30
|
+
rugby.bind(sports_results, :key => 'rugby.*')
|
31
|
+
allsport.bind(sports_results, :key => '*.result')
|
32
|
+
|
33
|
+
# publish messages to the exchange
|
34
|
+
sports_results.publish('Manchester United 1 : Hull City 4', :key => 'soccer.result')
|
35
|
+
sports_results.publish('England beat Australia by 5 wickets in first test', :key => 'cricket.result')
|
36
|
+
sports_results.publish('British Lions 15 : South Africa 12', :key => 'rugby.result')
|
37
|
+
|
38
|
+
# get message from the queues
|
39
|
+
|
40
|
+
# soccer queue got the soccer message
|
41
|
+
msg = soccer.pop
|
42
|
+
puts 'This is a message from the soccer q: ' + msg + "\n\n"
|
43
|
+
|
44
|
+
# cricket queue got the cricket message
|
45
|
+
msg = cricket.pop
|
46
|
+
puts 'This is a message from the cricket q: ' + msg + "\n\n"
|
47
|
+
|
48
|
+
# rugby queue got the rugby message
|
49
|
+
msg = rugby.pop
|
50
|
+
puts 'This is a message from the rugby q: ' + msg + "\n\n"
|
51
|
+
|
52
|
+
# allsport queue got all of the messages
|
53
|
+
until msg == :queue_empty do
|
54
|
+
msg = allsport.pop
|
55
|
+
puts 'This is a message from the allsport q: ' + msg + "\n\n" unless msg == :queue_empty
|
56
|
+
end
|
57
|
+
|
58
|
+
# close the client connection
|
59
|
+
b.stop
|
data/lib/bunny/client.rb
ADDED
@@ -0,0 +1,324 @@
|
|
1
|
+
module Bunny
|
2
|
+
|
3
|
+
=begin rdoc
|
4
|
+
|
5
|
+
=== DESCRIPTION:
|
6
|
+
|
7
|
+
The Client class provides the major Bunny API methods.
|
8
|
+
|
9
|
+
=end
|
10
|
+
|
11
|
+
class Client < Qrack::Client
|
12
|
+
CONNECT_TIMEOUT = 1.0
|
13
|
+
RETRY_DELAY = 10.0
|
14
|
+
|
15
|
+
attr_reader :status, :host, :vhost, :port
|
16
|
+
attr_accessor :channel, :logging, :exchanges, :queues, :ticket
|
17
|
+
|
18
|
+
=begin rdoc
|
19
|
+
|
20
|
+
=== DESCRIPTION:
|
21
|
+
|
22
|
+
Sets up a Bunny::Client object ready for connection to a broker/server. _Client_._status_ is set to
|
23
|
+
<tt>:not_connected</tt>.
|
24
|
+
|
25
|
+
==== OPTIONS:
|
26
|
+
|
27
|
+
* <tt>:host => '_hostname_' (default = 'localhost')</tt>
|
28
|
+
* <tt>:port => _portno_ (default = 5672)</tt>
|
29
|
+
* <tt>:vhost => '_vhostname_' (default = '/')</tt>
|
30
|
+
* <tt>:user => '_username_' (default = 'guest')</tt>
|
31
|
+
* <tt>:pass => '_password_' (default = 'guest')</tt>
|
32
|
+
* <tt>:logging => true or false (_default_)</tt> - If set to _true_, session information is sent
|
33
|
+
to STDOUT.
|
34
|
+
* <tt>:insist => true or false (_default_)</tt> - In a configuration with multiple load-sharing
|
35
|
+
servers, the server may respond to a Connection.Open method with a Connection.Redirect. The insist
|
36
|
+
option, if set to _true_, tells the server that the client is insisting on a connection to the
|
37
|
+
specified server.
|
38
|
+
|
39
|
+
=end
|
40
|
+
|
41
|
+
def initialize(opts = {})
|
42
|
+
@host = opts[:host] || 'localhost'
|
43
|
+
@port = opts[:port] || Qrack::Protocol::PORT
|
44
|
+
@user = opts[:user] || 'guest'
|
45
|
+
@pass = opts[:pass] || 'guest'
|
46
|
+
@vhost = opts[:vhost] || '/'
|
47
|
+
@logging = opts[:logging] || false
|
48
|
+
@insist = opts[:insist]
|
49
|
+
@status = :not_connected
|
50
|
+
end
|
51
|
+
|
52
|
+
=begin rdoc
|
53
|
+
|
54
|
+
=== DESCRIPTION:
|
55
|
+
|
56
|
+
Declares an exchange to the broker/server. If the exchange does not exist, a new one is created
|
57
|
+
using the arguments passed in. If the exchange already exists, a reference to it is created, provided
|
58
|
+
that the arguments passed in do not conflict with the existing attributes of the exchange. If an error
|
59
|
+
occurs a _Bunny_::_ProtocolError_ is raised.
|
60
|
+
|
61
|
+
==== OPTIONS:
|
62
|
+
|
63
|
+
* <tt>:type => one of :direct (_default_), :fanout, :topic, :headers</tt>
|
64
|
+
* <tt>:passive => true or false</tt> - If set to _true_, the server will not create the exchange.
|
65
|
+
The client can use this to check whether an exchange exists without modifying the server state.
|
66
|
+
* <tt>:durable => true or false (_default_)</tt> - If set to _true_ when creating a new exchange, the exchange
|
67
|
+
will be marked as durable. Durable exchanges remain active when a server restarts. Non-durable
|
68
|
+
exchanges (transient exchanges) are purged if/when a server restarts.
|
69
|
+
* <tt>:auto_delete => true or false (_default_)</tt> - If set to _true_, the exchange is deleted
|
70
|
+
when all queues have finished using it.
|
71
|
+
* <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
|
72
|
+
|
73
|
+
==== RETURNS:
|
74
|
+
|
75
|
+
Exchange
|
76
|
+
|
77
|
+
=end
|
78
|
+
|
79
|
+
def exchange(name, opts = {})
|
80
|
+
exchanges[name] ||= Bunny::Exchange.new(self, name, opts)
|
81
|
+
end
|
82
|
+
|
83
|
+
=begin rdoc
|
84
|
+
|
85
|
+
=== DESCRIPTION:
|
86
|
+
|
87
|
+
Returns hash of exchanges declared by Bunny.
|
88
|
+
|
89
|
+
=end
|
90
|
+
|
91
|
+
def exchanges
|
92
|
+
@exchanges ||= {}
|
93
|
+
end
|
94
|
+
|
95
|
+
=begin rdoc
|
96
|
+
|
97
|
+
=== DESCRIPTION:
|
98
|
+
|
99
|
+
Declares a queue to the broker/server. If the queue does not exist, a new one is created
|
100
|
+
using the arguments passed in. If the queue already exists, a reference to it is created, provided
|
101
|
+
that the arguments passed in do not conflict with the existing attributes of the queue. If an error
|
102
|
+
occurs a _Bunny_::_ProtocolError_ is raised.
|
103
|
+
|
104
|
+
==== OPTIONS:
|
105
|
+
|
106
|
+
* <tt>:passive => true or false (_default_)</tt> - If set to _true_, the server will not create
|
107
|
+
the queue. The client can use this to check whether a queue exists without modifying the server
|
108
|
+
state.
|
109
|
+
* <tt>:durable => true or false (_default_)</tt> - If set to _true_ when creating a new queue, the
|
110
|
+
queue will be marked as durable. Durable queues remain active when a server restarts. Non-durable
|
111
|
+
queues (transient queues) are purged if/when a server restarts. Note that durable queues do not
|
112
|
+
necessarily hold persistent messages, although it does not make sense to send persistent messages
|
113
|
+
to a transient queue.
|
114
|
+
* <tt>:exclusive => true or false (_default_)</tt> - If set to _true_, requests an exclusive queue.
|
115
|
+
Exclusive queues may only be consumed from by the current connection. Setting the 'exclusive'
|
116
|
+
flag always implies 'auto-delete'.
|
117
|
+
* <tt>:auto_delete => true or false (_default_)</tt> - If set to _true_, the queue is deleted
|
118
|
+
when all consumers have finished using it. Last consumer can be cancelled either explicitly
|
119
|
+
or because its channel is closed. If there has never been a consumer on the queue, it is not
|
120
|
+
deleted.
|
121
|
+
* <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
|
122
|
+
|
123
|
+
==== RETURNS:
|
124
|
+
|
125
|
+
Queue
|
126
|
+
|
127
|
+
=end
|
128
|
+
|
129
|
+
def queue(name, opts = {})
|
130
|
+
queues[name] ||= Bunny::Queue.new(self, name, opts)
|
131
|
+
end
|
132
|
+
|
133
|
+
=begin rdoc
|
134
|
+
|
135
|
+
=== DESCRIPTION:
|
136
|
+
|
137
|
+
Returns hash of queues declared by Bunny.
|
138
|
+
|
139
|
+
=end
|
140
|
+
|
141
|
+
def queues
|
142
|
+
@queues ||= {}
|
143
|
+
end
|
144
|
+
|
145
|
+
def send_frame(*args)
|
146
|
+
args.each do |data|
|
147
|
+
data.ticket = ticket if ticket and data.respond_to?(:ticket=)
|
148
|
+
data = data.to_frame(channel) unless data.is_a?(Qrack::Transport::Frame)
|
149
|
+
data.channel = channel
|
150
|
+
|
151
|
+
log :send, data
|
152
|
+
write(data.to_s)
|
153
|
+
end
|
154
|
+
nil
|
155
|
+
end
|
156
|
+
|
157
|
+
def next_frame
|
158
|
+
frame = Qrack::Transport::Frame.parse(buffer)
|
159
|
+
log :received, frame
|
160
|
+
frame
|
161
|
+
end
|
162
|
+
|
163
|
+
def next_method
|
164
|
+
next_payload
|
165
|
+
end
|
166
|
+
|
167
|
+
def next_payload
|
168
|
+
frame = next_frame
|
169
|
+
frame and frame.payload
|
170
|
+
end
|
171
|
+
|
172
|
+
=begin rdoc
|
173
|
+
|
174
|
+
=== DESCRIPTION:
|
175
|
+
|
176
|
+
Closes the current communication channel and connection. If an error occurs a
|
177
|
+
_Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to <tt>:not_connected</tt>.
|
178
|
+
|
179
|
+
==== RETURNS:
|
180
|
+
|
181
|
+
<tt>:not_connected</tt> if successful.
|
182
|
+
|
183
|
+
=end
|
184
|
+
|
185
|
+
def close
|
186
|
+
send_frame(
|
187
|
+
Qrack::Protocol::Channel::Close.new(:reply_code => 200, :reply_text => 'bye', :method_id => 0, :class_id => 0)
|
188
|
+
)
|
189
|
+
raise Bunny::ProtocolError, "Error closing channel #{channel}" unless next_method.is_a?(Qrack::Protocol::Channel::CloseOk)
|
190
|
+
|
191
|
+
self.channel = 0
|
192
|
+
send_frame(
|
193
|
+
Qrack::Protocol::Connection::Close.new(:reply_code => 200, :reply_text => 'Goodbye', :class_id => 0, :method_id => 0)
|
194
|
+
)
|
195
|
+
raise Bunny::ProtocolError, "Error closing connection" unless next_method.is_a?(Qrack::Protocol::Connection::CloseOk)
|
196
|
+
|
197
|
+
close_socket
|
198
|
+
end
|
199
|
+
|
200
|
+
alias stop close
|
201
|
+
|
202
|
+
def read(*args)
|
203
|
+
send_command(:read, *args)
|
204
|
+
end
|
205
|
+
|
206
|
+
def write(*args)
|
207
|
+
send_command(:write, *args)
|
208
|
+
end
|
209
|
+
|
210
|
+
=begin rdoc
|
211
|
+
|
212
|
+
=== DESCRIPTION:
|
213
|
+
|
214
|
+
Opens a communication channel and starts a connection. If an error occurs, a
|
215
|
+
_Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to <tt>:connected</tt>.
|
216
|
+
|
217
|
+
==== RETURNS:
|
218
|
+
|
219
|
+
<tt>:connected</tt> if successful.
|
220
|
+
|
221
|
+
=end
|
222
|
+
|
223
|
+
def start_session
|
224
|
+
@channel = 0
|
225
|
+
write(Qrack::Protocol::HEADER)
|
226
|
+
write([1, 1, Qrack::Protocol::VERSION_MAJOR, Qrack::Protocol::VERSION_MINOR].pack('C4'))
|
227
|
+
raise Bunny::ProtocolError, 'Connection initiation failed' unless next_method.is_a?(Qrack::Protocol::Connection::Start)
|
228
|
+
|
229
|
+
send_frame(
|
230
|
+
Qrack::Protocol::Connection::StartOk.new(
|
231
|
+
{:platform => 'Ruby', :product => 'Bunny', :information => 'http://github.com/celldee/bunny', :version => VERSION},
|
232
|
+
'AMQPLAIN',
|
233
|
+
{:LOGIN => @user, :PASSWORD => @pass},
|
234
|
+
'en_US'
|
235
|
+
)
|
236
|
+
)
|
237
|
+
|
238
|
+
method = next_method
|
239
|
+
raise Bunny::ProtocolError, "Connection failed - user: #{@user}, pass: #{@pass}" if method.nil?
|
240
|
+
|
241
|
+
if method.is_a?(Qrack::Protocol::Connection::Tune)
|
242
|
+
send_frame(
|
243
|
+
Qrack::Protocol::Connection::TuneOk.new( :channel_max => 0, :frame_max => 131072, :heartbeat => 0)
|
244
|
+
)
|
245
|
+
end
|
246
|
+
|
247
|
+
send_frame(
|
248
|
+
Qrack::Protocol::Connection::Open.new(:virtual_host => @vhost, :capabilities => '', :insist => @insist)
|
249
|
+
)
|
250
|
+
raise Bunny::ProtocolError, 'Cannot open connection' unless next_method.is_a?(Qrack::Protocol::Connection::OpenOk)
|
251
|
+
|
252
|
+
@channel = 1
|
253
|
+
send_frame(Qrack::Protocol::Channel::Open.new)
|
254
|
+
raise Bunny::ProtocolError, "Cannot open channel #{channel}" unless next_method.is_a?(Qrack::Protocol::Channel::OpenOk)
|
255
|
+
|
256
|
+
send_frame(
|
257
|
+
Qrack::Protocol::Access::Request.new(:realm => '/data', :read => true, :write => true, :active => true, :passive => true)
|
258
|
+
)
|
259
|
+
method = next_method
|
260
|
+
raise Bunny::ProtocolError, 'Access denied' unless method.is_a?(Qrack::Protocol::Access::RequestOk)
|
261
|
+
self.ticket = method.ticket
|
262
|
+
|
263
|
+
# return status
|
264
|
+
status
|
265
|
+
end
|
266
|
+
|
267
|
+
alias start start_session
|
268
|
+
|
269
|
+
private
|
270
|
+
|
271
|
+
def buffer
|
272
|
+
@buffer ||= Qrack::Transport::Buffer.new(self)
|
273
|
+
end
|
274
|
+
|
275
|
+
def send_command(cmd, *args)
|
276
|
+
begin
|
277
|
+
timeout(1.5) do
|
278
|
+
socket.__send__(cmd, *args)
|
279
|
+
end
|
280
|
+
rescue => e
|
281
|
+
@status = :not_connected
|
282
|
+
raise Bunny::ServerDownError, e.message
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def socket
|
287
|
+
return @socket if @socket and (@status == :connected) and not @socket.closed?
|
288
|
+
|
289
|
+
begin
|
290
|
+
@status = :not_connected
|
291
|
+
|
292
|
+
# Attempt to connect.
|
293
|
+
@socket = timeout(CONNECT_TIMEOUT) do
|
294
|
+
TCPSocket.new(host, port)
|
295
|
+
end
|
296
|
+
|
297
|
+
if Socket.constants.include? 'TCP_NODELAY'
|
298
|
+
@socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
|
299
|
+
end
|
300
|
+
@status = :connected
|
301
|
+
rescue => e
|
302
|
+
@status = :not_connected
|
303
|
+
raise Bunny::ServerDownError, e.message
|
304
|
+
end
|
305
|
+
|
306
|
+
@socket
|
307
|
+
end
|
308
|
+
|
309
|
+
def close_socket(reason=nil)
|
310
|
+
# Close the socket. The server is not considered dead.
|
311
|
+
@socket.close if @socket and not @socket.closed?
|
312
|
+
@socket = nil
|
313
|
+
@status = :not_connected
|
314
|
+
end
|
315
|
+
|
316
|
+
def log(*args)
|
317
|
+
return unless logging
|
318
|
+
require 'pp'
|
319
|
+
pp args
|
320
|
+
puts
|
321
|
+
end
|
322
|
+
|
323
|
+
end
|
324
|
+
end
|