bunny 0.5.2 → 0.5.3

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.
@@ -35,29 +35,29 @@ Sets up a Bunny::Client object ready for connection to a broker/server. _Client_
35
35
  =end
36
36
 
37
37
  def initialize(opts = {})
38
+ super
38
39
  @spec = '0-9-1'
39
- @host = opts[:host] || 'localhost'
40
40
  @port = opts[:port] || Qrack::Protocol09::PORT
41
- @user = opts[:user] || 'guest'
42
- @pass = opts[:pass] || 'guest'
43
- @vhost = opts[:vhost] || '/'
44
- @logfile = opts[:logfile] || nil
45
- @logging = opts[:logging] || false
46
- @status = :not_connected
47
- @frame_max = opts[:frame_max] || 131072
48
- @channel_max = opts[:channel_max] || 5
49
- @heartbeat = opts[:heartbeat] || 0
50
- @logger = nil
51
- create_logger if @logging
52
- @channels = []
53
- # Create channel 0
54
- @channel = Bunny::Channel09.new(self, true)
55
- @exchanges = {}
56
- @queues = {}
57
- @heartbeat_in = false
58
- @connecting = false
59
41
  end
60
42
 
43
+ def close_connection
44
+ # Set client channel to zero
45
+ switch_channel(0)
46
+
47
+ send_frame(
48
+ Qrack::Protocol09::Connection::Close.new(:reply_code => 200, :reply_text => 'Goodbye', :class_id => 0, :method_id => 0)
49
+ )
50
+ raise Bunny::ProtocolError, "Error closing connection" unless next_method.is_a?(Qrack::Protocol09::Connection::CloseOk)
51
+ end
52
+
53
+ def create_channel
54
+ channels.each do |c|
55
+ return c if (!c.open? and c.number != 0)
56
+ end
57
+ # If no channel to re-use instantiate new one
58
+ Bunny::Channel09.new(self)
59
+ end
60
+
61
61
  =begin rdoc
62
62
 
63
63
  === DESCRIPTION:
@@ -89,6 +89,97 @@ Exchange
89
89
  return exchanges[name] if exchanges.has_key?(name)
90
90
  exchanges[name] ||= Bunny::Exchange09.new(self, name, opts)
91
91
  end
92
+
93
+ def init_connection
94
+ write(Qrack::Protocol09::HEADER)
95
+ write([0, Qrack::Protocol09::VERSION_MAJOR, Qrack::Protocol09::VERSION_MINOR, Qrack::Protocol09::REVISION].pack('C4'))
96
+
97
+ frame = next_frame
98
+ if frame.nil? or !frame.payload.is_a?(Qrack::Protocol09::Connection::Start)
99
+ raise Bunny::ProtocolError, 'Connection initiation failed'
100
+ end
101
+ end
102
+
103
+ def next_frame(opts = {})
104
+ frame = nil
105
+
106
+ case
107
+ when channel.frame_buffer.size > 0
108
+ frame = channel.frame_buffer.shift
109
+ when opts.has_key?(:timeout)
110
+ Timeout::timeout(opts[:timeout], Qrack::ClientTimeout) do
111
+ frame = Qrack::Transport09::Frame.parse(buffer)
112
+ end
113
+ else
114
+ frame = Qrack::Transport09::Frame.parse(buffer)
115
+ end
116
+
117
+ @logger.info("received") { frame } if @logging
118
+
119
+ raise Bunny::ConnectionError, 'No connection to server' if (frame.nil? and !connecting?)
120
+
121
+ # Monitor server activity and discard heartbeats
122
+ @message_in = true
123
+
124
+ case
125
+ when frame.is_a?(Qrack::Transport09::Heartbeat)
126
+ next_frame(opts)
127
+ when frame.nil?
128
+ frame
129
+ when ((frame.channel != channel.number) and (frame.channel != 0))
130
+ channel.frame_buffer << frame
131
+ next_frame(opts)
132
+ else
133
+ frame
134
+ end
135
+
136
+ end
137
+
138
+ =begin rdoc
139
+
140
+ === DESCRIPTION:
141
+
142
+ Requests a specific quality of service. The QoS can be specified for the current channel
143
+ or for all channels on the connection. The particular properties and semantics of a QoS
144
+ method always depend on the content class semantics. Though the QoS method could in principle
145
+ apply to both peers, it is currently meaningful only for the server.
146
+
147
+ ==== Options:
148
+
149
+ * <tt>:prefetch_size => size in no. of octets (default = 0)</tt> - The client can request that
150
+ messages be sent in advance so that when the client finishes processing a message, the following
151
+ message is already held locally, rather than needing to be sent down the channel. Prefetching gives
152
+ a performance improvement. This field specifies the prefetch window size in octets. The server
153
+ will send a message in advance if it is equal to or smaller in size than the available prefetch
154
+ size (and also falls into other prefetch limits). May be set to zero, meaning "no specific limit",
155
+ although other prefetch limits may still apply. The prefetch-size is ignored if the no-ack option
156
+ is set.
157
+ * <tt>:prefetch_count => no. messages (default = 1)</tt> - Specifies a prefetch window in terms
158
+ of whole messages. This field may be used in combination with the prefetch-size field; a message
159
+ will only be sent in advance if both prefetch windows (and those at the channel and connection level)
160
+ allow it. The prefetch-count is ignored if the no-ack option is set.
161
+ * <tt>:global => true or false (_default_)</tt> - By default the QoS settings apply to the current channel only. If set to
162
+ true, they are applied to the entire connection.
163
+
164
+ ==== RETURNS:
165
+
166
+ <tt>:qos_ok</tt> if successful.
167
+
168
+ =end
169
+
170
+ def qos(opts = {})
171
+
172
+ send_frame(
173
+ Qrack::Protocol09::Basic::Qos.new({ :prefetch_size => 0, :prefetch_count => 1, :global => false }.merge(opts))
174
+ )
175
+
176
+ raise Bunny::ProtocolError,
177
+ "Error specifying Quality of Service" unless
178
+ next_method.is_a?(Qrack::Protocol09::Basic::QosOk)
179
+
180
+ # return confirmation
181
+ :qos_ok
182
+ end
92
183
 
