bunny 0.6.3.rc2 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,5 +1,7 @@
1
+ # encoding: utf-8
2
+
1
3
  module Bunny
2
-
4
+
3
5
  =begin rdoc
4
6
 
5
7
  === DESCRIPTION:
@@ -27,10 +29,10 @@ processing. If error occurs, _Bunny_::_ProtocolError_ is raised.
27
29
 
28
30
  ==== OPERATION:
29
31
 
30
- Passes a hash of message information to the block, if one has been supplied. The hash contains
32
+ Passes a hash of message information to the block, if one has been supplied. The hash contains
31
33
  :header, :payload and :delivery_details. The structure of the data is as follows -
32
34
 
33
- :header has instance variables -
35
+ :header has instance variables -
34
36
  @klass
35
37
  @size
36
38
  @weight
@@ -45,7 +47,7 @@ Passes a hash of message information to the block, if one has been supplied. The
45
47
  :consumer_tag
46
48
  :delivery_tag
47
49
  :redelivered
48
- :exchange
50
+ :exchange
49
51
  :routing_key
50
52
 
51
53
  If the :timeout option is specified then Qrack::ClientTimeout is raised if method times out
@@ -58,28 +60,27 @@ my_queue.subscribe(:timeout => 5) {|msg| puts msg[:payload]}
58
60
  my_queue.subscribe(:message_max => 10, :ack => true) {|msg| puts msg[:payload]}
59
61
 
60
62
  =end
61
-
62
- class Subscription < Qrack::Subscription
63
-
64
-
65
- def setup_consumer
66
- client.send_frame(
67
- Qrack::Protocol::Basic::Consume.new({ :queue => queue.name,
68
- :consumer_tag => consumer_tag,
69
- :no_ack => !ack,
70
- :exclusive => exclusive,
71
- :nowait => false }.merge(@opts))
72
- )
73
-
74
- method = client.next_method
75
-
76
- client.check_response(method, Qrack::Protocol::Basic::ConsumeOk,
77
- "Error subscribing to queue #{queue.name}")
78
-
79
- @consumer_tag = method.consumer_tag
80
-
81
- end
82
-
83
- end
84
-
85
- end
63
+
64
+ class Subscription < Bunny::Consumer
65
+
66
+ def setup_consumer
67
+ subscription_options = {
68
+ :queue => queue.name,
69
+ :consumer_tag => consumer_tag,
70
+ :no_ack => !ack,
71
+ :exclusive => exclusive,
72
+ :nowait => false
73
+ }.merge(@opts)
74
+
75
+ client.send_frame(Qrack::Protocol::Basic::Consume.new(subscription_options))
76
+
77
+ method = client.next_method
78
+
79
+ client.check_response(method, Qrack::Protocol::Basic::ConsumeOk, "Error subscribing to queue #{queue.name}")
80
+
81
+ @consumer_tag = method.consumer_tag
82
+ end
83
+
84
+ end
85
+
86
+ end
@@ -1,85 +1,86 @@
1
- module Bunny
2
-
3
- =begin rdoc
4
-
5
- === DESCRIPTION:
6
-
7
- Asks the server to start a "consumer", which is a transient request for messages from a specific
8
- queue. Consumers last as long as the channel they were created on, or until the client cancels them
9
- with an _unsubscribe_. Every time a message reaches the queue it is passed to the _blk_ for
10
- processing. If error occurs, _Bunny_::_ProtocolError_ is raised.
11
-
12
- ==== OPTIONS:
13
- * <tt>:consumer_tag => '_tag_'</tt> - Specifies the identifier for the consumer. The consumer tag is
14
- local to a connection, so two clients can use the same consumer tags. If this option is not
15
- specified a server generated name is used.
16
- * <tt>:ack => false (_default_) or true</tt> - If set to _false_, the server does not expect an
17
- acknowledgement message from the client. If set to _true_, the server expects an acknowledgement
18
- message from the client and will re-queue the message if it does not receive one within a time specified
19
- by the server.
20
- * <tt>:exclusive => true or false (_default_)</tt> - Request exclusive consumer access, meaning
21
- only this consumer can access the queue.
22
- * <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
23
- * <tt>:timeout => number of seconds - The subscribe loop will continue to wait for
24
- messages until terminated (Ctrl-C or kill command) or this timeout interval is reached.
25
- * <tt>:message_max => max number messages to process</tt> - When the required number of messages
26
- is processed subscribe loop is exited.
27
-
28
- ==== OPERATION:
29
-
30
- Passes a hash of message information to the block, if one has been supplied. The hash contains
31
- :header, :payload and :delivery_details. The structure of the data is as follows -
32
-
33
- :header has instance variables -
34
- @klass
35
- @size
36
- @weight
37
- @properties is a hash containing -
38
- :content_type
39
- :delivery_mode
40
- :priority
41
-
42
- :payload contains the message contents
1
+ # encoding: utf-8
43
2
 
