bunny 0.5.2 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- data/bunny.gemspec +4 -2
- data/examples/simple_consumer_08.rb +6 -6
- data/examples/simple_consumer_09.rb +6 -6
- data/lib/bunny.rb +1 -1
- data/lib/bunny/channel08.rb +3 -8
- data/lib/bunny/channel09.rb +3 -8
- data/lib/bunny/client08.rb +217 -344
- data/lib/bunny/client09.rb +175 -301
- data/lib/bunny/exchange08.rb +6 -1
- data/lib/bunny/exchange09.rb +6 -1
- data/lib/bunny/queue08.rb +144 -170
- data/lib/bunny/queue09.rb +160 -185
- data/lib/qrack/channel.rb +18 -0
- data/lib/qrack/client.rb +175 -2
- data/lib/qrack/qrack08.rb +2 -0
- data/lib/qrack/qrack09.rb +2 -0
- data/lib/qrack/queue.rb +53 -0
- data/spec/spec_08/exchange_spec.rb +8 -1
- data/spec/spec_08/queue_spec.rb +26 -0
- data/spec/spec_09/exchange_spec.rb +8 -1
- data/spec/spec_09/queue_spec.rb +26 -0
- metadata +4 -2
@@ -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
|
data/lib/qrack/client.rb
CHANGED
@@ -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, :
|
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
|
-
|
184
|
+
|
185
|
+
end
|
data/lib/qrack/qrack08.rb
CHANGED
data/lib/qrack/qrack09.rb
CHANGED
data/lib/qrack/queue.rb
ADDED
@@ -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
|
data/spec/spec_08/queue_spec.rb
CHANGED
@@ -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
|
data/spec/spec_09/queue_spec.rb
CHANGED
@@ -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.
|
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-
|
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
|