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.
@@ -0,0 +1,18 @@
1
+ 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
@@ -1,4 +1,7 @@
1
1
  module Qrack
2
+
3
+ class ClientTimeout < Timeout::Error; end
4
+
2
5
  # Client ancestor class
3
6
  class Client
4
7
 
@@ -6,7 +9,177 @@ module Qrack
6
9
  RETRY_DELAY = 10.0
7
10
 
8
11
  attr_reader :status, :host, :vhost, :port, :logging, :spec, :heartbeat
9
- attr_accessor :channel, :logfile, :exchanges, :queues, :channels, :heartbeat_in, :connecting
12
+ attr_accessor :channel, :logfile, :exchanges, :queues, :channels, :message_in, :message_out,
13
+ :connecting
10
14
 
15
+ def initialize(opts = {})
16
+ @host = opts[:host] || 'localhost'
17
+ @user = opts[:user] || 'guest'
18
+ @pass = opts[:pass] || 'guest'
19
+ @vhost = opts[:vhost] || '/'
20
+ @logfile = opts[:logfile] || nil
21
+ @logging = opts[:logging] || false
22
+ @status = :not_connected
23
+ @frame_max = opts[:frame_max] || 131072
24
+ @channel_max = opts[:channel_max] || 0
25
+ @heartbeat = opts[:heartbeat] || 0
26
+ @logger = nil
27
+ create_logger if @logging
28
+ @message_in = false
29
+ @message_out = false
30
+ @connecting = false
31
+ @channels ||= []
32
+ # Create channel 0
33
+ @channel = create_channel()
34
+ @exchanges ||= {}
35
+ @queues ||= {}
36
+ end
37
+
38
+ =begin rdoc
39
+
40
+ === DESCRIPTION:
41
+
42
+ Closes all active communication channels and connection. If an error occurs a
43
+ _Bunny_::_ProtocolError_ is raised. If successful, _Client_._status_ is set to <tt>:not_connected</tt>.
44
+
45
+ ==== RETURNS:
46
+
47
+ <tt>:not_connected</tt> if successful.
48
+
49
+ =end
50
+
51
+ def close
52
+ # Close all active channels
53
+ channels.each do |c|
54
+ c.close if c.open?
55
+ end
56
+
57
+ # Close connection to AMQP server
58
+ close_connection
59
+
60
+ # Close TCP Socket
61
+ close_socket
62
+ end
63
+
64
+ alias stop close
65
+
66
+ def connected?
67
+ status == :connected
68
+ end
69
+
70
+ def connecting?
71
+ connecting
72
+ end
73
+
74
+ def logging=(bool)
75
+ @logging = bool
76
+ create_logger if @logging
77
+ end
78
+
79
+ def next_payload(options = {})
80
+ next_frame(options).payload
81
+ end
82
+
83
+ alias next_method next_payload
84
+
85
+ def read(*args)
86
+ send_command(:read, *args)
87
+ end
88
+
89
+ =begin rdoc
90
+
91
+ === DESCRIPTION:
92
+
93
+ Checks to see whether or not an undeliverable message has been returned as a result of a publish
94
+ with the <tt>:immediate</tt> or <tt>:mandatory</tt> options.
95
+
96
+ ==== OPTIONS:
97
+
98
+ * <tt>:timeout => number of seconds (default = 0.1) - The method will wait for a return
99
+ message until this timeout interval is reached.
100
+
101
+ ==== RETURNS:
102
+
103
+ <tt>:no_return</tt> if message was not returned before timeout .
104
+ <tt>{:header, :return_details, :payload}</tt> if message is returned. <tt>:return_details</tt> is
105
+ a hash <tt>{:reply_code, :reply_text, :exchange, :routing_key}</tt>.
106
+
107
+ =end
108
+
109
+ def returned_message(opts = {})
110
+ secs = opts[:timeout] || 0.1
111
+ frame = next_frame(:timeout => secs)
112
+
113
+ if frame.is_a?(Symbol)
114
+ return :no_return if frame == :timed_out
115
+ end
116
+
117
+ method = frame.payload
118
+ header = next_payload
119
+ msg = next_payload
120
+ raise Bunny::MessageError, 'unexpected length' if msg.length < header.size
121
+
122
+ # Return the message and related info
123
+ {:header => header, :payload => msg, :return_details => method.arguments}
124
+ end
125
+
126
+ def switch_channel(chann)
127
+ if (0...channels.size).include? chann
128
+ @channel = channels[chann]
129
+ chann
130
+ else
131
+ raise RuntimeError, "Invalid channel number - #{chann}"
132
+ end
133
+ end
134
+
135
+ def write(*args)
136
+ send_command(:write, *args)
137
+ end
138
+
139
+ private
140
+
141
+ def close_socket(reason=nil)
142
+ # Close the socket. The server is not considered dead.
143
+ @socket.close if @socket and not @socket.closed?
144
+ @socket = nil
145
+ @status = :not_connected
146
+ end
147
+
148
+ def create_logger
149
+ @logfile ? @logger = Logger.new("#{logfile}") : @logger = Logger.new(STDOUT)
150
+ @logger.level = Logger::INFO
151
+ @logger.datetime_format = "%Y-%m-%d %H:%M:%S"
152
+ end
153
+
154
+ def send_command(cmd, *args)
155
+ begin
156
+ raise Bunny::ConnectionError, 'No connection - socket has not been created' if !@socket
157
+ @socket.__send__(cmd, *args)
158
+ rescue Errno::EPIPE, IOError => e
159
+ raise Bunny::ServerDownError, e.message
160
+ end
161
+ end
162
+
163
+ def socket
164
+ return @socket if @socket and (@status == :connected) and not @socket.closed?
165
+
166
+ begin
167
+ # Attempt to connect.
168
+ @socket = timeout(CONNECT_TIMEOUT) do
169
+ TCPSocket.new(host, port)
170
+ end
171
+
172
+ if Socket.constants.include? 'TCP_NODELAY'
173
+ @socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
174
+ end
175
+ rescue => e
176
+ @status = :not_connected
177
+ raise Bunny::ServerDownError, e.message
178
+ end
179
+
180
+ @socket
181
+ end
182
+
11
183
  end
