bunny 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/{README → README.rdoc} +9 -2
  2. data/bunny.gemspec +12 -7
  3. data/examples/simple_08.rb +1 -1
  4. data/examples/simple_09.rb +1 -1
  5. data/examples/simple_ack_08.rb +1 -1
  6. data/examples/simple_ack_09.rb +1 -1
  7. data/examples/simple_consumer_08.rb +6 -14
  8. data/examples/simple_consumer_09.rb +6 -14
  9. data/examples/simple_fanout_08.rb +2 -2
  10. data/examples/simple_fanout_09.rb +2 -2
  11. data/examples/simple_headers_08.rb +1 -1
  12. data/examples/simple_headers_09.rb +1 -1
  13. data/examples/simple_topic_08.rb +4 -4
  14. data/examples/simple_topic_09.rb +4 -4
  15. data/lib/bunny.rb +23 -15
  16. data/lib/bunny/channel08.rb +8 -2
  17. data/lib/bunny/channel09.rb +8 -2
  18. data/lib/bunny/client08.rb +67 -24
  19. data/lib/bunny/client09.rb +88 -48
  20. data/lib/bunny/exchange08.rb +55 -43
  21. data/lib/bunny/exchange09.rb +67 -54
  22. data/lib/bunny/queue08.rb +79 -137
  23. data/lib/bunny/queue09.rb +79 -141
  24. data/lib/bunny/subscription08.rb +85 -0
  25. data/lib/bunny/subscription09.rb +85 -0
  26. data/lib/qrack/client.rb +29 -10
  27. data/lib/qrack/protocol/spec08.rb +1 -0
  28. data/lib/qrack/protocol/spec09.rb +1 -0
  29. data/lib/qrack/qrack08.rb +1 -0
  30. data/lib/qrack/qrack09.rb +1 -0
  31. data/lib/qrack/queue.rb +1 -1
  32. data/lib/qrack/subscription.rb +102 -0
  33. data/spec/spec_08/bunny_spec.rb +6 -0
  34. data/spec/spec_08/connection_spec.rb +12 -0
  35. data/spec/spec_08/exchange_spec.rb +19 -3
  36. data/spec/spec_08/queue_spec.rb +87 -13
  37. data/spec/spec_09/bunny_spec.rb +7 -1
  38. data/spec/spec_09/connection_spec.rb +12 -0
  39. data/spec/spec_09/exchange_spec.rb +19 -3
  40. data/spec/spec_09/queue_spec.rb +94 -21
  41. metadata +11 -6
@@ -20,10 +20,15 @@ Sets up a Bunny::Client object ready for connection to a broker/server. _Client_
20
20
  ==== OPTIONS:
21
21
 
22
22
  * <tt>:host => '_hostname_' (default = 'localhost')</tt>
23
- * <tt>:port => _portno_ (default = 5672)</tt>
23
+ * <tt>:port => _portno_ (default = 5672 or 5671 if :ssl set to true)</tt>
24
24
  * <tt>:vhost => '_vhostname_' (default = '/')</tt>
25
25
  * <tt>:user => '_username_' (default = 'guest')</tt>
26
26
  * <tt>:pass => '_password_' (default = 'guest')</tt>
27
+ * <tt>:ssl => true or false (default = false)</tt> - If set to _true_, ssl
28
+ encryption will be used and port will default to 5671.
29
+ * <tt>:verify_ssl => true or false (default = true)</tt> - If ssl is enabled,
30
+ this will cause OpenSSL to validate the server certificate unless this
31
+ parameter is set to _false_.
27
32
  * <tt>:logfile => '_logfilepath_' (default = nil)</tt>
28
33
  * <tt>:logging => true or false (_default_)</tt> - If set to _true_, session information is sent
29
34
  to STDOUT if <tt>:logfile</tt> has not been specified. Otherwise, session information is written to
@@ -31,15 +36,48 @@ Sets up a Bunny::Client object ready for connection to a broker/server. _Client_
31
36
  * <tt>:frame_max => maximum frame size in bytes (default = 131072)</tt>
32
37
  * <tt>:channel_max => maximum number of channels (default = 0 no maximum)</tt>
33
38
  * <tt>:heartbeat => number of seconds (default = 0 no heartbeat)</tt>
39
+ * <tt>:connect_timeout => number of seconds before Qrack::ConnectionTimeout is raised (default = 5)</tt>
34
40
 
