bunny 0.6.3.rc2 → 0.7

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 (68) hide show
  1. data/.gitignore +8 -0
  2. data/.rspec +3 -0
  3. data/.travis.yml +15 -0
  4. data/.yardopts +9 -0
  5. data/CHANGELOG +3 -0
  6. data/Gemfile +39 -0
  7. data/Gemfile.lock +34 -0
  8. data/LICENSE +5 -4
  9. data/README.textile +54 -0
  10. data/Rakefile +15 -13
  11. data/bunny.gemspec +42 -61
  12. data/examples/simple_08.rb +4 -2
  13. data/examples/simple_09.rb +4 -2
  14. data/examples/simple_ack_08.rb +3 -1
  15. data/examples/simple_ack_09.rb +3 -1
  16. data/examples/simple_consumer_08.rb +4 -2
  17. data/examples/simple_consumer_09.rb +4 -2
  18. data/examples/simple_fanout_08.rb +3 -1
  19. data/examples/simple_fanout_09.rb +3 -1
  20. data/examples/simple_headers_08.rb +5 -3
  21. data/examples/simple_headers_09.rb +5 -3
  22. data/examples/simple_publisher_08.rb +3 -1
  23. data/examples/simple_publisher_09.rb +3 -1
  24. data/examples/simple_topic_08.rb +5 -3
  25. data/examples/simple_topic_09.rb +5 -3
  26. data/ext/amqp-0.8.json +616 -0
  27. data/ext/amqp-0.9.1.json +388 -0
  28. data/ext/config.yml +4 -0
  29. data/ext/qparser.rb +463 -0
  30. data/lib/bunny.rb +88 -66
  31. data/lib/bunny/channel08.rb +38 -38
  32. data/lib/bunny/channel09.rb +37 -37
  33. data/lib/bunny/client08.rb +184 -206
  34. data/lib/bunny/client09.rb +277 -363
  35. data/lib/bunny/consumer.rb +35 -0
  36. data/lib/bunny/exchange08.rb +37 -41
  37. data/lib/bunny/exchange09.rb +106 -124
  38. data/lib/bunny/queue08.rb +216 -202
  39. data/lib/bunny/queue09.rb +256 -326
  40. data/lib/bunny/subscription08.rb +30 -29
  41. data/lib/bunny/subscription09.rb +84 -83
  42. data/lib/bunny/version.rb +5 -0
  43. data/lib/qrack/amq-client-url.rb +165 -0
  44. data/lib/qrack/channel.rb +19 -17
  45. data/lib/qrack/client.rb +152 -151
  46. data/lib/qrack/errors.rb +5 -0
  47. data/lib/qrack/protocol/protocol08.rb +132 -130
  48. data/lib/qrack/protocol/protocol09.rb +133 -131
  49. data/lib/qrack/protocol/spec08.rb +2 -0
  50. data/lib/qrack/protocol/spec09.rb +2 -0
  51. data/lib/qrack/qrack08.rb +7 -10
  52. data/lib/qrack/qrack09.rb +7 -10
  53. data/lib/qrack/queue.rb +27 -40
  54. data/lib/qrack/subscription.rb +102 -101
  55. data/lib/qrack/transport/buffer08.rb +266 -264
  56. data/lib/qrack/transport/buffer09.rb +268 -264
  57. data/lib/qrack/transport/frame08.rb +13 -11
  58. data/lib/qrack/transport/frame09.rb +9 -7
  59. data/spec/spec_08/bunny_spec.rb +48 -45
  60. data/spec/spec_08/connection_spec.rb +10 -7
  61. data/spec/spec_08/exchange_spec.rb +145 -143
  62. data/spec/spec_08/queue_spec.rb +161 -161
  63. data/spec/spec_09/bunny_spec.rb +46 -44
  64. data/spec/spec_09/connection_spec.rb +15 -8
  65. data/spec/spec_09/exchange_spec.rb +147 -145
  66. data/spec/spec_09/queue_spec.rb +182 -184
  67. metadata +60 -41
  68. data/README.rdoc +0 -66
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ ####################################
4
+ # NOTE: THIS CLASS IS HERE TO MAKE #
5
+ # TRANSITION TO AMQ CLIENT EASIER #
6
+ ####################################
7
+
8
+ require "qrack/subscription"
9
+
10
+ # NOTE: This file is rather a temporary hack to fix
11
+ # https://github.com/ruby-amqp/bunny/issues/9 then
12
+ # some permanent solution. It's mostly copied from
13
+ # the AMQP and AMQ Client gems. Later on we should
14
+ # use AMQ Client directly and just inherit from
15
+ # the AMQ::Client::Sync::Consumer class.
16
+
17
+ module Bunny
18
+
19
+ # AMQP consumers are entities that handle messages delivered
20
+ # to them ("push API" as opposed to "pull API") by AMQP broker.
21
+ # Every consumer is associated with a queue. Consumers can be
22
+ # exclusive (no other consumers can be registered for the same
23
+ # queue) or not (consumers share the queue). In the case of
24
+ # multiple consumers per queue, messages are distributed in
25
+ # round robin manner with respect to channel-level prefetch
26
+ # setting).
27
+ class Consumer < Qrack::Subscription
28
+ def initialize(*args)
29
+ super(*args)
30
+ @consumer_tag ||= (1..32).to_a.shuffle.join
31
+ end
32
+
33
+ alias_method :consume, :start
34
+ end
35
+ end
@@ -1,5 +1,7 @@
1
+ # encoding: utf-8
2
+
1
3
  module Bunny
