bunny 0.6.3.rc2 → 0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/.rspec +3 -0
- data/.travis.yml +15 -0
- data/.yardopts +9 -0
- data/CHANGELOG +3 -0
- data/Gemfile +39 -0
- data/Gemfile.lock +34 -0
- data/LICENSE +5 -4
- data/README.textile +54 -0
- data/Rakefile +15 -13
- data/bunny.gemspec +42 -61
- data/examples/simple_08.rb +4 -2
- data/examples/simple_09.rb +4 -2
- data/examples/simple_ack_08.rb +3 -1
- data/examples/simple_ack_09.rb +3 -1
- data/examples/simple_consumer_08.rb +4 -2
- data/examples/simple_consumer_09.rb +4 -2
- data/examples/simple_fanout_08.rb +3 -1
- data/examples/simple_fanout_09.rb +3 -1
- data/examples/simple_headers_08.rb +5 -3
- data/examples/simple_headers_09.rb +5 -3
- data/examples/simple_publisher_08.rb +3 -1
- data/examples/simple_publisher_09.rb +3 -1
- data/examples/simple_topic_08.rb +5 -3
- data/examples/simple_topic_09.rb +5 -3
- data/ext/amqp-0.8.json +616 -0
- data/ext/amqp-0.9.1.json +388 -0
- data/ext/config.yml +4 -0
- data/ext/qparser.rb +463 -0
- data/lib/bunny.rb +88 -66
- data/lib/bunny/channel08.rb +38 -38
- data/lib/bunny/channel09.rb +37 -37
- data/lib/bunny/client08.rb +184 -206
- data/lib/bunny/client09.rb +277 -363
- data/lib/bunny/consumer.rb +35 -0
- data/lib/bunny/exchange08.rb +37 -41
- data/lib/bunny/exchange09.rb +106 -124
- data/lib/bunny/queue08.rb +216 -202
- data/lib/bunny/queue09.rb +256 -326
- data/lib/bunny/subscription08.rb +30 -29
- data/lib/bunny/subscription09.rb +84 -83
- data/lib/bunny/version.rb +5 -0
- data/lib/qrack/amq-client-url.rb +165 -0
- data/lib/qrack/channel.rb +19 -17
- data/lib/qrack/client.rb +152 -151
- data/lib/qrack/errors.rb +5 -0
- data/lib/qrack/protocol/protocol08.rb +132 -130
- data/lib/qrack/protocol/protocol09.rb +133 -131
- data/lib/qrack/protocol/spec08.rb +2 -0
- data/lib/qrack/protocol/spec09.rb +2 -0
- data/lib/qrack/qrack08.rb +7 -10
- data/lib/qrack/qrack09.rb +7 -10
- data/lib/qrack/queue.rb +27 -40
- data/lib/qrack/subscription.rb +102 -101
- data/lib/qrack/transport/buffer08.rb +266 -264
- data/lib/qrack/transport/buffer09.rb +268 -264
- data/lib/qrack/transport/frame08.rb +13 -11
- data/lib/qrack/transport/frame09.rb +9 -7
- data/spec/spec_08/bunny_spec.rb +48 -45
- data/spec/spec_08/connection_spec.rb +10 -7
- data/spec/spec_08/exchange_spec.rb +145 -143
- data/spec/spec_08/queue_spec.rb +161 -161
- data/spec/spec_09/bunny_spec.rb +46 -44
- data/spec/spec_09/connection_spec.rb +15 -8
- data/spec/spec_09/exchange_spec.rb +147 -145
- data/spec/spec_09/queue_spec.rb +182 -184
- metadata +60 -41
- data/README.rdoc +0 -66
@@ -1,133 +1,135 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module Qrack
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
4
|
+
module Protocol09
|
5
|
+
#:stopdoc:
|
6
|
+
class Class::Method
|
7
|
+
def initialize *args
|
8
|
+
opts = args.pop if args.last.is_a? Hash
|
9
|
+
opts ||= {}
|
10
|
+
|
11
|
+
if args.size == 1 and args.first.is_a? Transport09::Buffer
|
12
|
+
buf = args.shift
|
13
|
+
else
|
14
|
+
buf = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
self.class.arguments.each do |type, name|
|
18
|
+
val = buf ? buf.read(type) :
|
19
|
+
args.shift || opts[name] || opts[name.to_s]
|
20
|
+
instance_variable_set("@#{name}", val)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def arguments
|
25
|
+
self.class.arguments.inject({}) do |hash, (type, name)|
|
26
|
+
hash.update name => instance_variable_get("@#{name}")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_binary
|
31
|
+
buf = Transport09::Buffer.new
|
32
|
+
buf.write :short, self.class.parent.id
|
33
|
+
buf.write :short, self.class.id
|
34
|
+
|
35
|
+
bits = []
|
36
|
+
|
37
|
+
self.class.arguments.each do |type, name|
|
38
|
+
val = instance_variable_get("@#{name}")
|
39
|
+
if type == :bit
|
40
|
+
bits << (val || false)
|
41
|
+
else
|
42
|
+
unless bits.empty?
|
43
|
+
buf.write :bit, bits
|
44
|
+
bits = []
|
45
|
+
end
|
46
|
+
buf.write type, val
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
buf.write :bit, bits unless bits.empty?
|
51
|
+
buf.rewind
|
52
|
+
|
53
|
+
buf
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_s
|
57
|
+
to_binary.to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_frame channel = 0
|
61
|
+
Transport09::Method.new(self, channel)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Header
|
66
|
+
def initialize *args
|
67
|
+
opts = args.pop if args.last.is_a? Hash
|
68
|
+
opts ||= {}
|
69
|
+
|
70
|
+
first = args.shift
|
71
|
+
|
72
|
+
if first.is_a? ::Class and first.ancestors.include? Protocol09::Class
|
73
|
+
@klass = first
|
74
|
+
@size = args.shift || 0
|
75
|
+
@weight = args.shift || 0
|
76
|
+
@properties = opts
|
77
|
+
|
78
|
+
elsif first.is_a? Transport09::Buffer or first.is_a? String
|
79
|
+
buf = first
|
80
|
+
buf = Transport09::Buffer.new(buf) unless buf.is_a? Transport09::Buffer
|
81
|
+
|
82
|
+
@klass = Protocol09.classes[buf.read(:short)]
|
83
|
+
@weight = buf.read(:short)
|
84
|
+
@size = buf.read(:longlong)
|
85
|
+
|
86
|
+
props = buf.read(:properties, *klass.properties.map{|type,_| type })
|
87
|
+
@properties = Hash[*klass.properties.map{|_,name| name }.zip(props).reject{|k,v| v.nil? }.flatten]
|
88
|
+
|
89
|
+
else
|
90
|
+
raise ArgumentError, 'Invalid argument'
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
attr_accessor :klass, :size, :weight, :properties
|
95
|
+
|
96
|
+
def to_binary
|
97
|
+
buf = Transport09::Buffer.new
|
98
|
+
buf.write :short, klass.id
|
99
|
+
buf.write :short, weight # XXX rabbitmq only supports weight == 0
|
100
|
+
buf.write :longlong, size
|
101
|
+
buf.write :properties, (klass.properties.map do |type, name|
|
102
|
+
[ type, properties[name] || properties[name.to_s] ]
|
103
|
+
end)
|
104
|
+
buf.rewind
|
105
|
+
buf
|
106
|
+
end
|
107
|
+
|
108
|
+
def to_s
|
109
|
+
to_binary.to_s
|
110
|
+
end
|
111
|
+
|
112
|
+
def to_frame channel = 0
|
113
|
+
Transport09::Header.new(self, channel)
|
114
|
+
end
|
115
|
+
|
116
|
+
def == header
|
117
|
+
[ :klass, :size, :weight, :properties ].inject(true) do |eql, field|
|
118
|
+
eql and __send__(field) == header.__send__(field)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def method_missing meth, *args, &blk
|
123
|
+
@properties.has_key?(meth) || @klass.properties.find{|_,name| name == meth } ? @properties[meth] :
|
124
|
+
super
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.parse buf
|
129
|
+
buf = Transport09::Buffer.new(buf) unless buf.is_a? Transport09::Buffer
|
130
|
+
class_id, method_id = buf.read(:short, :short)
|
131
|
+
classes[class_id].methods[method_id].new(buf)
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
133
135
|
end
|
data/lib/qrack/qrack08.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
$: << File.expand_path(File.dirname(__FILE__))
|
2
4
|
|
3
5
|
require 'protocol/spec08'
|
@@ -9,15 +11,10 @@ require 'transport/frame08'
|
|
9
11
|
require 'qrack/client'
|
10
12
|
require 'qrack/channel'
|
11
13
|
require 'qrack/queue'
|
12
|
-
require '
|
14
|
+
require 'bunny/consumer'
|
15
|
+
require 'qrack/errors'
|
13
16
|
|
14
17
|
module Qrack
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# Errors
|
20
|
-
class BufferOverflowError < StandardError; end
|
21
|
-
class InvalidTypeError < StandardError; end
|
22
|
-
|
23
|
-
end
|
18
|
+
include Protocol
|
19
|
+
include Transport
|
20
|
+
end
|
data/lib/qrack/qrack09.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
$: << File.expand_path(File.dirname(__FILE__))
|
2
4
|
|
3
5
|
require 'protocol/spec09'
|
@@ -9,15 +11,10 @@ require 'transport/frame09'
|
|
9
11
|
require 'qrack/client'
|
10
12
|
require 'qrack/channel'
|
11
13
|
require 'qrack/queue'
|
12
|
-
require '
|
14
|
+
require 'bunny/consumer'
|
15
|
+
require 'qrack/errors'
|
13
16
|
|
14
17
|
module Qrack
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# Errors
|
20
|
-
class BufferOverflowError < StandardError; end
|
21
|
-
class InvalidTypeError < StandardError; end
|
22
|
-
|
23
|
-
end
|
18
|
+
include Protocol09
|
19
|
+
include Transport09
|
20
|
+
end
|
data/lib/qrack/queue.rb
CHANGED
@@ -1,53 +1,40 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# Queue ancestor class
|
4
|
-
class Queue
|
5
|
-
|
6
|
-
attr_reader :name, :client
|
7
|
-
attr_accessor :delivery_tag, :subscription
|
8
|
-
|
9
|
-
=begin rdoc
|
10
|
-
|
11
|
-
=== DESCRIPTION:
|
12
|
-
|
13
|
-
Returns consumer count from Queue#status.
|
1
|
+
# encoding: utf-8
|
14
2
|
|
15
|
-
|
16
|
-
|
17
|
-
def consumer_count
|
18
|
-
s = status
|
19
|
-
s[:consumer_count]
|
20
|
-
end
|
21
|
-
|
22
|
-
=begin rdoc
|
3
|
+
module Qrack
|
23
4
|
|
24
|
-
|
5
|
+
# Queue ancestor class
|
6
|
+
class Queue
|
25
7
|
|
26
|
-
|
8
|
+
# @return [AMQ::Client::Consumer] Default consumer (registered with {Queue#subscribe}).
|
9
|
+
attr_accessor :default_consumer
|
27
10
|
|
28
|
-
|
11
|
+
attr_reader :name, :client
|
29
12
|
|
30
|
-
|
31
|
-
s = status
|
32
|
-
s[:message_count]
|
33
|
-
end
|
13
|
+
attr_accessor :delivery_tag
|
34
14
|
|
35
|
-
=begin rdoc
|
36
15
|
|
37
|
-
|
16
|
+
# Returns consumer count from {Queue#status}.
|
17
|
+
def consumer_count
|
18
|
+
s = status
|
19
|
+
s[:consumer_count]
|
20
|
+
end
|
38
21
|
|
39
|
-
|
22
|
+
# Returns message count from {Queue#status}.
|
23
|
+
def message_count
|
24
|
+
s = status
|
25
|
+
s[:message_count]
|
26
|
+
end
|
40
27
|
|
41
|
-
|
28
|
+
# Publishes a message to the queue via the default nameless '' direct exchange.
|
42
29
|
|
43
|
-
nil
|
30
|
+
# @return [NilClass] nil
|
31
|
+
# @deprecated
|
32
|
+
# @note This method will be removed before 0.8 release.
|
33
|
+
def publish(data, opts = {})
|
34
|
+
Bunny.deprecation_warning("Qrack::Queue#publish", "0.8")
|
35
|
+
exchange.publish(data, opts)
|
36
|
+
end
|
44
37
|
|
45
|
-
|
38
|
+
end
|
46
39
|
|
47
|
-
def publish(data, opts = {})
|
48
|
-
exchange.publish(data, opts)
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
40
|
end
|
data/lib/qrack/subscription.rb
CHANGED
@@ -1,102 +1,103 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
#################################################
|
4
|
+
# WARNING: THIS CLASS IS DEPRECATED, DO NOT #
|
5
|
+
# USE IT DIRECTLY! USE BUNNY::CONSUMER INSTEAD! #
|
6
|
+
#################################################
|
7
|
+
|
1
8
|
module Qrack
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
end
|
99
|
-
|
100
|
-
end
|
101
|
-
|
102
|
-
end
|
9
|
+
# Subscription ancestor class
|
10
|
+
# @deprecated
|
11
|
+
class Subscription
|
12
|
+
|
13
|
+
attr_accessor :consumer_tag, :delivery_tag, :message_max, :timeout, :ack, :exclusive
|
14
|
+
attr_reader :client, :queue, :message_count
|
15
|
+
|
16
|
+
def initialize(client, queue, opts = {})
|
17
|
+
@client = client
|
18
|
+
@queue = queue
|
19
|
+
|
20
|
+
# Get timeout value
|
21
|
+
@timeout = opts[:timeout] || nil
|
22
|
+
|
23
|
+
# Get maximum amount of messages to process
|
24
|
+
@message_max = opts[:message_max] || nil
|
25
|
+
|
26
|
+
# If a consumer tag is not passed in the server will generate one
|
27
|
+
@consumer_tag = opts[:consumer_tag] || nil
|
28
|
+
|
29
|
+
# Ignore the :nowait option if passed, otherwise program will hang waiting for a
|
30
|
+
# response from the server causing an error.
|
31
|
+
opts.delete(:nowait)
|
32
|
+
|
33
|
+
# Do we want to have to provide an acknowledgement?
|
34
|
+
@ack = opts[:ack] || nil
|
35
|
+
|
36
|
+
# Does this consumer want exclusive use of the queue?
|
37
|
+
@exclusive = opts[:exclusive] || false
|
38
|
+
|
39
|
+
# Initialize message counter
|
40
|
+
@message_count = 0
|
41
|
+
|
42
|
+
# Store options
|
43
|
+
@opts = opts
|
44
|
+
end
|
45
|
+
|
46
|
+
def start(&blk)
|
47
|
+
# Do not process any messages if zero message_max
|
48
|
+
if message_max == 0
|
49
|
+
return
|
50
|
+
end
|
51
|
+
|
52
|
+
# Notify server about new consumer
|
53
|
+
setup_consumer
|
54
|
+
|
55
|
+
# Start subscription loop
|
56
|
+
loop do
|
57
|
+
|
58
|
+
begin
|
59
|
+
method = client.next_method(:timeout => timeout)
|
60
|
+
rescue Qrack::ClientTimeout
|
61
|
+
queue.unsubscribe
|
62
|
+
break
|
63
|
+
end
|
64
|
+
|
65
|
+
# Increment message counter
|
66
|
+
@message_count += 1
|
67
|
+
|
68
|
+
# get delivery tag to use for acknowledge
|
69
|
+
queue.delivery_tag = method.delivery_tag if @ack
|
70
|
+
|
71
|
+
header = client.next_payload
|
72
|
+
|
73
|
+
# If maximum frame size is smaller than message payload body then message
|
74
|
+
# will have a message header and several message bodies
|
75
|
+
msg = ''
|
76
|
+
while msg.length < header.size
|
77
|
+
msg << client.next_payload
|
78
|
+
end
|
79
|
+
|
80
|
+
# If block present, pass the message info to the block for processing
|
81
|
+
blk.call({:header => header, :payload => msg, :delivery_details => method.arguments}) if !blk.nil?
|
82
|
+
|
83
|
+
# Exit loop if message_max condition met
|
84
|
+
if (!message_max.nil? and message_count == message_max)
|
85
|
+
# Stop consuming messages
|
86
|
+
queue.unsubscribe()
|
87
|
+
# Acknowledge receipt of the final message
|
88
|
+
queue.ack() if @ack
|
89
|
+
# Quit the loop
|
90
|
+
break
|
91
|
+
end
|
92
|
+
|
93
|
+
# Have to do the ack here because the ack triggers the release of messages from the server
|
94
|
+
# if you are using Client#qos prefetch and you will get extra messages sent through before
|
95
|
+
# the unsubscribe takes effect to stop messages being sent to this consumer unless the ack is
|
96
|
+
# deferred.
|
97
|
+
queue.ack() if @ack
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|