35
41
  =end
36
42
 
37
43
  def initialize(opts = {})
38
44
  super
39
45
  @spec = '0-9-1'
40
- @port = opts[:port] || Qrack::Protocol09::PORT
46
+ @port = opts[:port] || (opts[:ssl] ? Qrack::Protocol09::SSL_PORT : Qrack::Protocol09::PORT)
41
47
  end
42
48
 
49
+ =begin rdoc
50
+
51
+ === DESCRIPTION:
52
+
53
+ Checks response from AMQP methods and takes appropriate action
54
+
55
+ =end
56
+
57
+ def check_response(received_method, expected_method, err_msg, err_class = Bunny::ProtocolError)
58
+ case
59
+ when received_method.is_a?(Qrack::Protocol09::Connection::Close)
60
+ # Clean up the socket
61
+ close_socket
62
+
63
+ raise Bunny::ForcedConnectionCloseError,
64
+ "Error Reply Code: #{received_method.reply_code}\nError Reply Text: #{received_method.reply_text}"
65
+
66
+ when received_method.is_a?(Qrack::Protocol09::Channel::Close)
67
+ # Clean up the channel
68
+ channel.active = false
69
+
70
+ raise Bunny::ForcedChannelCloseError,
71
+ "Error Reply Code: #{received_method.reply_code}\nError Reply Text: #{received_method.reply_text}"
72
+
73
+ when !received_method.is_a?(expected_method)
74
+ raise err_class, err_msg
75
+
76
+ else
77
+ :response_ok
78
+ end
79
+ end
80
+
43
81
  def close_connection
44
82
  # Set client channel to zero
45
83
  switch_channel(0)
@@ -47,7 +85,11 @@ Sets up a Bunny::Client object ready for connection to a broker/server. _Client_
47
85
  send_frame(
48
86
  Qrack::Protocol09::Connection::Close.new(:reply_code => 200, :reply_text => 'Goodbye', :class_id => 0, :method_id => 0)
49
87
  )
50
- raise Bunny::ProtocolError, "Error closing connection" unless next_method.is_a?(Qrack::Protocol09::Connection::CloseOk)
88
+
89
+ method = next_method
90
+
91
+ check_response(method, Qrack::Protocol09::Connection::CloseOk, "Error closing connection")
92
+
51
93
  end
52
94
 
53
95
  def create_channel
@@ -86,8 +128,7 @@ Exchange
86
128
  =end
87
129
 
88
130
  def exchange(name, opts = {})
89
- return exchanges[name] if exchanges.has_key?(name)
90
- exchanges[name] ||= Bunny::Exchange09.new(self, name, opts)
131
+ exchanges[name] || Bunny::Exchange09.new(self, name, opts)
91
132
  end
92
133
 
93
134
  def init_connection
@@ -135,6 +176,34 @@ Exchange
135
176
 
136
177
  end
137
178
 
179
+ def open_connection
180
+ send_frame(
181
+ Qrack::Protocol09::Connection::StartOk.new(
182
+ :client_properties => {:platform => 'Ruby', :product => 'Bunny', :information => 'http://github.com/celldee/bunny', :version => VERSION},
183
+ :mechanism => 'PLAIN',
184
+ :response => "\0" + @user + "\0" + @pass,
185
+ :locale => 'en_US'
186
+ )
187
+ )
188
+
189
+ frame = next_frame
190
+ raise Bunny::ProtocolError, "Connection failed - user: #{@user}" if frame.nil?
191
+
192
+ method = frame.payload
193
+
194
+ if method.is_a?(Qrack::Protocol09::Connection::Tune)
195
+ send_frame(
196
+ Qrack::Protocol09::Connection::TuneOk.new( :channel_max => @channel_max, :frame_max => @frame_max, :heartbeat => @heartbeat)
197
+ )
198
+ end
199
+
200
+ send_frame(
201
+ Qrack::Protocol09::Connection::Open.new(:virtual_host => @vhost, :reserved_1 => 0, :reserved_2 => false)
202
+ )
203
+
204
+ raise Bunny::ProtocolError, 'Cannot open connection' unless next_method.is_a?(Qrack::Protocol09::Connection::OpenOk)
205
+ end
206
+
138
207
  =begin rdoc
139
208
 
140
209
  === DESCRIPTION:
