bunny 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -4,30 +4,23 @@ Google Group: [bunny-amqp](http://groups.google.com/group/bunny-amqp)
4
4
 
5
5
  Mailing List: [bunny-amqp-devel](http://rubyforge.org/mailman/listinfo/bunny-amqp-devel)
6
6
 
7
- Rubyforge: [bunny-amqp](http://bunny-amqp.rubyforge.org)
7
+ Rubyforge: [bunny-amqp](http://rubyforge.org/projects/bunny-amqp)
8
8
 
9
9
  ## Announcements
10
10
 
11
- **IMPORTANT**
11
+ Bunny v0.1.1 has been released. It contains the following changes -
12
12
 
13
- The Exchange#initialize method arguments have changed as of version 0.0.7
14
-
15
- You now create an exchange like this -
16
-
17
- b = Bunny.new
18
- exch = b.exchange('my_exchange', :type => :fanout)
19
-
20
- If you do not specify a :type option then a default of :direct is used.
21
-
22
- The old way was -
23
-
24
- b = Bunny.new
25
- exch = b.exchange(:fanout, 'my_exchange')
13
+ * Queue#delete method returns ‘QUEUE DELETED’, Exchange#delete method returns ‘EXCHANGE DELETED’, Queue#bind returns ‘BIND SUCCEEDED’, Queue#unbind returns ‘UNBIND SUCCEEDED’
14
+ * Queue#subscribe method available (see example bunny/examples/simple_consumer.rb)
15
+ * Queue#status now returns a hash {:message_count, :consumer_count}
16
+ * Queue#ack works after a Queue#subscribe or Queue#pop if :ack => true was specified
26
17
 
27
18
  ## About
28
19
 
29
20
  *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.
30
21
 
22
+ It is based on a great deal of fabulous code from [amqp](http://github.com/tmm1/amqp) by Aman Gupta and [Carrot](http://github.com/famoseagle/carrot) by Amos Elliston.
23
+
31
24
  You can use *Bunny* to -
32
25
 
33
26
  * Create and delete exchanges
@@ -43,12 +36,7 @@ You can use *Bunny* to -
43
36
  b = Bunny.new(:logging => true)
44
37
 
45
38
  # start a communication session with the amqp server
46
- begin
47
- b.start
48
- rescue Exception => e
49
- puts 'ERROR - Could not start a session: ' + e
50
- exit
51
- end
39
+ b.start
52
40
 
53
41
  # declare a queue
54
42
  q = b.queue('test1')
@@ -110,12 +98,15 @@ Queue#message_count
110
98
  ### Return queue consumer count
111
99
  Queue#consumer_count
112
100
 
113
- ### Return queue status (array of message count and consumer_count)
101
+ ### Return queue status (hash {:message count, :consumer_count})
114
102
  Queue#status
115
103
 
116
104
  ### Delete a queue from the target server
117
105
  Queue#delete({_options_})
118
106
 
107
+ ### Acknowledge receipt of a message
108
+ Queue#ack
109
+
119
110
  ## Acknowledgements
120
111
 
121
112
  This project has borrowed heavily from the following two projects and owes their respective creators and collaborators a whole lot of gratitude:
@@ -0,0 +1,44 @@
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
+ begin
17
+ b.start
18
+ rescue Exception => e
19
+ puts 'ERROR - Could not start a session: ' + e
20
+ exit
21
+ end
22
+
23
+ # declare queues
24
+ q1 = b.queue('test_fan1')
25
+ q2 = b.queue('test_fan2')
26
+
27
+ # create a fanout exchange
28
+ exch = b.exchange('test_fan', :type => :fanout)
29
+
30
+ # bind the queues to the exchange
31
+ q1.bind(exch)
32
+ q2.bind(exch)
33
+
34
+ # publish a message to the exchange
35
+ exch.publish('This message will be fanned out')
36
+
37
+ # get message from the queues
38
+ msg = q1.pop
39
+ puts 'This is the message from q1: ' + msg + "\n\n"
40
+ msg = q2.pop
41
+ puts 'This is the message from q2: ' + msg + "\n\n"
42
+
43
+ # close the client connection
44
+ b.stop
data/examples/simple.rb CHANGED
@@ -13,12 +13,7 @@ require 'bunny'
13
13
  b = Bunny.new(:logging => true)
14
14
 
15
15
  # start a communication session with the amqp server
16
- begin
17
- b.start
18
- rescue Exception => e
19
- puts 'ERROR - Could not start a session: ' + e
20
- exit
21
- end
16
+ b.start
22
17
 
23
18
  # declare a queue
24
19
  q = b.queue('test1')
@@ -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,36 @@
1
+ # consumer.rb
2
+
3
+ # N.B. To be used in conjunction with publisher.rb - RUN THIS BEFORE 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
+ $:.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 queue
21
+ q = b.queue('po_box')
22
+
23
+ # create/get exchange
24
+ exch = b.exchange('sorting_room')
25
+
26
+ # bind queue to exchange
27
+ q.bind(exch, :key => 'fred')
28
+
29
+ # subscribe to queue
30
+ msg = q.subscribe(:consumer_tag => 'testtag1')
31
+
32
+ # output received message
33
+ puts msg
34
+
35
+ # close the connection
36
+ b.stop
@@ -0,0 +1,33 @@
1
+ # simple_publisher.rb
2
+
3
+ # N.B. To be used in conjunction with simple_consumer.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
+ $:.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 queue
21
+ q = b.queue('po_box')
22
+
23
+ # create/get exchange
24
+ exch = b.exchange('sorting_room')
25
+
26
+ # bind queue to exchange
27
+ q.bind(exch, :key => 'fred')
28
+
29
+ # publish message to exchange
30
+ exch.publish('This is a message from the publisher', :key => 'fred')
31
+
32
+ # message should now be picked up by the consumer so we can stop
33
+ b.stop
data/lib/amqp.rb CHANGED
@@ -3,10 +3,14 @@ module AMQP
3
3
  require "amqp/#{file}"
4
4
  end
5
5
 
6
- # constants
6
+ # return messages
7
7
  CONNECTED = 'CONNECTED'
8
8
  NOT_CONNECTED = 'NOT CONNECTED'
9
9
  QUEUE_EMPTY = 'QUEUE EMPTY'
10
+ QUEUE_DELETED = 'QUEUE DELETED'
11
+ EXCHANGE_DELETED = 'EXCHANGE DELETED'
12
+ BIND_SUCCEEDED = 'BIND SUCCEEDED'
13
+ UNBIND_SUCCEEDED = 'UNBIND SUCCEEDED'
10
14
 
11
15
  # specific error definitions
12
16
  class ProtocolError < StandardError; end
@@ -65,6 +65,9 @@ class Bunny
65
65
  client.next_method.is_a?(Protocol::Exchange::DeleteOk)
66
66
 
67
67
  client.exchanges.delete(name)
68
+
69
+ # return confirmation
70
+ EXCHANGE_DELETED
68
71
  end
69
72
 
70
73
  end
data/lib/bunny/queue.rb CHANGED
@@ -24,15 +24,28 @@ class Bunny
24
24
 
25
25
  raise ProtocolError, "Error declaring queue #{name}" unless client.next_method.is_a?(Protocol::Queue::DeclareOk)
26
26
  end
27
+
28
+ def ack
29
+ client.send_frame(
30
+ Protocol::Basic::Ack.new(:delivery_tag => delivery_tag)
31
+ )
32
+
33
+ # reset delivery tag
34
+ self.delivery_tag = nil
35
+ end
27
36
 
28
37
  def pop(opts = {})
38
+
29
39
  # do we want the message header?
30
40
  hdr = opts.delete(:header)
31
41
 
42
+ # do we want to have to provide an acknowledgement?
43
+ ack = opts.delete(:ack)
44
+
32
45
  client.send_frame(
33
46
  Protocol::Basic::Get.new({ :queue => name,
34
47
  :consumer_tag => name,
35
- :no_ack => !opts.delete(:ack),
48
+ :no_ack => !ack,
36
49
  :nowait => true }.merge(opts))
37
50
  )
38
51
 
@@ -44,6 +57,9 @@ class Bunny
44
57
  raise ProtocolError, "Error getting message from queue #{name}"
45
58
  end
46
59
 
60
+ # get delivery tag to use for acknowledge
61
+ self.delivery_tag = method.delivery_tag if ack
62
+
47
63
  header = client.next_payload
48
64
  msg = client.next_payload
49
65
  raise MessageError, 'unexpected length' if msg.length < header.size
@@ -57,20 +73,58 @@ class Bunny
57
73
  end
58
74
 
59
75
  def message_count
60
- status.first
76
+ s = status
77
+ s[:message_count]
61
78
  end
62
79
 
63
80
  def consumer_count
64
- status.last
81
+ s = status
82
+ s[:consumer_count]
65
83
  end
66
84
 
67
- def status(opts = {}, &blk)
85
+ def status(opts = {})
68
86
  client.send_frame(
69
87
  Protocol::Queue::Declare.new({ :queue => name, :passive => true }.merge(opts))
70
88
  )
71
89
  method = client.next_method
72
- [method.message_count, method.consumer_count]
90
+ {:message_count => method.message_count, :consumer_count => method.consumer_count}
73
91
  end
92
+
93
+ def subscribe(opts = {})
94
+ consumer_tag = opts[:consumer_tag] || name
95
+
96
+ # ignore the :nowait option if passed, otherwise program will not wait for a
97
+ # message to get to the server causing an error
98
+ opts.delete(:nowait)
99
+
100
+ # do we want the message header?
101
+ hdr = opts.delete(:header)
102
+
103
+ # do we want to have to provide an acknowledgement?
104
+ ack = opts.delete(:ack)
105
+
106
+ client.send_frame(
107
+ Protocol::Basic::Consume.new({ :queue => name,
108
+ :consumer_tag => consumer_tag,
109
+ :no_ack => !ack,
110
+ :nowait => false }.merge(opts))
111
+ )
112
+
113
+ raise ProtocolError,
114
+ "Error subscribing to queue #{name}" unless
115
+ client.next_method.is_a?(Protocol::Basic::ConsumeOk)
116
+
117
+ method = client.next_method
118
+
119
+ # get delivery tag to use for acknowledge
120
+ self.delivery_tag = method.delivery_tag if ack
121
+
122
+ header = client.next_payload
123
+ msg = client.next_payload
124
+ raise MessageError, 'unexpected length' if msg.length < header.size
125
+
126
+ hdr ? {:header => header, :payload => msg} : msg
127
+ end
74
128
 
75
129
  def bind(exchange, opts = {})
76
130
  exchange = exchange.respond_to?(:name) ? exchange.name : exchange
@@ -90,6 +144,9 @@ class Bunny
90
144
  raise ProtocolError,
91
145
  "Error binding queue #{name}" unless
92
146
  client.next_method.is_a?(Protocol::Queue::BindOk)
147
+
148
+ # return message
149
+ BIND_SUCCEEDED
93
150
  end
94
151
 
95
152
  def unbind(exchange, opts = {})
@@ -107,6 +164,9 @@ class Bunny
107
164
  raise ProtocolError,
108
165
  "Error unbinding queue #{name}" unless
109
166
  client.next_method.is_a?(Protocol::Queue::UnbindOk)
167
+
168
+ # return message
169
+ UNBIND_SUCCEEDED
110
170
  end
111
171
 
112
172
  def delete(opts = {})
@@ -123,6 +183,9 @@ class Bunny
123
183
  client.next_method.is_a?(Protocol::Queue::DeleteOk)
124
184
 
125
185
  client.queues.delete(name)
186
+
187
+ # return confirmation
188
+ QUEUE_DELETED
126
189
  end
127
190
 
128
191
  private
@@ -62,7 +62,8 @@ describe Bunny::Exchange do
62
62
 
63
63
  it "should be able to be deleted" do
64
64
  exch = @b.exchange('direct_exchange')
65
- exch.delete
65
+ res = exch.delete
66
+ res.should == 'EXCHANGE DELETED'
66
67
  @b.exchanges.has_key?('direct_exchange').should be false
67
68
  end
68
69
 
data/spec/queue_spec.rb CHANGED
@@ -22,25 +22,25 @@ describe Bunny::Queue do
22
22
  it "should ignore the :nowait option when binding to an exchange" do
23
23
  exch = @b.exchange('direct_exch')
24
24
  q = @b.queue('test0')
25
- q.bind(exch, :nowait => true)
25
+ q.bind(exch, :nowait => true).should == 'BIND SUCCEEDED'
26
26
  end
27
27
 
28
28
  it "should be able to bind to an exchange" do
29
29
  exch = @b.exchange('direct_exch')
30
30
  q = @b.queue('test1')
31
- q.bind(exch)
31
+ q.bind(exch).should == 'BIND SUCCEEDED'
32
32
  end
33
33
 
34
34
  it "should ignore the :nowait option when unbinding from an exchange" do
35
35
  exch = @b.exchange('direct_exch')
36
36
  q = @b.queue('test0')
37
- q.unbind(exch, :nowait => true)
37
+ q.unbind(exch, :nowait => true).should == 'UNBIND SUCCEEDED'
38
38
  end
39
39
 
40
40
  it "should be able to unbind from an exchange" do
41
41
  exch = @b.exchange('direct_exch')
42
42
  q = @b.queue('test1')
43
- q.unbind(exch)
43
+ q.unbind(exch).should == 'UNBIND SUCCEEDED'
44
44
  end
45
45
 
46
46
  it "should be able to publish a message" do
@@ -76,7 +76,8 @@ describe Bunny::Queue do
76
76
 
77
77
  it "should be able to be deleted" do
78
78
  q = @b.queue('test1')
79
- q.delete
79
+ res = q.delete
80
+ res.should == 'QUEUE DELETED'
80
81
  @b.queues.has_key?('test1').should be false
81
82
  end
82
83
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bunny
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Duncan
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-25 00:00:00 +01:00
12
+ date: 2009-04-27 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -36,6 +36,10 @@ files:
36
36
  - lib/amqp/spec.rb
37
37
  - lib/bunny.rb
38
38
  - examples/simple.rb
39
+ - examples/fanout.rb
40
+ - examples/simple_consumer.rb
41
+ - examples/simple_publisher.rb
42
+ - examples/simple_ack.rb
39
43
  - spec/bunny_spec.rb
40
44
  - spec/exchange_spec.rb
41
45
  - spec/queue_spec.rb