2
-
4
+
3
5
  =begin rdoc
4
6
 
5
7
  === DESCRIPTION:
@@ -28,7 +30,7 @@ target broker/server or visit the {AMQP website}[http://www.amqp.org] to find th
28
30
  specification that applies to your target broker/server.
29
31
 
30
32
  =end
31
-
33
+
32
34
  class Exchange
33
35
 
34
36
  attr_reader :client, :type, :name, :opts, :key
@@ -36,38 +38,35 @@ specification that applies to your target broker/server.
36
38
  def initialize(client, name, opts = {})
37
39
  # check connection to server
38
40
  raise Bunny::ConnectionError, 'Not connected to server' if client.status == :not_connected
39
-
41
+
40
42
  @client, @name, @opts = client, name, opts
41
-
43
+
42
44
  # set up the exchange type catering for default names
43
- if name.match(/^amq\./)
44
- new_type = name.sub(/amq\./, '')
45
+ if name =~ /^amq\.(.+)$/
46
+ predeclared = true
47
+ new_type = $1
45
48
  # handle 'amq.match' default
46
49
  new_type = 'headers' if new_type == 'match'
47
50
  @type = new_type.to_sym
48
51
  else
49
52
  @type = opts[:type] || :direct
50
53
  end
51
-
54
+
52
55
  @key = opts[:key]
53
56
  @client.exchanges[@name] ||= self
54
-
57
+
55
58
  # ignore the :nowait option if passed, otherwise program will hang waiting for a
56
59
  # response that will not be sent by the server
57
60
  opts.delete(:nowait)
58
-
59
- unless name == "amq.#{type}" or name == ''
60
- client.send_frame(
61
- Qrack::Protocol::Exchange::Declare.new(
62
- { :exchange => name, :type => type, :nowait => false }.merge(opts)
63
- )
64
- )
65
61
 
66
- method = client.next_method
62
+ unless predeclared or name == ''
63
+ opts = { :exchange => name, :type => type, :nowait => false }.merge(opts)
64
+
65
+ client.send_frame(Qrack::Protocol::Exchange::Declare.new(opts))
67
66
 
68
- client.check_response(method, Qrack::Protocol::Exchange::DeclareOk,
69
- "Error declaring exchange #{name}: type = #{type}")
67
+ method = client.next_method
70
68
 
69
+ client.check_response(method, Qrack::Protocol::Exchange::DeclareOk, "Error declaring exchange #{name}: type = #{type}")
71
70
  end
72
71
  end
73
72
 
@@ -95,14 +94,11 @@ if successful. If an error occurs raises _Bunny_::_ProtocolError_.
95
94
  # response that will not be sent by the server
96
95
  opts.delete(:nowait)
97
96
 
98
- client.send_frame(
99
- Qrack::Protocol::Exchange::Delete.new({ :exchange => name, :nowait => false }.merge(opts))
100
- )
97
+ client.send_frame(Qrack::Protocol::Exchange::Delete.new({ :exchange => name, :nowait => false }.merge(opts)))
101
98
 
102
- method = client.next_method
99
+ method = client.next_method
103
100
 
104
- client.check_response(method, Qrack::Protocol::Exchange::DeleteOk,
105
- "Error deleting exchange #{name}")
101
+ client.check_response(method, Qrack::Protocol::Exchange::DeleteOk, "Error deleting exchange #{name}")
106
102
 
107
103
  client.exchanges.delete(name)
108
104
 
@@ -122,6 +118,7 @@ if any, is committed.
122
118
 
123
119
  * <tt>:key => 'routing_key'</tt> - Specifies the routing key for the message. The routing key is
124
120
  used for routing messages depending on the exchange configuration.
121
+ * <tt>:content_type => 'content/type'</tt> - Specifies the content type to use for the message.
125
122
  * <tt>:mandatory => true or false (_default_)</tt> - Tells the server how to react if the message
126
123
  cannot be routed to a queue. If set to _true_, the server will return an unroutable message
127
124
  with a Return method. If this flag is zero, the server silently drops the message.
@@ -130,8 +127,8 @@ if any, is committed.
130
127
  undeliverable message with a Return method. If set to _false_, the server will queue the message,
131
128
  but with no guarantee that it will ever be consumed.
132
129
  * <tt>:persistent => true or false (_default_)</tt> - Tells the server whether to persist the message
133
- If set to _true_, the message will be persisted to disk and not lost if the server restarts.
134
- If set to _false_, the message will not be persisted across server restart. Setting to _true_
130
+ If set to _true_, the message will be persisted to disk and not lost if the server restarts.
131
+ If set to _false_, the message will not be persisted across server restart. Setting to _true_
135
132
  incurs a performance penalty as there is an extra cost associated with disk access.
136
133
 
137
134
  ==== RETURNS:
@@ -144,25 +141,24 @@ nil
144
141
  opts = opts.dup
145
142
  out = []
146
143
 
147
- # Set up options
148
- routing_key = opts.delete(:key) || key
149
- mandatory = opts.delete(:mandatory)
150
- immediate = opts.delete(:immediate)
151
- delivery_mode = opts.delete(:persistent) ? 2 : 1
152
-
153
- out << Qrack::Protocol::Basic::Publish.new(
154
- { :exchange => name,
155
- :routing_key => routing_key,
156
- :mandatory => mandatory,
157
- :immediate => immediate }
158
- )
144
+ # Set up options
145
+ routing_key = opts.delete(:key) || key
146
+ mandatory = opts.delete(:mandatory)
147
+ immediate = opts.delete(:immediate)
148
+ delivery_mode = opts.delete(:persistent) ? 2 : 1
149
+ content_type = opts.delete(:content_type) || 'application/octet-stream'
150
+
151
+ out << Qrack::Protocol::Basic::Publish.new({ :exchange => name,
152
+ :routing_key => routing_key,
153
+ :mandatory => mandatory,
154
+ :immediate => immediate })
159
155
  data = data.to_s
160
156
  out << Qrack::Protocol::Header.new(
161
157
  Qrack::Protocol::Basic,
162
158
  data.bytesize, {
163
- :content_type => 'application/octet-stream',
159
+ :content_type => content_type,
164
160
  :delivery_mode => delivery_mode,
165
- :priority => 0
161
+ :priority => 0
166
162
  }.merge(opts)
167
163
  )
168
164
  out << Qrack::Transport::Body.new(data)
@@ -171,5 +167,5 @@ nil
171
167
  end
172
168
 
173
169
  end
174
-
170
+
175
171
  end
@@ -1,34 +1,29 @@
1
- module Bunny
2
-
3
- =begin rdoc
4
-
5
- === DESCRIPTION:
6
-
7
- *Exchanges* are the routing and distribution hub of AMQP. All messages that Bunny sends
8
- to an AMQP broker/server _have_ to pass through an exchange in order to be routed to a
9
- destination queue. The AMQP specification defines the types of exchange that you can create.
10
-
11
- At the time of writing there are four (4) types of exchange defined -
1
+ # encoding: utf-8
12
2
 
13
- * <tt>:direct</tt>
14
- * <tt>:fanout</tt>
15
- * <tt>:topic</tt>
16
- * <tt>:headers</tt>
17
-
18
- AMQP-compliant brokers/servers are required to provide default exchanges for the _direct_ and
19
- _fanout_ exchange types. All default exchanges are prefixed with <tt>'amq.'</tt>, for example -
20
-
21
- * <tt>amq.direct</tt>
22
- * <tt>amq.fanout</tt>
23
- * <tt>amq.topic</tt>
24
- * <tt>amq.match</tt> or <tt>amq.headers</tt>
25
-
26
- If you want more information about exchanges, please consult the documentation for your
27
- target broker/server or visit the {AMQP website}[http://www.amqp.org] to find the version of the
28
- specification that applies to your target broker/server.
3
+ module Bunny
29
4
 
30
- =end
31
-
5
+ # *Exchanges* are the routing and distribution hub of AMQP. All messages that Bunny sends
6
+ # to an AMQP broker/server @have_to pass through an exchange in order to be routed to a
7
+ # destination queue. The AMQP specification defines the types of exchange that you can create.
8
+ #
9
+ # At the time of writing there are four (4) types of exchange defined:
10
+ #
11
+ # * @:direct@
12
+ # * @:fanout@
13
+ # * @:topic@
14
+ # * @:headers@
15
+ #
16
+ # AMQP-compliant brokers/servers are required to provide default exchanges for the @direct@ and
17
+ # @fanout@ exchange types. All default exchanges are prefixed with @'amq.'@, for example:
18
+ #
19
+ # * @amq.direct@
20
+ # * @amq.fanout@
21
+ # * @amq.topic@
22
+ # * @amq.match@ or @amq.headers@
23
+ #
24
+ # If you want more information about exchanges, please consult the documentation for your
25
+ # target broker/server or visit the "AMQP website":http://www.amqp.org to find the version of the
26
+ # specification that applies to your target broker/server.
32
27
  class Exchange09
33
28
 
34
29
  attr_reader :client, :type, :name, :opts, :key
@@ -36,74 +31,63 @@ specification that applies to your target broker/server.
36
31
  def initialize(client, name, opts = {})
37
32
  # check connection to server
38
33
  raise Bunny::ConnectionError, 'Not connected to server' if client.status == :not_connected
39
-
34
+
40
35
  @client, @name, @opts = client, name, opts
41
-
36
+
42
37
  # set up the exchange type catering for default names
43
- if name.match(/^amq\./)
44
- new_type = name.sub(/amq\./, '')
38
+ if name =~ /^amq\.(.+)$/
39
+ predeclared = true
40
+ new_type = $1
45
41
  # handle 'amq.match' default
46
42
  new_type = 'headers' if new_type == 'match'
47
43
  @type = new_type.to_sym
48
44
  else
49
45
  @type = opts[:type] || :direct
50
46
  end
51
-
47
+
52
48
  @key = opts[:key]
53
49
  @client.exchanges[@name] ||= self
54
-
50
+
55
51
  # ignore the :nowait option if passed, otherwise program will hang waiting for a
56
52
  # response that will not be sent by the server
57
53
  opts.delete(:nowait)
58
-
59
- unless name == "amq.#{type}" or name == ''
60
- client.send_frame(
61
- Qrack::Protocol09::Exchange::Declare.new(
62
- { :exchange => name, :type => type, :nowait => false,
63
- :deprecated_ticket => 0, :deprecated_auto_delete => false, :deprecated_internal => false }.merge(opts)
64
- )
65
- )
54
+
55
+ unless predeclared or name == ''
56
+ opts = {
57
+ :exchange => name, :type => type, :nowait => false,
58
+ :deprecated_ticket => 0, :deprecated_auto_delete => false, :deprecated_internal => false
59
+ }.merge(opts)
60
+
61
+ client.send_frame(Qrack::Protocol09::Exchange::Declare.new(opts))
66
62
 
67
63
  method = client.next_method
68
64
 
69
- client.check_response(method, Qrack::Protocol09::Exchange::DeclareOk,
70
- "Error declaring exchange #{name}: type = #{type}")
71
-
65
+ client.check_response(method, Qrack::Protocol09::Exchange::DeclareOk, "Error declaring exchange #{name}: type = #{type}")
72
66
  end
73
67
  end
74
68
 
75
- =begin rdoc
76
-
77
- === DESCRIPTION:
78
-
79
- Requests that an exchange is deleted from broker/server. Removes reference from exchanges
80
- if successful. If an error occurs raises _Bunny_::_ProtocolError_.
81
-
82
- ==== Options:
83
-
84
- * <tt>:if_unused => true or false (_default_)</tt> - If set to _true_, the server will only
85
- delete the exchange if it has no queue bindings. If the exchange has queue bindings the
86
- server does not delete it but raises a channel exception instead.
87
- * <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
88
-
89
- ==== Returns:
90
-
91
- <tt>:delete_ok</tt> if successful
92
- =end
93
-
69
+ # Requests that an exchange is deleted from broker/server. Removes reference from exchanges
70
+ # if successful. If an error occurs raises {Bunny::ProtocolError}.
71
+ #
72
+ # @option opts [Boolean] :if_unused (false)
73
+ # If set to @true@, the server will only delete the exchange if it has no queue bindings. If the exchange has queue bindings the server does not delete it but raises a channel exception instead.
74
+ #
75
+ # @option opts [Boolean] :nowait (false)
76
+ # Ignored by Bunny, always @false@.
77
+ #
78
+ # @return [Symbol] @:delete_ok@ if successful.
94
79
  def delete(opts = {})
95
80
  # ignore the :nowait option if passed, otherwise program will hang waiting for a
96
81
  # response that will not be sent by the server
97
82
  opts.delete(:nowait)
98
83
 
99
- client.send_frame(
100
- Qrack::Protocol09::Exchange::Delete.new({ :exchange => name, :nowait => false, :deprecated_ticket => 0 }.merge(opts))
101
- )
84
+ opts = { :exchange => name, :nowait => false, :deprecated_ticket => 0 }.merge(opts)
85
+
86
+ client.send_frame(Qrack::Protocol09::Exchange::Delete.new(opts))
102
87
 
103
88
  method = client.next_method
104
89
 
105
- client.check_response(method, Qrack::Protocol09::Exchange::DeleteOk,
106
- "Error deleting exchange #{name}")
90
+ client.check_response(method, Qrack::Protocol09::Exchange::DeleteOk, "Error deleting exchange #{name}")
107
91
 
108
92
  client.exchanges.delete(name)
109
93
 
@@ -111,67 +95,65 @@ if successful. If an error occurs raises _Bunny_::_ProtocolError_.
111
95
  :delete_ok
112
96
  end
113
97
 
114
- =begin rdoc
115
-
116
- === DESCRIPTION:
117
-
118
- Publishes a message to a specific exchange. The message will be routed to queues as defined
119
- by the exchange configuration and distributed to any active consumers when the transaction,
120
- if any, is committed.
121
-
122
- ==== OPTIONS:
123
-
124
- * <tt>:key => 'routing_key'</tt> - Specifies the routing key for the message. The routing key is
125
- used for routing messages depending on the exchange configuration.
126
- * <tt>:mandatory => true or false (_default_)</tt> - Tells the server how to react if the message
127
- cannot be routed to a queue. If set to _true_, the server will return an unroutable message
128
- with a Return method. If this flag is zero, the server silently drops the message.
129
- * <tt>:immediate => true or false (_default_)</tt> - Tells the server how to react if the message
130
- cannot be routed to a queue consumer immediately. If set to _true_, the server will return an
131
- undeliverable message with a Return method. If set to _false_, the server will queue the message,
132
- but with no guarantee that it will ever be consumed.
133
- * <tt>:persistent => true or false (_default_)</tt> - Tells the server whether to persist the message
134
- If set to _true_, the message will be persisted to disk and not lost if the server restarts.
135
- If set to _false_, the message will not be persisted across server restart. Setting to _true_
136
- incurs a performance penalty as there is an extra cost associated with disk access.
137
-
138
- ==== RETURNS:
139
-
140
- nil
141
-
142
- =end
143
-
98
+ # Publishes a message to a specific exchange. The message will be routed to queues as defined
99
+ # by the exchange configuration and distributed to any active consumers when the transaction,
100
+ # if any, is committed.
101
+ #
102
+ # @option opts [String] :key
103
+ # Specifies the routing key for the message. The routing key is
104
+ # used for routing messages depending on the exchange configuration.
105
+ #
106
+ # @option opts [String] :content_type
107
+ # Specifies the content type for the message.
108
+ #
109
+ # @option opts [Boolean] :mandatory (false)
110
+ # Tells the server how to react if the message cannot be routed to a queue.
111
+ # If set to @true@, the server will return an unroutable message
112
+ # with a Return method. If this flag is zero, the server silently drops the message.
113
+ #
114
+ # @option opts [Boolean] :immediate (false)
115
+ # Tells the server how to react if the message cannot be routed to a queue consumer
116
+ # immediately. If set to @true@, the server will return an undeliverable message with
117
+ # a Return method. If set to @false@, the server will queue the message, but with no
118
+ # guarantee that it will ever be consumed.
119
+ #
120
+ # @option opts [Boolean] :persistent (false)
121
+ # Tells the server whether to persist the message. If set to @true@, the message will
122
+ # be persisted to disk and not lost if the server restarts. If set to @false@, the message
123
+ # will not be persisted across server restart. Setting to @true@ incurs a performance penalty
124
+ # as there is an extra cost associated with disk access.
125
+ #
126
+ # @return [NilClass] nil
144
127
  def publish(data, opts = {})
145
128
  opts = opts.dup
146
129
  out = []
147
130
 
148
- # Set up options
149
- routing_key = opts.delete(:key) || key
150
- mandatory = opts.delete(:mandatory)
151
- immediate = opts.delete(:immediate)
152
- delivery_mode = opts.delete(:persistent) ? 2 : 1
153
-
154
- out << Qrack::Protocol09::Basic::Publish.new(
155
- { :exchange => name,
156
- :routing_key => routing_key,
157
- :mandatory => mandatory,
158
- :immediate => immediate,
159
- :deprecated_ticket => 0 }
160
- )
161
- data = data.to_s
162
- out << Qrack::Protocol09::Header.new(
163
- Qrack::Protocol09::Basic,
164
- data.bytesize, {
165
- :content_type => 'application/octet-stream',
166
- :delivery_mode => delivery_mode,
167
- :priority => 0
168
- }.merge(opts)
169
- )
170
- out << Qrack::Transport09::Body.new(data)
131
+ # Set up options
132
+ routing_key = opts.delete(:key) || key
133
+ mandatory = opts.delete(:mandatory)
134
+ immediate = opts.delete(:immediate)
135
+ delivery_mode = opts.delete(:persistent) ? 2 : 1
136
+ content_type = opts.delete(:content_type) || 'application/octet-stream'
137
+
138
+ out << Qrack::Protocol09::Basic::Publish.new({ :exchange => name,
139
+ :routing_key => routing_key,
140
+ :mandatory => mandatory,
141
+ :immediate => immediate,
142
+ :deprecated_ticket => 0 })
143
+ data = data.to_s
144
+ out << Qrack::Protocol09::Header.new(
145
+ Qrack::Protocol09::Basic,
146
+ data.bytesize, {
147
+ :content_type => content_type,
148
+ :delivery_mode => delivery_mode,
149
+ :priority => 0
150
+ }.merge(opts)
151
+ )
152
+ out << Qrack::Transport09::Body.new(data)
171
153
 
172
154
  client.send_frame(*out)
173
155
  end
174
156
 
175
157
  end
176
-
158
+
177
159
  end