@@ -173,9 +242,9 @@ true, they are applied to the entire connection.
173
242
  Qrack::Protocol09::Basic::Qos.new({ :prefetch_size => 0, :prefetch_count => 1, :global => false }.merge(opts))
174
243
  )
175
244
 
176
- raise Bunny::ProtocolError,
177
- "Error specifying Quality of Service" unless
178
- next_method.is_a?(Qrack::Protocol09::Basic::QosOk)
245
+ method = next_method
246
+
247
+ check_response(method, Qrack::Protocol09::Basic::QosOk, "Error specifying Quality of Service")
179
248
 
180
249
  # return confirmation
181
250
  :qos_ok
@@ -221,9 +290,8 @@ Queue
221
290
  name = nil
222
291
  end
223
292
 
224
- return queues[name] if queues.has_key?(name)
225
-
226
- Bunny::Queue09.new(self, name, opts)
293
+ # Queue is responsible for placing itself in the list of queues
294
+ queues[name] || Bunny::Queue09.new(self, name, opts)
227
295
  end
228
296
 
229
297
  =begin rdoc
@@ -326,9 +394,9 @@ after a commit.
326
394
  def tx_commit
327
395
  send_frame(Qrack::Protocol09::Tx::Commit.new())
328
396
 
329
- raise Bunny::ProtocolError,
330
- "Error commiting transaction" unless
331
- next_method.is_a?(Qrack::Protocol09::Tx::CommitOk)
397
+ method = next_method
398
+
399
+ check_response(method, Qrack::Protocol09::Tx::CommitOk, "Error commiting transaction")
332
400
 
333
401
  # return confirmation
334
402
  :commit_ok
@@ -350,9 +418,9 @@ after a rollback.
350
418
  def tx_rollback
351
419
  send_frame(Qrack::Protocol09::Tx::Rollback.new())
352
420
 
353
- raise Bunny::ProtocolError,
354
- "Error rolling back transaction" unless
355
- next_method.is_a?(Qrack::Protocol09::Tx::RollbackOk)
421
+ method = next_method
422
+
423
+ check_response(method, Qrack::Protocol09::Tx::RollbackOk, "Error rolling back transaction")
356
424
 
357
425
  # return confirmation
358
426
  :rollback_ok
@@ -374,41 +442,13 @@ using the Commit or Rollback methods.
374
442
  def tx_select
375
443
  send_frame(Qrack::Protocol09::Tx::Select.new())
376
444
 
377
- raise Bunny::ProtocolError,
378
- "Error initiating transactions for current channel" unless
379
- next_method.is_a?(Qrack::Protocol09::Tx::SelectOk)
445
+ method = next_method
446
+
447
+ check_response(method, Qrack::Protocol::Tx::SelectOk, "Error initiating transactions for current channel")
380
448
 
381
449
  # return confirmation
382
450
  :select_ok
383
451
  end
384
-
385
- def open_connection
386
- send_frame(
387
- Qrack::Protocol09::Connection::StartOk.new(
388
- :client_properties => {:platform => 'Ruby', :product => 'Bunny', :information => 'http://github.com/celldee/bunny', :version => VERSION},
389
- :mechanism => 'PLAIN',
390
- :response => "\0" + @user + "\0" + @pass,
391
- :locale => 'en_US'
392
- )
393
- )
394
-
395
- frame = next_frame
396
- raise Bunny::ProtocolError, "Connection failed - user: #{@user}, pass: #{@pass}" if frame.nil?
397
-
398
- method = frame.payload
399
-
400
- if method.is_a?(Qrack::Protocol09::Connection::Tune)
401
- send_frame(
402
- Qrack::Protocol09::Connection::TuneOk.new( :channel_max => @channel_max, :frame_max => @frame_max, :heartbeat => @heartbeat)
403
- )
404
- end
405
-
406
- send_frame(
407
- Qrack::Protocol09::Connection::Open.new(:virtual_host => @vhost, :reserved_1 => 0, :reserved_2 => false)
408
- )
409
-
410
- raise Bunny::ProtocolError, 'Cannot open connection' unless next_method.is_a?(Qrack::Protocol09::Connection::OpenOk)
411
- end
412
452
 
413
453
  private
414
454
 
@@ -63,9 +63,11 @@ specification that applies to your target broker/server.
63
63
  )
64
64
  )
65
65
 