93
184
  =begin rdoc
94
185
 
@@ -134,130 +225,54 @@ Queue
134
225
 
135
226
  Bunny::Queue09.new(self, name, opts)
136
227
  end
137
-
138
- def send_heartbeat
139
- # Create a new heartbeat frame
140
- hb = Qrack::Transport09::Heartbeat.new('')
141
- # Channel 0 must be used
142
- switch_channel(0) if @channel.number > 0
143
- # Send the heartbeat to server
144
- send_frame(hb)
145
- end
146
-
147
- def send_frame(*args)
148
- args.each do |data|
149
- data = data.to_frame(channel.number) unless data.is_a?(Qrack::Transport09::Frame)
150
- data.channel = channel.number
151
-
152
- @logger.info("send") { data } if @logging
153
- write(data.to_s)
154
- end
155
- nil
156
- end
157
-
158
- def next_frame(opts = {})
159
- secs = opts[:timeout] || 0
160
-
161
- begin
162
- Timeout::timeout(secs) do
163
- @frame = Qrack::Transport09::Frame.parse(buffer)
164
- end
165
- rescue Timeout::Error
166
- return :timed_out
167
- end
168
-
169
- @logger.info("received") { @frame } if @logging
170
-
171
- raise Bunny::ConnectionError, 'No connection to server' if (@frame.nil? and !connecting?)
172
-
173
- if @frame.is_a?(Qrack::Transport09::Heartbeat)
174
- @heartbeat_in = true
175
- next_frame
176
- end
177
-
178
- @frame
179
- end
180
-
181
- def next_payload
182
- frame = next_frame
183
- frame.payload
184
- end
185
-
186
- alias next_method next_payload
187
-
188
- =begin rdoc
189
-
190
- === DESCRIPTION:
191
-
192
- Checks to see whether or not an undeliverable message has been returned as a result of a publish
193
- with the <tt>:immediate</tt> or <tt>:mandatory</tt> options.
194
-
195
- ==== OPTIONS:
196
-
197
- * <tt>:timeout => number of seconds (default = 0.1) - The method will wait for a return
198
- message until this timeout interval is reached.
199
-
200
- ==== RETURNS:
201
-
202
- <tt>:no_return</tt> if message was not returned before timeout .
203
- <tt>{:header, :return_details, :payload}</tt> if message is returned. <tt>:return_details</tt> is
204
- a hash <tt>{:reply_code, :reply_text, :exchange, :routing_key}</tt>.
205
-
206
- =end
207
-
208
- def returned_message(opts = {})
209
- secs = opts[:timeout] || 0.1
210
- frame = next_frame(:timeout => secs)
211
-
212
- if frame.is_a?(Symbol)
213
- return :no_return if frame == :timed_out
214
- end
215
-
216
- method = frame.payload
217
- header = next_payload
218
- msg = next_payload
219
- raise Bunny::MessageError, 'unexpected length' if msg.length < header.size
220
-
221
- # Return the message and related info
222
- {:header => header, :payload => msg, :return_details => method.arguments}
223
- end
224
-
228
+
225
229
  =begin rdoc