12
- end
184
+
185
+ end
@@ -7,6 +7,8 @@ require 'transport/buffer08'
7
7
  require 'transport/frame08'
8
8
 
9
9
  require 'qrack/client'
10
+ require 'qrack/channel'
11
+ require 'qrack/queue'
10
12
 
11
13
  module Qrack
12
14
 
@@ -7,6 +7,8 @@ require 'transport/buffer09'
7
7
  require 'transport/frame09'
8
8
 
9
9
  require 'qrack/client'
10
+ require 'qrack/channel'
11
+ require 'qrack/queue'
10
12
 
11
13
  module Qrack
12
14
 
@@ -0,0 +1,53 @@
1
+ module Qrack
2
+
3
+ # Queue ancestor class
4
+ class Queue
5
+
6
+ attr_reader :name, :client
7
+ attr_accessor :delivery_tag
8
+
9
+ =begin rdoc
10
+
11
+ === DESCRIPTION:
12
+
13
+ Returns consumer count from Queue#status.
14
+
15
+ =end
16
+
17
+ def consumer_count
18
+ s = status
19
+ s[:consumer_count]
20
+ end
21
+
22
+ =begin rdoc
23
+
24
+ === DESCRIPTION:
25
+
26
+ Returns message count from Queue#status.
27
+
28
+ =end
29
+
30
+ def message_count
31
+ s = status
32
+ s[:message_count]
33
+ end
34
+
35
+ =begin rdoc
36
+
37
+ === DESCRIPTION:
38
+
39
+ Publishes a message to the queue via the default nameless '' direct exchange.
40
+
41
+ ==== RETURNS:
42
+
43
+ nil
44
+
45
+ =end
46
+
47
+ def publish(data, opts = {})
48
+ exchange.publish(data, opts)
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -115,6 +115,13 @@ describe Bunny do
115
115
  exch = @b.exchange('direct_exchange')
116
116
  exch.publish('This is a published message')
117
117
  end
118
+
119
+ it "should not modify the passed options hash when publishing a message" do
120
+ exch = @b.exchange('direct_exchange')
121
+ opts = {:key => 'a', :persistent => true}
122
+ exch.publish('', opts)
123
+ opts.should == {:key => 'a', :persistent => true}
124
+ end
118
125
 
119
126
  it "should be able to return an undeliverable message" do
120
127
  exch = @b.exchange('')
@@ -136,4 +143,4 @@ describe Bunny do
136
143
  exch.delete(:nowait => true)
137
144
  end
138
145
 
139
- end
146
+ end
@@ -67,6 +67,14 @@ describe Bunny do
67
67
  q.message_count.should == 0
68
68
  end
69
69
 