66
- raise Bunny::ProtocolError,
67
- "Error declaring exchange #{name}: type = #{type}" unless
68
- client.next_method.is_a?(Qrack::Protocol::Exchange::DeclareOk)
66
+ method = client.next_method
67
+
68
+ client.check_response(method, Qrack::Protocol::Exchange::DeclareOk,
69
+ "Error declaring exchange #{name}: type = #{type}")
70
+
69
71
  end
70
72
  end
71
73
 
@@ -73,6 +75,45 @@ specification that applies to your target broker/server.
73
75
 
74
76
  === DESCRIPTION:
75
77
 
78
+ Requests that an exchange is deleted from broker/server. Removes reference from exchanges
79
+ if successful. If an error occurs raises _Bunny_::_ProtocolError_.
80
+
81
+ ==== Options:
82
+
83
+ * <tt>:if_unused => true or false (_default_)</tt> - If set to _true_, the server will only
84
+ delete the exchange if it has no queue bindings. If the exchange has queue bindings the
85
+ server does not delete it but raises a channel exception instead.
86
+ * <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
87
+
88
+ ==== Returns:
89
+
90
+ <tt>:delete_ok</tt> if successful
91
+ =end
92
+
93
+ def delete(opts = {})
94
+ # ignore the :nowait option if passed, otherwise program will hang waiting for a
95
+ # response that will not be sent by the server
96
+ opts.delete(:nowait)
97
+
98
+ client.send_frame(
99
+ Qrack::Protocol::Exchange::Delete.new({ :exchange => name, :nowait => false }.merge(opts))
100
+ )
101
+
102
+ method = client.next_method
103
+
104
+ client.check_response(method, Qrack::Protocol::Exchange::DeleteOk,
105
+ "Error deleting exchange #{name}")
106
+
107
+ client.exchanges.delete(name)
108
+
109
+ # return confirmation
110
+ :delete_ok
111
+ end
112
+
113
+ =begin rdoc
114
+
115
+ === DESCRIPTION:
116
+
76
117
  Publishes a message to a specific exchange. The message will be routed to queues as defined
77
118
  by the exchange configuration and distributed to any active consumers when the transaction,
78
119
  if any, is committed.
@@ -103,15 +144,24 @@ nil
103
144
  opts = opts.dup
104
145
  out = []
105
146
 
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
+
106
153
  out << Qrack::Protocol::Basic::Publish.new(
107
- { :exchange => name, :routing_key => opts.delete(:key) || key }.merge(opts)
154
+ { :exchange => name,
155
+ :routing_key => routing_key,
156
+ :mandatory => mandatory,
157
+ :immediate => immediate }
108
158
  )
109
159
  data = data.to_s
110
160
  out << Qrack::Protocol::Header.new(
111
161
  Qrack::Protocol::Basic,
112
162
  data.length, {
113
163
  :content_type => 'application/octet-stream',
114
- :delivery_mode => (opts.delete(:persistent) ? 2 : 1),
164
+ :delivery_mode => delivery_mode,
115
165
  :priority => 0
116
166
  }.merge(opts)
117
167
  )
@@ -120,44 +170,6 @@ nil
120
170
  client.send_frame(*out)
121
171
  end
122
172
 
123
- =begin rdoc
124
-
125
- === DESCRIPTION:
126
-
127
- Requests that an exchange is deleted from broker/server. Removes reference from exchanges
128
- if successful. If an error occurs raises _Bunny_::_ProtocolError_.
129
-
130
- ==== Options:
131
-
132
- * <tt>:if_unused => true or false (_default_)</tt> - If set to _true_, the server will only
133
- delete the exchange if it has no queue bindings. If the exchange has queue bindings the
134
- server does not delete it but raises a channel exception instead.
135
- * <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
136
-
137
- ==== Returns:
138
-
139
- <tt>:delete_ok</tt> if successful
140
- =end
141
-
142
- def delete(opts = {})
143
- # ignore the :nowait option if passed, otherwise program will hang waiting for a
144
- # response that will not be sent by the server
145
- opts.delete(:nowait)
146
-
147
- client.send_frame(
148
- Qrack::Protocol::Exchange::Delete.new({ :exchange => name, :nowait => false }.merge(opts))
149
- )
150
-
151
- raise Bunny::ProtocolError,
152
- "Error deleting exchange #{name}" unless
153
- client.next_method.is_a?(Qrack::Protocol::Exchange::DeleteOk)
154
-
155
- client.exchanges.delete(name)
156
-
157
- # return confirmation
158
- :delete_ok
159
- end
160
-
161
173
  end