226
230
 
227
231
  === DESCRIPTION:
228
232
 
229
- Closes the current communication channel and connection. If an error occurs a
230
- _Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to <tt>:not_connected</tt>.
233
+ Asks the broker to redeliver all unacknowledged messages on a specified channel. Zero or
234
+ more messages may be redelivered.
231
235
 
232
- ==== RETURNS:
236
+ ==== Options:
233
237
 
234
- <tt>:not_connected</tt> if successful.
238
+ * <tt>:requeue => true or false (_default_)</tt> - If set to _false_, the message will be
239
+ redelivered to the original recipient. If set to _true_, the server will attempt to requeue
240
+ the message, potentially then delivering it to an alternative subscriber.
235
241
 
236
242
  =end
237
243
 
238
- def close
239
- # Close all active channels
240
- channels.each do |c|
241
- c.close if c.open?
242
- end
244
+ def recover(opts = {})
243
245
 
244
- # Close connection to AMQP server
245
- close_connection
246
+ send_frame(
247
+ Qrack::Protocol09::Basic::Recover.new({ :requeue => false }.merge(opts))
248
+ )
246
249
 
247
- # Close TCP socket
248
- close_socket
249
- end
250
+ end
251
+
252
+ def send_frame(*args)
253
+ args.each do |data|
254
+ data = data.to_frame(channel.number) unless data.is_a?(Qrack::Transport09::Frame)
255
+ data.channel = channel.number
250
256
 
251
- alias stop close
257
+ @logger.info("send") { data } if @logging
258
+ write(data.to_s)
252
259
 
253
- def read(*args)
254
- send_command(:read, *args)
255
- end
260
+ # Monitor client activity for heartbeat purposes
261
+ @message_out = true
262
+ end
256
263
 
257
- def write(*args)
258
- send_command(:write, *args)
264
+ nil
259
265
  end
260
-
266
+
267
+ def send_heartbeat
268
+ # Create a new heartbeat frame
269
+ hb = Qrack::Transport09::Heartbeat.new('')
270
+ # Channel 0 must be used
271
+ switch_channel(0) if @channel.number > 0
272
+ # Send the heartbeat to server
273
+ send_frame(hb)
274
+ end
275
+
261
276
  =begin rdoc
262
277
 
263
278
  === DESCRIPTION:
@@ -298,68 +313,51 @@ _Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to <
298
313
  =begin rdoc
299
314
 
300
315
  === DESCRIPTION:
316
+ This method commits all messages published and acknowledged in
317
+ the current transaction. A new transaction starts immediately
318
+ after a commit.
301
319
 
302
- Asks the broker to redeliver all unacknowledged messages on a specified channel. Zero or
303
- more messages may be redelivered.
304
-
305
- ==== Options:
320
+ ==== RETURNS:
306
321
 
307
- * <tt>:requeue => true or false (_default_)</tt> - If set to _false_, the message will be
308
- redelivered to the original recipient. If set to _true_, the server will attempt to requeue
309
- the message, potentially then delivering it to an alternative subscriber.
322
+ <tt>:commit_ok</tt> if successful.
310
323
 
311
324
  =end
312
325
 
313
- def recover(opts = {})
326
+ def tx_commit
327
+ send_frame(Qrack::Protocol09::Tx::Commit.new())
314
328
 
