amqp 0.7.0.pre → 0.7.0
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.
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/CHANGELOG +8 -2
- data/CONTRIBUTORS +22 -0
- data/Gemfile +3 -3
- data/README.md +20 -11
- data/Rakefile +30 -6
- data/amqp.gemspec +1 -1
- data/bin/cleanify.rb +50 -0
- data/examples/amqp/simple.rb +6 -4
- data/examples/mq/ack.rb +8 -6
- data/examples/mq/automatic_binding_for_default_direct_exchange.rb +65 -0
- data/examples/mq/callbacks.rb +9 -1
- data/examples/mq/clock.rb +17 -17
- data/examples/mq/hashtable.rb +19 -10
- data/examples/mq/internal.rb +13 -11
- data/examples/mq/logger.rb +38 -36
- data/examples/mq/multiclock.rb +16 -7
- data/examples/mq/pingpong.rb +16 -7
- data/examples/mq/pop.rb +8 -6
- data/examples/mq/primes-simple.rb +2 -0
- data/examples/mq/primes.rb +7 -5
- data/examples/mq/stocks.rb +14 -5
- data/lib/amqp.rb +12 -8
- data/lib/amqp/buffer.rb +35 -158
- data/lib/amqp/client.rb +34 -22
- data/lib/amqp/frame.rb +8 -64
- data/lib/amqp/protocol.rb +21 -70
- data/lib/amqp/server.rb +11 -9
- data/lib/amqp/spec.rb +8 -6
- data/lib/amqp/version.rb +2 -0
- data/lib/ext/blankslate.rb +3 -1
- data/lib/ext/em.rb +2 -0
- data/lib/ext/emfork.rb +13 -11
- data/lib/mq.rb +253 -156
- data/lib/mq/collection.rb +6 -88
- data/lib/mq/exchange.rb +70 -13
- data/lib/mq/header.rb +12 -6
- data/lib/mq/logger.rb +9 -7
- data/lib/mq/queue.rb +42 -30
- data/lib/mq/rpc.rb +6 -4
- data/protocol/codegen.rb +20 -18
- data/research/api.rb +10 -46
- data/research/primes-forked.rb +9 -7
- data/research/primes-processes.rb +74 -72
- data/research/primes-threaded.rb +9 -7
- data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +61 -0
- data/spec/mq_helper.rb +70 -0
- data/spec/spec_helper.rb +84 -29
- data/spec/unit/amqp/buffer_spec.rb +178 -0
- data/spec/unit/amqp/client_spec.rb +472 -0
- data/spec/unit/amqp/frame_spec.rb +60 -0
- data/spec/unit/amqp/misc_spec.rb +123 -0
- data/spec/unit/amqp/protocol_spec.rb +53 -0
- data/spec/unit/mq/channel_close_spec.rb +15 -0
- data/spec/unit/mq/collection_spec.rb +129 -0
- data/spec/unit/mq/exchange_declaration_spec.rb +524 -0
- data/spec/unit/mq/misc_spec.rb +228 -0
- data/spec/unit/mq/mq_basic_spec.rb +39 -0
- data/spec/unit/mq/queue_declaration_spec.rb +97 -0
- data/spec/unit/mq/queue_spec.rb +71 -0
- metadata +33 -21
- data/Gemfile.lock +0 -16
- data/old/README +0 -30
- data/old/Rakefile +0 -12
- data/old/amqp-0.8.json +0 -606
- data/old/amqp_spec.rb +0 -796
- data/old/amqpc.rb +0 -695
- data/old/codegen.rb +0 -148
- data/spec/channel_close_spec.rb +0 -13
- data/spec/sync_async_spec.rb +0 -52
data/lib/amqp/frame.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require File.expand_path('../spec', __FILE__)
|
2
4
|
require File.expand_path('../buffer', __FILE__)
|
3
5
|
require File.expand_path('../protocol', __FILE__)
|
4
6
|
|
5
7
|
module AMQP
|
6
8
|
class Frame #:nodoc: all
|
7
|
-
def initialize
|
9
|
+
def initialize(payload = nil, channel = 0)
|
8
10
|
@channel, @payload = channel, payload
|
9
11
|
end
|
10
12
|
attr_accessor :channel, :payload
|
@@ -12,7 +14,7 @@ module AMQP
|
|
12
14
|
def id
|
13
15
|
self.class::ID
|
14
16
|
end
|
15
|
-
|
17
|
+
|
16
18
|
def to_binary
|
17
19
|
buf = Buffer.new
|
18
20
|
buf.write :octet, id
|
@@ -32,11 +34,11 @@ module AMQP
|
|
32
34
|
eql and __send__(field) == frame.__send__(field)
|
33
35
|
end
|
34
36
|
end
|
35
|
-
|
37
|
+
|
36
38
|
class Invalid < StandardError; end
|
37
|
-
|
39
|
+
|
38
40
|
class Method
|
39
|
-
def initialize
|
41
|
+
def initialize(payload = nil, channel = 0)
|
40
42
|
super
|
41
43
|
unless @payload.is_a? Protocol::Class::Method or @payload.nil?
|
42
44
|
@payload = Protocol.parse(@payload)
|
@@ -45,7 +47,7 @@ module AMQP
|
|
45
47
|
end
|
46
48
|
|
47
49
|
class Header
|
48
|
-
def initialize
|
50
|
+
def initialize(payload = nil, channel = 0)
|
49
51
|
super
|
50
52
|
unless @payload.is_a? Protocol::Header or @payload.nil?
|
51
53
|
@payload = Protocol::Header.new(@payload)
|
@@ -64,61 +66,3 @@ module AMQP
|
|
64
66
|
end
|
65
67
|
end
|
66
68
|
end
|
67
|
-
|
68
|
-
if $0 =~ /bacon/ or $0 == __FILE__
|
69
|
-
require 'bacon'
|
70
|
-
include AMQP
|
71
|
-
|
72
|
-
describe Frame do
|
73
|
-
should 'handle basic frame types' do
|
74
|
-
Frame::Method.new.id.should == 1
|
75
|
-
Frame::Header.new.id.should == 2
|
76
|
-
Frame::Body.new.id.should == 3
|
77
|
-
end
|
78
|
-
|
79
|
-
should 'convert method frames to binary' do
|
80
|
-
meth = Protocol::Connection::Secure.new :challenge => 'secret'
|
81
|
-
|
82
|
-
frame = Frame::Method.new(meth)
|
83
|
-
frame.to_binary.should.be.kind_of? Buffer
|
84
|
-
frame.to_s.should == [ 1, 0, meth.to_s.length, meth.to_s, 206 ].pack('CnNa*C')
|
85
|
-
end
|
86
|
-
|
87
|
-
should 'convert binary to method frames' do
|
88
|
-
orig = Frame::Method.new Protocol::Connection::Secure.new(:challenge => 'secret')
|
89
|
-
|
90
|
-
copy = Frame.parse(orig.to_binary)
|
91
|
-
copy.should == orig
|
92
|
-
end
|
93
|
-
|
94
|
-
should 'ignore partial frames until ready' do
|
95
|
-
frame = Frame::Method.new Protocol::Connection::Secure.new(:challenge => 'secret')
|
96
|
-
data = frame.to_s
|
97
|
-
|
98
|
-
buf = Buffer.new
|
99
|
-
Frame.parse(buf).should == nil
|
100
|
-
|
101
|
-
buf << data[0..5]
|
102
|
-
Frame.parse(buf).should == nil
|
103
|
-
|
104
|
-
buf << data[6..-1]
|
105
|
-
Frame.parse(buf).should == frame
|
106
|
-
|
107
|
-
Frame.parse(buf).should == nil
|
108
|
-
end
|
109
|
-
|
110
|
-
should 'convert header frames to binary' do
|
111
|
-
head = Protocol::Header.new(Protocol::Basic, :priority => 1)
|
112
|
-
|
113
|
-
frame = Frame::Header.new(head)
|
114
|
-
frame.to_s.should == [ 2, 0, head.to_s.length, head.to_s, 206 ].pack('CnNa*C')
|
115
|
-
end
|
116
|
-
|
117
|
-
should 'convert binary to header frame' do
|
118
|
-
orig = Frame::Header.new Protocol::Header.new(Protocol::Basic, :priority => 1)
|
119
|
-
|
120
|
-
copy = Frame.parse(orig.to_binary)
|
121
|
-
copy.should == orig
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
data/lib/amqp/protocol.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require File.expand_path('../spec', __FILE__)
|
2
4
|
require File.expand_path('../buffer', __FILE__)
|
3
5
|
|
@@ -5,12 +7,12 @@ module AMQP
|
|
5
7
|
module Protocol
|
6
8
|
#:stopdoc:
|
7
9
|
class Class::Method
|
8
|
-
def initialize
|
10
|
+
def initialize(*args)
|
9
11
|
opts = args.pop if args.last.is_a? Hash
|
10
12
|
opts ||= {}
|
11
|
-
|
13
|
+
|
12
14
|
@debug = 1 # XXX hack, p(obj) == '' if no instance vars are set
|
13
|
-
|
15
|
+
|
14
16
|
if args.size == 1 and args.first.is_a? Buffer
|
15
17
|
buf = args.shift
|
16
18
|
else
|
@@ -55,19 +57,19 @@ module AMQP
|
|
55
57
|
|
56
58
|
buf
|
57
59
|
end
|
58
|
-
|
60
|
+
|
59
61
|
def to_s
|
60
62
|
to_binary.to_s
|
61
63
|
end
|
62
|
-
|
63
|
-
def to_frame
|
64
|
+
|
65
|
+
def to_frame(channel = 0)
|
64
66
|
Frame::Method.new(self, channel)
|
65
67
|
end
|
66
68
|
end
|
67
69
|
|
68
70
|
#:startdoc:
|
69
71
|
#
|
70
|
-
# Contains a properties hash that holds some potentially interesting
|
72
|
+
# Contains a properties hash that holds some potentially interesting
|
71
73
|
# information.
|
72
74
|
# * :delivery_mode
|
73
75
|
# 1 equals transient.
|
@@ -89,12 +91,12 @@ module AMQP
|
|
89
91
|
# A monotonically increasing integer. This number should not be trusted
|
90
92
|
# as a sequence number. There is no guarantee it won't get reset.
|
91
93
|
class Header
|
92
|
-
def initialize
|
94
|
+
def initialize(*args)
|
93
95
|
opts = args.pop if args.last.is_a? Hash
|
94
96
|
opts ||= {}
|
95
|
-
|
97
|
+
|
96
98
|
first = args.shift
|
97
|
-
|
99
|
+
|
98
100
|
if first.is_a? ::Class and first.ancestors.include? Protocol::Class
|
99
101
|
@klass = first
|
100
102
|
@size = args.shift || 0
|
@@ -104,21 +106,21 @@ module AMQP
|
|
104
106
|
elsif first.is_a? Buffer or first.is_a? String
|
105
107
|
buf = first
|
106
108
|
buf = Buffer.new(buf) unless buf.is_a? Buffer
|
107
|
-
|
109
|
+
|
108
110
|
@klass = Protocol.classes[buf.read(:short)]
|
109
111
|
@weight = buf.read(:short)
|
110
112
|
@size = buf.read(:longlong)
|
111
113
|
|
112
|
-
props = buf.read(:properties, *klass.properties.map{|type,_| type })
|
113
|
-
@properties = Hash[*klass.properties.map{|_,name| name }.zip(props).reject{|k,v| v.nil? }.flatten]
|
114
|
+
props = buf.read(:properties, *klass.properties.map { |type, _| type })
|
115
|
+
@properties = Hash[*klass.properties.map { |_, name| name }.zip(props).reject { |k, v| v.nil? }.flatten]
|
114
116
|
|
115
117
|
else
|
116
118
|
raise ArgumentError, 'Invalid argument'
|
117
119
|
end
|
118
|
-
|
120
|
+
|
119
121
|
end
|
120
122
|
attr_accessor :klass, :size, :weight, :properties
|
121
|
-
|
123
|
+
|
122
124
|
def to_binary
|
123
125
|
buf = Buffer.new
|
124
126
|
buf.write :short, klass.id
|
@@ -130,12 +132,12 @@ module AMQP
|
|
130
132
|
buf.rewind
|
131
133
|
buf
|
132
134
|
end
|
133
|
-
|
135
|
+
|
134
136
|
def to_s
|
135
137
|
to_binary.to_s
|
136
138
|
end
|
137
139
|
|
138
|
-
def to_frame
|
140
|
+
def to_frame(channel = 0)
|
139
141
|
Frame::Header.new(self, channel)
|
140
142
|
end
|
141
143
|
|
@@ -145,8 +147,8 @@ module AMQP
|
|
145
147
|
end
|
146
148
|
end
|
147
149
|
|
148
|
-
def method_missing
|
149
|
-
@properties.has_key?(meth) || @klass.properties.find{|_,name| name == meth } ? @properties[meth] :
|
150
|
+
def method_missing(meth, *args, &blk)
|
151
|
+
@properties.has_key?(meth) || @klass.properties.find { |_, name| name == meth } ? @properties[meth] :
|
150
152
|
super
|
151
153
|
end
|
152
154
|
end
|
@@ -159,54 +161,3 @@ module AMQP
|
|
159
161
|
#:stopdoc:
|
160
162
|
end
|
161
163
|
end
|
162
|
-
|
163
|
-
if $0 =~ /bacon/ or $0 == __FILE__
|
164
|
-
require 'bacon'
|
165
|
-
include AMQP
|
166
|
-
|
167
|
-
describe Protocol do
|
168
|
-
should 'instantiate methods with arguments' do
|
169
|
-
meth = Protocol::Connection::StartOk.new nil, 'PLAIN', nil, 'en_US'
|
170
|
-
meth.locale.should == 'en_US'
|
171
|
-
end
|
172
|
-
|
173
|
-
should 'instantiate methods with named parameters' do
|
174
|
-
meth = Protocol::Connection::StartOk.new :locale => 'en_US',
|
175
|
-
:mechanism => 'PLAIN'
|
176
|
-
meth.locale.should == 'en_US'
|
177
|
-
end
|
178
|
-
|
179
|
-
should 'convert methods to binary' do
|
180
|
-
meth = Protocol::Connection::Secure.new :challenge => 'secret'
|
181
|
-
meth.to_binary.should.be.kind_of? Buffer
|
182
|
-
|
183
|
-
meth.to_s.should == [ 10, 20, 6, 'secret' ].pack('nnNa*')
|
184
|
-
end
|
185
|
-
|
186
|
-
should 'convert binary to method' do
|
187
|
-
orig = Protocol::Connection::Secure.new :challenge => 'secret'
|
188
|
-
copy = Protocol.parse orig.to_binary
|
189
|
-
orig.should == copy
|
190
|
-
end
|
191
|
-
|
192
|
-
should 'convert headers to binary' do
|
193
|
-
head = Protocol::Header.new Protocol::Basic,
|
194
|
-
size = 5,
|
195
|
-
weight = 0,
|
196
|
-
:content_type => 'text/json',
|
197
|
-
:delivery_mode => 1,
|
198
|
-
:priority => 1
|
199
|
-
head.to_s.should == [ 60, weight, 0, size, 0b1001_1000_0000_0000, 9, 'text/json', 1, 1 ].pack('nnNNnCa*CC')
|
200
|
-
end
|
201
|
-
|
202
|
-
should 'convert binary to header' do
|
203
|
-
orig = Protocol::Header.new Protocol::Basic,
|
204
|
-
size = 5,
|
205
|
-
weight = 0,
|
206
|
-
:content_type => 'text/json',
|
207
|
-
:delivery_mode => 1,
|
208
|
-
:priority => 1
|
209
|
-
Protocol::Header.new(orig.to_binary).should == orig
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
data/lib/amqp/server.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require File.expand_path('../frame', __FILE__)
|
2
4
|
|
3
5
|
module AMQP
|
@@ -8,17 +10,17 @@ module AMQP
|
|
8
10
|
@started = false
|
9
11
|
end
|
10
12
|
|
11
|
-
def receive_data
|
13
|
+
def receive_data(data)
|
12
14
|
@buf << data
|
13
15
|
|
14
16
|
unless @started
|
15
17
|
if @buf.size >= 8
|
16
|
-
if @buf.slice!(0,8) == "AMQP\001\001\b\000"
|
18
|
+
if @buf.slice!(0, 8) == "AMQP\001\001\b\000"
|
17
19
|
send Protocol::Connection::Start.new(
|
18
20
|
8,
|
19
21
|
0,
|
20
22
|
{
|
21
|
-
:information => 'Licensed under the Ruby license. See http://github.com/
|
23
|
+
:information => 'Licensed under the Ruby license. See http://github.com/ruby-amqp/amqp',
|
22
24
|
:copyright => 'Copyright (c) 2008-2009 Aman Gupta',
|
23
25
|
:platform => 'Ruby/EventMachine',
|
24
26
|
:version => '0.6.1',
|
@@ -42,7 +44,7 @@ module AMQP
|
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
45
|
-
def process_frame
|
47
|
+
def process_frame(frame)
|
46
48
|
channel = frame.channel
|
47
49
|
|
48
50
|
case method = frame.payload
|
@@ -67,7 +69,7 @@ module AMQP
|
|
67
69
|
end
|
68
70
|
end
|
69
71
|
|
70
|
-
def send
|
72
|
+
def send(data, opts = {})
|
71
73
|
channel = opts[:channel] ||= 0
|
72
74
|
data = data.to_frame(channel) unless data.is_a? Frame
|
73
75
|
data.channel = channel
|
@@ -81,8 +83,8 @@ module AMQP
|
|
81
83
|
end
|
82
84
|
|
83
85
|
private
|
84
|
-
|
85
|
-
def log
|
86
|
+
|
87
|
+
def log(*args)
|
86
88
|
require 'pp'
|
87
89
|
pp args
|
88
90
|
puts
|
@@ -93,7 +95,7 @@ end
|
|
93
95
|
if __FILE__ == $0
|
94
96
|
require 'rubygems'
|
95
97
|
require 'eventmachine'
|
96
|
-
EM.run{
|
98
|
+
EM.run {
|
97
99
|
AMQP::Server.start
|
98
100
|
}
|
99
|
-
end
|
101
|
+
end
|
data/lib/amqp/spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
|
2
4
|
#:stopdoc:
|
3
5
|
# this file was autogenerated on Thu Jul 09 15:17:33 -0700 2009
|
@@ -76,7 +78,7 @@ module AMQP
|
|
76
78
|
end
|
77
79
|
]
|
78
80
|
end
|
79
|
-
|
81
|
+
|
80
82
|
def properties() @properties ||= [] end
|
81
83
|
|
82
84
|
def id() self::ID end
|
@@ -93,10 +95,10 @@ module AMQP
|
|
93
95
|
end
|
94
96
|
]
|
95
97
|
end
|
96
|
-
|
98
|
+
|
97
99
|
def arguments() @arguments ||= [] end
|
98
100
|
|
99
|
-
def section() Protocol.const_get(self.to_s[/Protocol::(.+?)::/,1]) end
|
101
|
+
def section() Protocol.const_get(self.to_s[/Protocol::(.+?)::/, 1]) end
|
100
102
|
def id() self::ID end
|
101
103
|
def name() self::NAME end
|
102
104
|
end
|
@@ -107,9 +109,9 @@ module AMQP
|
|
107
109
|
end
|
108
110
|
end
|
109
111
|
end
|
110
|
-
|
112
|
+
|
111
113
|
def self.methods() @methods ||= {} end
|
112
|
-
|
114
|
+
|
113
115
|
def self.Method(id, name)
|
114
116
|
@_base_methods ||= {}
|
115
117
|
@_base_methods[id] ||= ::Class.new(Method) do
|
@@ -142,7 +144,7 @@ module AMQP
|
|
142
144
|
end
|
143
145
|
end
|
144
146
|
end
|
145
|
-
|
147
|
+
|
146
148
|
module AMQP
|
147
149
|
module Protocol
|
148
150
|
class Connection < Class( 10, :connection ); end
|
data/lib/amqp/version.rb
CHANGED
data/lib/ext/blankslate.rb
CHANGED
data/lib/ext/em.rb
CHANGED
data/lib/ext/emfork.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
EMFORK = $0 == __FILE__
|
2
4
|
|
3
5
|
if EMFORK
|
@@ -11,21 +13,21 @@ require 'eventmachine'
|
|
11
13
|
# helper to fork off EM reactors
|
12
14
|
def EM.fork num = 1, &blk
|
13
15
|
unless @forks
|
14
|
-
trap('CHLD'){
|
16
|
+
trap('CHLD') {
|
15
17
|
pid = Process.wait
|
16
18
|
p [:pid, pid, :died] if EMFORK
|
17
19
|
block = @forks.delete(pid)
|
18
20
|
EM.fork(1, &block)
|
19
21
|
}
|
20
22
|
|
21
|
-
trap('EXIT'){
|
23
|
+
trap('EXIT') {
|
22
24
|
p [:pid, Process.pid, :exit] if EMFORK
|
23
|
-
@forks.keys.each{ |pid|
|
25
|
+
@forks.keys.each { |pid|
|
24
26
|
p [:pid, Process.pid, :killing, pid] if EMFORK
|
25
27
|
Process.kill('USR1', pid)
|
26
28
|
}
|
27
29
|
}
|
28
|
-
|
30
|
+
|
29
31
|
@forks = {}
|
30
32
|
end
|
31
33
|
|
@@ -33,9 +35,9 @@ def EM.fork num = 1, &blk
|
|
33
35
|
pid = EM.fork_reactor do
|
34
36
|
p [:pid, Process.pid, :started] if EMFORK
|
35
37
|
|
36
|
-
trap('USR1'){ EM.stop_event_loop }
|
37
|
-
trap('CHLD'){}
|
38
|
-
trap('EXIT'){}
|
38
|
+
trap('USR1') { EM.stop_event_loop }
|
39
|
+
trap('CHLD') {}
|
40
|
+
trap('EXIT') {}
|
39
41
|
|
40
42
|
blk.call
|
41
43
|
end
|
@@ -52,12 +54,12 @@ end
|
|
52
54
|
if EMFORK
|
53
55
|
p 'starting reactor'
|
54
56
|
|
55
|
-
trap('INT'){ EM.stop_event_loop }
|
57
|
+
trap('INT') { EM.stop_event_loop }
|
56
58
|
|
57
|
-
EM.run{
|
59
|
+
EM.run {
|
58
60
|
p [:parent, Process.pid]
|
59
61
|
|
60
|
-
EM.fork(2){
|
62
|
+
EM.fork(2) {
|
61
63
|
EM.add_periodic_timer(1) do
|
62
64
|
p [:fork, Process.pid, :ping]
|
63
65
|
end
|
@@ -66,4 +68,4 @@ if EMFORK
|
|
66
68
|
}
|
67
69
|
|
68
70
|
p 'reactor stopped'
|
69
|
-
end
|
71
|
+
end
|