162
174
 
163
175
  end
@@ -64,9 +64,11 @@ specification that applies to your target broker/server.
64
64
  )
65
65
  )
66
66
 
67
- raise Bunny::ProtocolError,
68
- "Error declaring exchange #{name}: type = #{type}" unless
69
- client.next_method.is_a?(Qrack::Protocol09::Exchange::DeclareOk)
67
+ method = client.next_method
68
+
69
+ client.check_response(method, Qrack::Protocol09::Exchange::DeclareOk,
70
+ "Error declaring exchange #{name}: type = #{type}")
71
+
70
72
  end
71
73
  end
72
74
 
@@ -74,6 +76,45 @@ specification that applies to your target broker/server.
74
76
 
75
77
  === DESCRIPTION:
76
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
+
94
+ def delete(opts = {})
95
+ # ignore the :nowait option if passed, otherwise program will hang waiting for a
96
+ # response that will not be sent by the server
97
+ opts.delete(:nowait)
98
+
99
+ client.send_frame(
100
+ Qrack::Protocol09::Exchange::Delete.new({ :exchange => name, :nowait => false, :reserved_1 => 0 }.merge(opts))
101
+ )
102
+
103
+ method = client.next_method
104
+
105
+ client.check_response(method, Qrack::Protocol09::Exchange::DeleteOk,
106
+ "Error deleting exchange #{name}")
107
+
108
+ client.exchanges.delete(name)
109
+
110
+ # return confirmation
111
+ :delete_ok
112
+ end
113
+
114
+ =begin rdoc
115
+
116
+ === DESCRIPTION:
117
+
77
118
  Publishes a message to a specific exchange. The message will be routed to queues as defined
78
119
  by the exchange configuration and distributed to any active consumers when the transaction,
79
120
  if any, is committed.
@@ -104,61 +145,33 @@ nil
104
145
  opts = opts.dup
105
146
  out = []
106
147
 
107
- out << Qrack::Protocol09::Basic::Publish.new(
108
- { :exchange => name, :routing_key => opts.delete(:key) || key, :reserved_1 => 0 }.merge(opts)
109
- )
110
- data = data.to_s
111
- out << Qrack::Protocol09::Header.new(
112
- Qrack::Protocol09::Basic,
113
- data.length, {
114
- :content_type => 'application/octet-stream',
115
- :delivery_mode => (opts.delete(:persistent) ? 2 : 1),
116
- :priority => 0
117
- }.merge(opts)
118
- )
119
- out << Qrack::Transport09::Body.new(data)
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
+ :reserved_1 => 0 }
160
+ )
161
+ data = data.to_s
162
+ out << Qrack::Protocol09::Header.new(
163
+ Qrack::Protocol09::Basic,
164
+ data.length, {
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)
120
171
 
121
172
  client.send_frame(*out)
122
173
  end
123
174
 
124
- =begin rdoc
125
-
126
- === DESCRIPTION:
127
-
128
- Requests that an exchange is deleted from broker/server. Removes reference from exchanges
129
- if successful. If an error occurs raises _Bunny_::_ProtocolError_.
130
-
131
- ==== Options:
132
-
133
- * <tt>:if_unused => true or false (_default_)</tt> - If set to _true_, the server will only
134
- delete the exchange if it has no queue bindings. If the exchange has queue bindings the
135
- server does not delete it but raises a channel exception instead.
136
- * <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
137
-
138
- ==== Returns:
139
-
140
- <tt>:delete_ok</tt> if successful
141
- =end
142
-
143
- def delete(opts = {})
144
- # ignore the :nowait option if passed, otherwise program will hang waiting for a
145
- # response that will not be sent by the server
146
- opts.delete(:nowait)
147
-
148
- client.send_frame(
149
- Qrack::Protocol09::Exchange::Delete.new({ :exchange => name, :nowait => false, :reserved_1 => 0 }.merge(opts))
150
- )
151
-
152
- raise Bunny::ProtocolError,
153
- "Error deleting exchange #{name}" unless
154
- client.next_method.is_a?(Qrack::Protocol09::Exchange::DeleteOk)
155
-
156
- client.exchanges.delete(name)
157
-
158
- # return confirmation
159
- :delete_ok
160
- end
161
-
162
175
  end
163
176
 
164
177
  end