70
+ it "should be able to pop a message where body length exceeds max frame size" do
71
+ q = @b.queue('test1')
72
+ lg_msg = 'z' * 142000
73
+ q.publish(lg_msg)
74
+ msg = q.pop
75
+ msg.should == lg_msg
76
+ end
77
+
70
78
  it "should be able to be purged to remove all of its messages" do
71
79
  q = @b.queue('test1')
72
80
  5.times {q.publish('This is another test message')}
@@ -82,6 +90,24 @@ describe Bunny do
82
90
  msg = q.pop
83
91
  msg.should == :queue_empty
84
92
  end
93
+
94
+ it "should stop subscription without processing messages if max specified is 0" do
95
+ q = @b.queue('test1')
96
+ 5.times {q.publish('Yet another test message')}
97
+ q.message_count.should == 5
98
+ q.subscribe(:message_max => 0){|msg| x = 1}
99
+ q.message_count.should == 5
100
+ q.unsubscribe.should == :unsubscribe_ok
101
+ q.purge.should == :purge_ok
102
+ end
103
+
104
+ it "should stop subscription after processing number of messages specified > 0" do
105
+ q = @b.queue('test1')
106
+ 5.times {q.publish('Yet another test message')}
107
+ q.message_count.should == 5
108
+ q.subscribe(:message_max => 5){|msg| x = 1}
109
+ q.unsubscribe.should == :unsubscribe_ok
110
+ end
85
111
 
86
112
  it "should be able to be deleted" do
87
113
  q = @b.queue('test1')
@@ -115,6 +115,13 @@ describe Bunny do
115
115
  exch = @b.exchange('direct_exchange')
116
116
  exch.publish('This is a published message')
117
117
  end
118
+
119
+ it "should not modify the passed options hash when publishing a message" do
120
+ exch = @b.exchange('direct_exchange')
121
+ opts = {:key => 'a', :persistent => true}
122
+ exch.publish('', opts)
123
+ opts.should == {:key => 'a', :persistent => true}
124
+ end
118
125
 
119
126
  it "should be able to return an undeliverable message" do
120
127
  exch = @b.exchange('')
@@ -136,4 +143,4 @@ describe Bunny do
136
143
  exch.delete(:nowait => true)
137
144
  end
138
145
 
139
- end
146
+ end
@@ -67,6 +67,14 @@ describe Bunny do
67
67
  q.message_count.should == 0
68
68
  end
69
69
 
70
+ it "should be able to pop a message where body length exceeds max frame size" do
71
+ q = @b.queue('test1')
72
+ lg_msg = 'z' * 142000
73
+ q.publish(lg_msg)
74
+ msg = q.pop
75
+ msg.should == lg_msg
76
+ end
77
+
70
78
  it "should be able to be purged to remove all of its messages" do
71
79
  q = @b.queue('test1')
72
80
  5.times {q.publish('This is another test message')}
@@ -82,6 +90,24 @@ describe Bunny do
82
90
  msg = q.pop
83
91
  msg.should == :queue_empty
84
92
  end
93
+
94
+ it "should stop subscription without processing messages if max specified is 0" do
95
+ q = @b.queue('test1')
96
+ 5.times {q.publish('Yet another test message')}
97
+ q.message_count.should == 5
98
+ q.subscribe(:message_max => 0){|msg| x = 1}
99
+ q.message_count.should == 5
100
+ q.unsubscribe.should == :unsubscribe_ok
101
+ q.purge.should == :purge_ok
102
+ end
103
+
104
+ it "should stop subscription after processing number of messages specified > 0" do
105
+ q = @b.queue('test1')
106
+ 5.times {q.publish('Yet another test message')}
107
+ q.message_count.should == 5
108
+ q.subscribe(:message_max => 5){|msg| x = 1}
109
+ q.unsubscribe.should == :unsubscribe_ok
110
+ end
85
111
 
86
112
  it "should be able to be deleted" do
87
113
  q = @b.queue('test1')
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.5.2
4
+ version: 0.5.3
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-08-17 00:00:00 +01:00
12
+ date: 2009-09-07 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -50,6 +50,8 @@ files:
50
50
  - lib/bunny/queue08.rb
51
51
  - lib/bunny/queue09.rb
52
52
  - lib/qrack/client.rb
53
+ - lib/qrack/channel.rb
54
+ - lib/qrack/queue.rb
53
55
  - lib/qrack/protocol/protocol08.rb
54
56
  - lib/qrack/protocol/protocol09.rb
55
57
  - lib/qrack/protocol/spec08.rb