44
- :delivery details is a hash containing -
45
- :consumer_tag
46
- :delivery_tag
47
- :redelivered
48
- :exchange
49
- :routing_key
50
-
51
- If the :timeout option is specified then Qrack::ClientTimeout is raised if method times out
52
- waiting to receive the next message from the queue.
53
-
54
- ==== EXAMPLES
55
-
56
- my_queue.subscribe(:timeout => 5) {|msg| puts msg[:payload]}
57
-
58
- my_queue.subscribe(:message_max => 10, :ack => true) {|msg| puts msg[:payload]}
59
-
60
- =end
61
-
62
- class Subscription09 < Qrack::Subscription
63
-
64
- def setup_consumer
65
- client.send_frame(
66
- Qrack::Protocol09::Basic::Consume.new({ :deprecated_ticket => 0,
67
- :queue => queue.name,
68
- :consumer_tag => consumer_tag,
69
- :no_ack => !ack,
70
- :exclusive => exclusive,
71
- :nowait => false}.merge(@opts))
72
- )
73
-
74
- method = client.next_method
75
-
76
- client.check_response(method, Qrack::Protocol09::Basic::ConsumeOk,
77
- "Error subscribing to queue #{queue.name}")
3
+ module Bunny
78
4
 
79
- @consumer_tag = method.consumer_tag
80
-
81
- end
82
-
83
- end
84
-
85
- end
5
+ # Asks the server to start a "consumer", which is a transient request for messages from a specific
6
+ # queue. Consumers last as long as the channel they were created on, or until the client cancels them
7
+ # with an @unsubscribe@. Every time a message reaches the queue it is passed to the @blk@ for
8
+ # processing. If error occurs, {Bunny::ProtocolError} is raised.
9
+ #
10
+ # @option opts [String] :consumer_tag
11
+ # Specifies the identifier for the consumer. The consumer tag is
12
+ # local to a connection, so two clients can use the same consumer tags.
13
+ # If this option is not specified a server generated name is used.
14
+ #
15
+ # @option opts [Boolean] :ack (false)
16
+ # If set to @false@, the server does not expect an acknowledgement message
17
+ # from the client. If set to @true, the server expects an acknowledgement
18
+ # message from the client and will re-queue the message if it does not
19
+ # receive one within a time specified by the server.
20
+ #
21
+ # @option opts [Boolean] :exclusive (false)
22
+ # Request exclusive consumer access, meaning only this consumer can access the queue.
23
+ #
24
+ # @option opts [Boolean] :nowait (false)
25
+ # Ignored by Bunny, always @false@.
26
+ #
27
+ # @option opts [Numeric] :timeout
28
+ # The subscribe loop will continue to wait for messages
29
+ # until terminated (Ctrl-C or kill command) or this timeout interval is reached.
30
+ #
31
+ # @option opts [Integer] :message_max
32
+ # When the required number of messages is processed subscribe loop is exited.
33
+ #
34
+ # h2. Operation
35
+ #
36
+ # Passes a hash of message information to the block, if one has been supplied. The hash contains
37
+ # :header, :payload and :delivery_details. The structure of the data is as follows -
38
+ #
39
+ # :header has instance variables -
40
+ # @klass
41
+ # @size
42
+ # @weight
43
+ # @properties is a hash containing -
44
+ # :content_type
45
+ # :delivery_mode
46
+ # :priority
47
+ #
48
+ # :payload contains the message contents
49
+ #
50
+ # :delivery details is a hash containing -
51
+ # :consumer_tag
52
+ # :delivery_tag
53
+ # :redelivered
54
+ # :exchange
55
+ # :routing_key
56
+ #
57
+ # If the :timeout option is specified then Qrack::ClientTimeout is raised if method times out
58
+ # waiting to receive the next message from the queue.
59
+ #
60
+ # @example
61
+ # my_queue.subscribe(timeout: 5) { |msg| puts msg[:payload] }
62
+ # my_queue.subscribe(message_max: 10, ack: true) { |msg| puts msg[:payload] }
63
+ class Subscription09 < Bunny::Consumer
64
+
65
+ def setup_consumer
66
+ subscription_options = {
67
+ :deprecated_ticket => 0,
68
+ :queue => queue.name,
69
+ :consumer_tag => consumer_tag,
70
+ :no_ack => !ack,
71
+ :exclusive => exclusive,
72
+ :nowait => false
73
+ }.merge(@opts)
74
+
75
+ client.send_frame(Qrack::Protocol09::Basic::Consume.new(subscription_options))
76
+
77
+ method = client.next_method
78
+
79
+ client.check_response(method, Qrack::Protocol09::Basic::ConsumeOk, "Error subscribing to queue #{queue.name}")
80
+
81
+ @consumer_tag = method.consumer_tag
82
+ end
83
+
84
+ end
85
+
86
+ end
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ module Bunny
4
+ VERSION = "0.7"
5
+ end
@@ -0,0 +1,165 @@
1
+ # encoding: utf-8
2
+
3
+ ################################################################
4
+ # DO NOT EDIT THIS FILE ! #
5
+ # The file comes from https://github.com/ruby-amqp/amq-client, #
6
+ # it's located in lib/amq/client/settings.rb, so if you want #
7
+ # to make some changes, please do them in the amq-client repo. #
8
+ ################################################################
9
+
10
+ # TODO: When we start to work on porting Bunny on AMQ Client,
11
+ # this file will become obsolete.
12
+
13
+ require "uri"
14
+
15
+ module AMQ
16
+ module Client
17
+ # @see AMQ::Client::Settings.configure
18
+ module Settings
19
+ # @private
20
+ AMQP_PORTS = {"amqp" => 5672, "amqps" => 5671}.freeze
21
+
22
+ # @private
23
+ AMQPS = "amqps".freeze
24
+
25
+ # Default connection settings used by AMQ clients
26
+ #
27
+ # @see AMQ::Client::Settings.configure
28
+ def self.default
29
+ @default ||= {
30
+ # server
31
+ :host => "127.0.0.1",
32
+ :port => AMQ::Protocol::DEFAULT_PORT,
33
+
34
+ # login
35
+ :user => "guest",
36
+ :pass => "guest",
37
+ :vhost => "/",
38
+
39
+ # connection timeout
40
+ :timeout => nil,
41
+
42
+ # logging
43
+ :logging => false,
44
+
45
+ # ssl
46
+ :ssl => false,
47
+
48
+ # broker
49
+ # if you want to load broker-specific extensions
50
+ :broker => nil,
51
+
52
+ :frame_max => 131072
53
+ }
54
+ end
55
+
56
+
57
+ def self.client_properties
58
+ @client_properties ||= {
59
+ :platform => ::RUBY_DESCRIPTION,
60
+ :product => "AMQ Client",
61
+ :information => "http://github.com/ruby-amqp/amq-client",
62
+ :version => AMQ::Client::VERSION
63
+ }
64
+ end
65
+
66
+
67
+ # Merges given configuration parameters with defaults and returns
68
+ # the result.
69
+ #
70
+ # @param [Hash] Configuration parameters to use.
71
+ #
72
+ # @option settings [String] :host ("127.0.0.1") Hostname AMQ broker runs on.
73
+ # @option settings [String] :port (5672) Port AMQ broker listens on.
74
+ # @option settings [String] :vhost ("/") Virtual host to use.
75
+ # @option settings [String] :user ("guest") Username to use for authentication.
76
+ # @option settings [String] :pass ("guest") Password to use for authentication.
77
+ # @option settings [String] :ssl (false) Should be use TLS (SSL) for connection?
78
+ # @option settings [String] :timeout (nil) Connection timeout.
79
+ # @option settings [String] :logging (false) Turns logging on or off.
80
+ # @option settings [String] :broker (nil) Broker name (use if you intend to use broker-specific features).
81
+ # @option settings [Fixnum] :frame_max (131072) Maximum frame size to use. If broker cannot support frames this large, broker's maximum value will be used instead.
82
+ #
83
+ # @return [Hash] Merged configuration parameters.
84
+ def self.configure(settings = nil)
85
+ case settings
86
+ when Hash then
87
+ if username = settings.delete(:username)
88
+ settings[:user] ||= username
89
+ end
90
+
91
+ if password = settings.delete(:password)
92
+ settings[:pass] ||= password
93
+ end
94
+
95
+
96
+ self.default.merge(settings)
97
+ when String then
98
+ settings = self.parse_amqp_url(settings)
99
+ self.default.merge(settings)
100
+ when NilClass then
101
+ self.default
102
+ end
103
+ end
104
+
105
+ # Parses AMQP connection URI and returns its components as a hash.
106
+ #
107
+ # h2. vhost naming schemes
108
+ #
109
+ # It is convenient to be able to specify the AMQP connection
110
+ # parameters as a URI string, and various "amqp" URI schemes
111
+ # exist. Unfortunately, there is no standard for these URIs, so
112
+ # while the schemes share the basic idea, they differ in some
113
+ # details. This implementation aims to encourage URIs that work
114
+ # as widely as possible.
115
+ #
116
+ # The URI scheme should be "amqp", or "amqps" if SSL is required.
117
+ #
118
+ # The host, port, username and password are represented in the
119
+ # authority component of the URI in the same way as in http URIs.
120
+ #
121
+ # The vhost is obtained from the first segment of the path, with the
122
+ # leading slash removed. The path should contain only a single
123
+ # segment (i.e, the only slash in it should be the leading one).
124
+ # If the vhost is to include slashes or other reserved URI
125
+ # characters, these should be percent-escaped.
126
+ #
127
+ # @example How vhost is parsed
128
+ #
129
+ # AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com") # => vhost is nil, so default (/) will be used
130
+ # AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/") # => vhost is an empty string
131
+ # AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/%2Fvault") # => vhost is /vault
132
+ # AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/production") # => vhost is production
133
+ # AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/a.b.c") # => vhost is a.b.c
134
+ # AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/foo/bar") # => ArgumentError
135
+ #
136
+ #
137
+ # @param [String] connection_string AMQP connection URI, à la JDBC connection string. For example: amqp://bus.megacorp.internal:5877.
138
+ # @return [Hash] Connection parameters (:username, :password, :vhost, :host, :port, :ssl)
139
+ #
140
+ # @raise [ArgumentError] When connection URI schema is not amqp or amqps, or the path contains multiple segments
141
+ #
142
+ # @see http://bit.ly/ks8MXK Connecting to The Broker documentation guide
143
+ # @api public
144
+ def self.parse_amqp_url(connection_string)
145
+ uri = URI.parse(connection_string)
146
+ raise ArgumentError.new("Connection URI must use amqp or amqps schema (example: amqp://bus.megacorp.internal:5766), learn more at http://bit.ly/ks8MXK") unless %w{amqp amqps}.include?(uri.scheme)
147
+
148
+ opts = {}
149
+
150
+ opts[:scheme] = uri.scheme
151
+ opts[:user] = URI.unescape(uri.user) if uri.user
152
+ opts[:pass] = URI.unescape(uri.password) if uri.password
153
+ opts[:host] = uri.host if uri.host
154
+ opts[:port] = uri.port || AMQ::Client::Settings::AMQP_PORTS[uri.scheme]
155
+ opts[:ssl] = uri.scheme == AMQ::Client::Settings::AMQPS
156
+ if uri.path =~ %r{^/(.*)}
157
+ raise ArgumentError.new("#{uri} has multiple-segment path; please percent-encode any slashes in the vhost name (e.g. /production => %2Fproduction). Learn more at http://bit.ly/amqp-gem-and-connection-uris") if $1.index('/')
158
+ opts[:vhost] = URI.unescape($1)
159
+ end
160
+
161
+ opts
162
+ end
163
+ end
164
+ end
165
+ end
@@ -1,18 +1,20 @@
1
+ # encoding: utf-8
2
+
1
3
  module Qrack
2
- # Channel ancestor class
3
- class Channel
4
-
5
- attr_accessor :number, :active, :frame_buffer
6
- attr_reader :client
7
-
8
- def initialize(client)
9
- @frame_buffer = []
10
- @client = client
11
- @number = client.channels.size
12
- @active = false
13
- client.channels[@number] = self
14
- end
15
-
16
- end
17
-
18
- end
4
+ # Channel ancestor class
5
+ class Channel
6
+
7
+ attr_accessor :number, :active, :frame_buffer
8
+ attr_reader :client
9
+
10
+ def initialize(client)
11
+ @frame_buffer = []
12
+ @client = client
13
+ @number = client.channels.size
14
+ @active = false
15
+ client.channels[@number] = self
16
+ end
17
+
18
+ end
19
+
20
+ end