315
- send_frame(
316
- Qrack::Protocol09::Basic::Recover.new({ :requeue => false }.merge(opts))
317
- )
329
+ raise Bunny::ProtocolError,
330
+ "Error commiting transaction" unless
331
+ next_method.is_a?(Qrack::Protocol09::Tx::CommitOk)
318
332
 
319
- end
320
-
333
+ # return confirmation
334
+ :commit_ok
335
+ end
336
+
321
337
  =begin rdoc
322
338
 
323
339
  === DESCRIPTION:
340
+ This method abandons all messages published and acknowledged in
341
+ the current transaction. A new transaction starts immediately
342
+ after a rollback.
324
343
 
325
- Requests a specific quality of service. The QoS can be specified for the current channel
326
- or for all channels on the connection. The particular properties and semantics of a QoS
327
- method always depend on the content class semantics. Though the QoS method could in principle
328
- apply to both peers, it is currently meaningful only for the server.
344
+ ==== RETURNS:
329
345
 
330
- ==== Options:
331
-
332
- * <tt>:prefetch_size => size in no. of octets (default = 0)</tt> - The client can request that
333
- messages be sent in advance so that when the client finishes processing a message, the following
334
- message is already held locally, rather than needing to be sent down the channel. Prefetching gives
335
- a performance improvement. This field specifies the prefetch window size in octets. The server
336
- will send a message in advance if it is equal to or smaller in size than the available prefetch
337
- size (and also falls into other prefetch limits). May be set to zero, meaning "no specific limit",
338
- although other prefetch limits may still apply. The prefetch-size is ignored if the no-ack option
339
- is set.
340
- * <tt>:prefetch_count => no. messages (default = 1)</tt> - Specifies a prefetch window in terms
341
- of whole messages. This field may be used in combination with the prefetch-size field; a message
342
- will only be sent in advance if both prefetch windows (and those at the channel and connection level)
343
- allow it. The prefetch-count is ignored if the no-ack option is set.
344
- * <tt>:global => true or false (_default_)</tt> - By default the QoS settings apply to the current channel only. If set to
345
- true, they are applied to the entire connection.
346
+ <tt>:rollback_ok</tt> if successful.
346
347
 
347
348
  =end
348
349
 
349
- def qos(opts = {})
350
-
351
- send_frame(
352
- Qrack::Protocol09::Basic::Qos.new({ :prefetch_size => 0, :prefetch_count => 1, :global => false }.merge(opts))
353
- )
354
-
355
- raise Bunny::ProtocolError,
356
- "Error specifying Quality of Service" unless
357
- next_method.is_a?(Qrack::Protocol09::Basic::QosOk)
350
+ def tx_rollback
351
+ send_frame(Qrack::Protocol09::Tx::Rollback.new())
358
352
 
359
- # return confirmation
360
- :qos_ok
361
- end
353
+ raise Bunny::ProtocolError,
354
+ "Error rolling back transaction" unless
355
+ next_method.is_a?(Qrack::Protocol09::Tx::RollbackOk)
362
356
 
357
+ # return confirmation
358
+ :rollback_ok
359
+ end
360
+
363
361
  =begin rdoc
364
362
 
365
363
  === DESCRIPTION:
@@ -367,6 +365,10 @@ This method sets the channel to use standard transactions. The
367
365
  client must use this method at least once on a channel before
368
366
  using the Commit or Rollback methods.
369
367
 
368
+ ==== RETURNS:
369
+
370
+ <tt>:select_ok</tt> if successful.
371
+
370
372
  =end
371
373
 
372
374
  def tx_select
@@ -380,82 +382,6 @@ using the Commit or Rollback methods.
380
382
  :select_ok
381
383
  end
382
384
 
383
- =begin rdoc
384
-
385
- === DESCRIPTION:
386
- This method commits all messages published and acknowledged in
387
- the current transaction. A new transaction starts immediately
388
- after a commit.
389
-
390
- =end
391
-
392
- def tx_commit
393
- send_frame(Qrack::Protocol09::Tx::Commit.new())
394
-
395
- raise Bunny::ProtocolError,
396
- "Error commiting transaction" unless
397
- next_method.is_a?(Qrack::Protocol09::Tx::CommitOk)
398
-
399
- # return confirmation
400
- :commit_ok
401
- end
402
-
403
- =begin rdoc
404
-
405
- === DESCRIPTION:
406
- This method abandons all messages published and acknowledged in
407
- the current transaction. A new transaction starts immediately
408
- after a rollback.
409
-
410
- =end
411
-
412
- def tx_rollback
413
- send_frame(Qrack::Protocol09::Tx::Rollback.new())
414
-
415
- raise Bunny::ProtocolError,
416
- "Error rolling back transaction" unless
417
- next_method.is_a?(Qrack::Protocol09::Tx::RollbackOk)
418
-
419
- # return confirmation
420
- :rollback_ok
421
- end
422
-
423
- def logging=(bool)
424
- @logging = bool
425
- create_logger if @logging
426
- end
427
-
428
- def create_channel
429
- channels.each do |c|
430
- return c if (!c.open? and c.number != 0)
431
- end
432
- # If no channel to re-use instantiate new one
433
- Bunny::Channel09.new(self)
434
- end
435
-
436
- def switch_channel(chann)
437
- if (0...channels.size).include? chann
438
- @channel = channels[chann]
439
- chann
440
- else
441
- raise RuntimeError, "Invalid channel number - #{chann}"
442
- end
443
- end
444
-
445
- def connecting?
446
- connecting
447
- end
448
-
449
- def init_connection
450
- write(Qrack::Protocol09::HEADER)
451
- write([0, Qrack::Protocol09::VERSION_MAJOR, Qrack::Protocol09::VERSION_MINOR, Qrack::Protocol09::REVISION].pack('C4'))
452
-
453
- frame = next_frame
454
- if frame.nil? or !frame.payload.is_a?(Qrack::Protocol09::Connection::Start)
455
- raise Bunny::ProtocolError, 'Connection initiation failed'
456
- end
457
- end
458
-
459
385
  def open_connection
460
386
  send_frame(
461
387
  Qrack::Protocol09::Connection::StartOk.new(
@@ -483,16 +409,6 @@ after a rollback.
483
409
 
484
410
  raise Bunny::ProtocolError, 'Cannot open connection' unless next_method.is_a?(Qrack::Protocol09::Connection::OpenOk)
485
411
  end
486
-
487
- def close_connection
488
- # Set client channel to zero
489
- switch_channel(0)
490
-
491
- send_frame(
492
- Qrack::Protocol09::Connection::Close.new(:reply_code => 200, :reply_text => 'Goodbye', :class_id => 0, :method_id => 0)
493
- )
494
- raise Bunny::ProtocolError, "Error closing connection" unless next_method.is_a?(Qrack::Protocol09::Connection::CloseOk)
495
- end
496
412
 
497
413
  private
498
414
 
@@ -500,47 +416,5 @@ after a rollback.
500
416
  @buffer ||= Qrack::Transport09::Buffer.new(self)
501
417
  end
502
418
 
503
- def send_command(cmd, *args)
504
- begin
505
- raise Bunny::ConnectionError, 'No connection - socket has not been created' if !@socket
506
- @socket.__send__(cmd, *args)
507
- rescue Errno::EPIPE, IOError => e
508
- raise Bunny::ServerDownError, e.message
509
- end
510
- end
511
-
512
- def socket
513
- return @socket if @socket and (@status == :connected) and not @socket.closed?
514
-
515
- begin
516
- # Attempt to connect.
517
- @socket = timeout(CONNECT_TIMEOUT) do
518
- TCPSocket.new(host, port)
519
- end
520
-
521
- if Socket.constants.include? 'TCP_NODELAY'
522
- @socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
523
- end
524
- rescue => e
525
- @status = :not_connected
526
- raise Bunny::ServerDownError, e.message
527
- end
528
-
529
- @socket
530
- end
531
-
532
- def close_socket(reason=nil)
533
- # Close the socket. The server is not considered dead.
534
- @socket.close if @socket and not @socket.closed?
535
- @socket = nil
536
- @status = :not_connected
537
- end
538
-
539
- def create_logger
540
- @logfile ? @logger = Logger.new("#{logfile}") : @logger = Logger.new(STDOUT)
541
- @logger.level = Logger::INFO
542
- @logger.datetime_format = "%Y-%m-%d %H:%M:%S"
543
- end
544
-
545
419
  end
546
420
  end