amqp 0.5.0 → 0.5.1
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/README +39 -7
- data/examples/clock.rb +6 -3
- data/examples/pingpong.rb +18 -26
- data/examples/primes-forked.rb +63 -0
- data/examples/primes-processes.rb +135 -0
- data/examples/primes-simple.rb +19 -0
- data/examples/primes-threaded.rb +49 -0
- data/examples/primes.rb +99 -0
- data/examples/stocks.rb +1 -1
- data/lib/amqp/buffer.rb +20 -12
- data/lib/amqp/client.rb +2 -2
- data/lib/amqp/spec.rb +5 -0
- data/lib/emfork.rb +67 -0
- data/lib/mq.rb +34 -130
- data/lib/mq/exchange.rb +36 -0
- data/lib/mq/queue.rb +52 -0
- data/lib/mq/rpc.rb +51 -0
- data/protocol/codegen.rb +8 -1
- metadata +23 -5
data/README
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
Simple AMQP
|
1
|
+
Simple AMQP driver for Ruby/EventMachine.
|
2
|
+
|
3
|
+
This library was tested primarily with RabbitMQ, although it should be compatible with any
|
4
|
+
server implementing the AMQP 0-8 spec.
|
2
5
|
|
3
6
|
To use with RabbitMQ, first run the server:
|
4
7
|
|
@@ -7,11 +10,22 @@ To use with RabbitMQ, first run the server:
|
|
7
10
|
cd rabbitmq-server
|
8
11
|
make run
|
9
12
|
|
10
|
-
|
13
|
+
To get started, refer to the various bundled examples:
|
14
|
+
|
15
|
+
ruby examples/pingpong.rb # 1-1 communication using amq.direct
|
16
|
+
ruby examples/clock.rb # 1-N communication using amq.fanout
|
17
|
+
ruby examples/stocks.rb # 1-subscriber communication using amq.topic
|
18
|
+
ruby examples/hashtable.rb # simple async rpc layer
|
19
|
+
ruby examples/primes.rb 4 # parallelized prime number generation
|
20
|
+
|
21
|
+
For more details into the lower level AMQP client API, run the simple client example:
|
11
22
|
|
12
23
|
ruby examples/simple.rb
|
13
24
|
|
14
|
-
|
25
|
+
Or refer to protocol/doc.txt, which enumerates packets sent between a server and client
|
26
|
+
during a typical session, in both binary and decoded formats.
|
27
|
+
|
28
|
+
To run the test suite:
|
15
29
|
|
16
30
|
rake spec
|
17
31
|
|
@@ -24,7 +38,25 @@ Special thanks to Dmitriy Samovskiy, Ben Hood and Tony Garnock-Jones.
|
|
24
38
|
|
25
39
|
Other AMQP resources:
|
26
40
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
41
|
+
Servers:
|
42
|
+
RabbitMQ (Rabbit Technologies, Erlang/OTP, MPL) http://rabbitmq.com
|
43
|
+
OpenAMP (iMatrix, C, GPL2) http://openamq.org
|
44
|
+
ActiveMQ (Apache Foundation, Java, apache2) http://activemq.apache.org/
|
45
|
+
|
46
|
+
John O'Hara's article on the history of AMQP:
|
47
|
+
http://www.acmqueue.org/modules.php?name=Content&pa=showpage&pid=485
|
48
|
+
|
49
|
+
Barry Pederson's py-amqplib:
|
50
|
+
http://barryp.org/software/py-amqplib/
|
51
|
+
|
52
|
+
Ben Hood's article on writing an AMQP client:
|
53
|
+
http://hopper.squarespace.com/blog/2008/6/21/build-your-own-amqp-client.html
|
54
|
+
|
55
|
+
Dmitriy Samovskiy's introduction to Ruby+QPid+RabbitMQ:
|
56
|
+
http://somic-org.homelinux.org/blog/2008/06/24/ruby-amqp-rabbitmq-example/
|
57
|
+
|
58
|
+
Ben Hood's AMQP client in AS3:
|
59
|
+
http://github.com/0x6e6562/as3-amqp
|
60
|
+
|
61
|
+
RabbitMQ's protocol code generator:
|
62
|
+
http://hg.rabbitmq.com/rabbitmq-codegen/
|
data/examples/clock.rb
CHANGED
@@ -9,18 +9,21 @@ EM.run{
|
|
9
9
|
|
10
10
|
# AMQP.logging = true
|
11
11
|
|
12
|
+
clock = MQ.new.fanout('clock')
|
12
13
|
EM.add_periodic_timer(1){
|
13
14
|
puts
|
14
15
|
|
15
16
|
log :publishing, time = Time.now
|
16
|
-
|
17
|
+
clock.publish(Marshal.dump(time))
|
17
18
|
}
|
18
19
|
|
19
|
-
MQ.new
|
20
|
+
amq = MQ.new
|
21
|
+
amq.queue('every second').bind(amq.fanout('clock')).subscribe{ |time|
|
20
22
|
log 'every second', :received, Marshal.load(time)
|
21
23
|
}
|
22
24
|
|
23
|
-
MQ.new
|
25
|
+
amq = MQ.new
|
26
|
+
amq.queue('every 5 seconds').bind(amq.fanout('clock')).subscribe{ |time|
|
24
27
|
time = Marshal.load(time)
|
25
28
|
log 'every 5 seconds', :received, time if time.strftime('%S').to_i%5 == 0
|
26
29
|
}
|
data/examples/pingpong.rb
CHANGED
@@ -10,44 +10,36 @@ EM.run{
|
|
10
10
|
# AMQP.logging = true
|
11
11
|
|
12
12
|
amq = MQ.new
|
13
|
-
|
14
|
-
|
13
|
+
EM.add_periodic_timer(1){
|
14
|
+
puts
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
log :sending, 'ping'
|
17
|
+
amq.queue('one').publish('ping')
|
18
|
+
}
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
20
|
+
amq = MQ.new
|
21
|
+
amq.queue('one').subscribe{ |msg|
|
22
|
+
log 'one', :received, msg, :sending, 'pong'
|
23
|
+
amq.queue('two').publish('pong')
|
24
24
|
}
|
25
25
|
|
26
26
|
amq = MQ.new
|
27
27
|
amq.queue('two').subscribe{ |msg|
|
28
28
|
log 'two', :received, msg
|
29
|
-
puts
|
30
|
-
}
|
31
|
-
|
32
|
-
amq = MQ.new
|
33
|
-
amq.direct.publish('ding', :key => 'one')
|
34
|
-
EM.add_periodic_timer(1){
|
35
|
-
log :sending, 'ping', :to => 'one', :from => 'two'
|
36
|
-
amq.direct.publish('ping', :key => 'one', :reply_to => 'two')
|
37
29
|
}
|
38
30
|
|
39
31
|
}
|
40
32
|
|
41
33
|
__END__
|
42
34
|
|
43
|
-
[
|
35
|
+
[Sun Jul 20 03:52:24 -0700 2008, :sending, "ping"]
|
36
|
+
[Sun Jul 20 03:52:24 -0700 2008, "one", :received, "ping", :sending, "pong"]
|
37
|
+
[Sun Jul 20 03:52:24 -0700 2008, "two", :received, "pong"]
|
44
38
|
|
45
|
-
[
|
46
|
-
[
|
47
|
-
[
|
48
|
-
[Thu Jul 17 21:23:56 -0700 2008, "two", :received, "pong"]
|
39
|
+
[Sun Jul 20 03:52:25 -0700 2008, :sending, "ping"]
|
40
|
+
[Sun Jul 20 03:52:25 -0700 2008, "one", :received, "ping", :sending, "pong"]
|
41
|
+
[Sun Jul 20 03:52:25 -0700 2008, "two", :received, "pong"]
|
49
42
|
|
50
|
-
[
|
51
|
-
[
|
52
|
-
[
|
53
|
-
[Thu Jul 17 21:23:57 -0700 2008, "two", :received, "pong"]
|
43
|
+
[Sun Jul 20 03:52:26 -0700 2008, :sending, "ping"]
|
44
|
+
[Sun Jul 20 03:52:26 -0700 2008, "one", :received, "ping", :sending, "pong"]
|
45
|
+
[Sun Jul 20 03:52:26 -0700 2008, "two", :received, "pong"]
|
@@ -0,0 +1,63 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
+
require 'mq'
|
3
|
+
|
4
|
+
MAX = 5000
|
5
|
+
|
6
|
+
def EM.fork &blk
|
7
|
+
raise if reactor_running?
|
8
|
+
|
9
|
+
unless @forks
|
10
|
+
at_exit{
|
11
|
+
@forks.each{ |pid| Process.kill('KILL', pid) }
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
(@forks ||= []) << Kernel.fork do
|
16
|
+
EM.run(&blk)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def log *args
|
21
|
+
p args
|
22
|
+
end
|
23
|
+
|
24
|
+
# MQ.logging = true
|
25
|
+
|
26
|
+
# worker
|
27
|
+
|
28
|
+
workers = ARGV[0] ? (Integer(ARGV[0]) rescue 2) : 2
|
29
|
+
|
30
|
+
workers.times do
|
31
|
+
EM.fork{
|
32
|
+
log "prime checker", Process.pid, :started
|
33
|
+
|
34
|
+
class Fixnum
|
35
|
+
def prime?
|
36
|
+
('1' * self) !~ /^1?$|^(11+?)\1+$/
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
MQ.queue('prime checker').subscribe{ |info, num|
|
41
|
+
log "prime checker #{Process.pid}", :prime?, num
|
42
|
+
if Integer(num).prime?
|
43
|
+
MQ.queue(info.reply_to).publish(num, :reply_to => Process.pid)
|
44
|
+
end
|
45
|
+
}
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
# controller
|
50
|
+
|
51
|
+
EM.run{
|
52
|
+
MQ.queue('prime collector').subscribe{ |info, prime|
|
53
|
+
log 'prime collector', :received, prime, :from, info.reply_to
|
54
|
+
(@primes ||= []) << Integer(prime)
|
55
|
+
EM.stop_event_loop if prime == '499'
|
56
|
+
}
|
57
|
+
|
58
|
+
MAX.times do |i|
|
59
|
+
EM.next_tick do
|
60
|
+
MQ.queue('prime checker').publish((i+1).to_s, :reply_to => 'prime collector')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
}
|
@@ -0,0 +1,135 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
+
require 'mq'
|
3
|
+
|
4
|
+
MAX = 500
|
5
|
+
|
6
|
+
EM.run{
|
7
|
+
|
8
|
+
def log *args
|
9
|
+
p args
|
10
|
+
end
|
11
|
+
|
12
|
+
# MQ.logging = true
|
13
|
+
|
14
|
+
if ARGV[0] == 'worker'
|
15
|
+
|
16
|
+
log "prime checker #{Process.pid}", :started
|
17
|
+
|
18
|
+
class Fixnum
|
19
|
+
def prime?
|
20
|
+
('1' * self) !~ /^1?$|^(11+?)\1+$/
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
MQ.queue('prime checker').subscribe{ |info, num|
|
25
|
+
log "prime checker #{Process.pid}", :prime?, num
|
26
|
+
if Integer(num).prime?
|
27
|
+
MQ.queue(info.reply_to).publish(num, :reply_to => Process.pid)
|
28
|
+
EM.stop_event_loop if num == (MAX-1).to_s
|
29
|
+
end
|
30
|
+
}
|
31
|
+
|
32
|
+
elsif ARGV[0] == 'controller'
|
33
|
+
|
34
|
+
MQ.queue('prime collector').subscribe{ |info, prime|
|
35
|
+
log 'prime collector', :received, prime, :from, info.reply_to
|
36
|
+
(@primes ||= []) << Integer(prime)
|
37
|
+
}
|
38
|
+
|
39
|
+
MAX.times do |i|
|
40
|
+
EM.next_tick do
|
41
|
+
MQ.queue('prime checker').publish((i+1).to_s, :reply_to => 'prime collector')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
else # run n workers and 1 controller as an example
|
46
|
+
|
47
|
+
workers = ARGV[0] ? (Integer(ARGV[0]) rescue 2) : 2
|
48
|
+
|
49
|
+
([ :worker ] * workers + [ :controller ]).each do |type|
|
50
|
+
log :spawning, "`ruby #{$0} #{type}`"
|
51
|
+
|
52
|
+
EM.popen("ruby #{$0} #{type}") do |c|
|
53
|
+
def c.receive_data data
|
54
|
+
puts data
|
55
|
+
end
|
56
|
+
|
57
|
+
def c.unbind
|
58
|
+
EM.stop_event_loop
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
}
|
65
|
+
|
66
|
+
__END__
|
67
|
+
|
68
|
+
["prime checker", :started, {:pid=>1958}]
|
69
|
+
["prime checker", :started, {:pid=>1957}]
|
70
|
+
["prime checker", :started, {:pid=>1956}]
|
71
|
+
["prime checker", :prime?, "1", {:pid=>1958}]
|
72
|
+
["prime checker", :prime?, "2", {:pid=>1957}]
|
73
|
+
["prime collector", :received, "2", {:from_pid=>"1957"}]
|
74
|
+
["prime checker", :prime?, "3", {:pid=>1956}]
|
75
|
+
["prime collector", :received, "3", {:from_pid=>"1956"}]
|
76
|
+
["prime checker", :prime?, "4", {:pid=>1958}]
|
77
|
+
["prime checker", :prime?, "5", {:pid=>1957}]
|
78
|
+
["prime collector", :received, "5", {:from_pid=>"1957"}]
|
79
|
+
["prime checker", :prime?, "6", {:pid=>1956}]
|
80
|
+
["prime checker", :prime?, "7", {:pid=>1958}]
|
81
|
+
["prime collector", :received, "7", {:from_pid=>"1958"}]
|
82
|
+
["prime checker", :prime?, "8", {:pid=>1957}]
|
83
|
+
["prime checker", :prime?, "9", {:pid=>1956}]
|
84
|
+
["prime checker", :prime?, "10", {:pid=>1958}]
|
85
|
+
["prime checker", :prime?, "11", {:pid=>1957}]
|
86
|
+
["prime collector", :received, "11", {:from_pid=>"1957"}]
|
87
|
+
["prime checker", :prime?, "12", {:pid=>1956}]
|
88
|
+
["prime checker", :prime?, "13", {:pid=>1958}]
|
89
|
+
["prime collector", :received, "13", {:from_pid=>"1958"}]
|
90
|
+
["prime checker", :prime?, "14", {:pid=>1957}]
|
91
|
+
["prime checker", :prime?, "15", {:pid=>1956}]
|
92
|
+
["prime checker", :prime?, "16", {:pid=>1958}]
|
93
|
+
["prime checker", :prime?, "17", {:pid=>1957}]
|
94
|
+
["prime collector", :received, "17", {:from_pid=>"1957"}]
|
95
|
+
["prime checker", :prime?, "18", {:pid=>1956}]
|
96
|
+
["prime checker", :prime?, "19", {:pid=>1958}]
|
97
|
+
["prime collector", :received, "19", {:from_pid=>"1958"}]
|
98
|
+
["prime checker", :prime?, "20", {:pid=>1957}]
|
99
|
+
["prime checker", :prime?, "21", {:pid=>1956}]
|
100
|
+
["prime checker", :prime?, "22", {:pid=>1958}]
|
101
|
+
["prime checker", :prime?, "23", {:pid=>1957}]
|
102
|
+
["prime collector", :received, "23", {:from_pid=>"1957"}]
|
103
|
+
["prime checker", :prime?, "24", {:pid=>1956}]
|
104
|
+
["prime checker", :prime?, "25", {:pid=>1958}]
|
105
|
+
["prime checker", :prime?, "26", {:pid=>1957}]
|
106
|
+
["prime checker", :prime?, "27", {:pid=>1956}]
|
107
|
+
["prime checker", :prime?, "28", {:pid=>1958}]
|
108
|
+
["prime checker", :prime?, "29", {:pid=>1957}]
|
109
|
+
["prime collector", :received, "29", {:from_pid=>"1957"}]
|
110
|
+
["prime checker", :prime?, "30", {:pid=>1956}]
|
111
|
+
["prime checker", :prime?, "31", {:pid=>1958}]
|
112
|
+
["prime collector", :received, "31", {:from_pid=>"1958"}]
|
113
|
+
["prime checker", :prime?, "32", {:pid=>1957}]
|
114
|
+
["prime checker", :prime?, "33", {:pid=>1956}]
|
115
|
+
["prime checker", :prime?, "34", {:pid=>1958}]
|
116
|
+
["prime checker", :prime?, "35", {:pid=>1957}]
|
117
|
+
["prime checker", :prime?, "36", {:pid=>1956}]
|
118
|
+
["prime checker", :prime?, "37", {:pid=>1958}]
|
119
|
+
["prime collector", :received, "37", {:from_pid=>"1958"}]
|
120
|
+
["prime checker", :prime?, "38", {:pid=>1957}]
|
121
|
+
["prime checker", :prime?, "39", {:pid=>1956}]
|
122
|
+
["prime checker", :prime?, "40", {:pid=>1958}]
|
123
|
+
["prime checker", :prime?, "41", {:pid=>1957}]
|
124
|
+
["prime collector", :received, "41", {:from_pid=>"1957"}]
|
125
|
+
["prime checker", :prime?, "42", {:pid=>1956}]
|
126
|
+
["prime checker", :prime?, "43", {:pid=>1958}]
|
127
|
+
["prime collector", :received, "43", {:from_pid=>"1958"}]
|
128
|
+
["prime checker", :prime?, "44", {:pid=>1957}]
|
129
|
+
["prime checker", :prime?, "45", {:pid=>1956}]
|
130
|
+
["prime checker", :prime?, "46", {:pid=>1958}]
|
131
|
+
["prime checker", :prime?, "47", {:pid=>1957}]
|
132
|
+
["prime collector", :received, "47", {:from_pid=>"1957"}]
|
133
|
+
["prime checker", :prime?, "48", {:pid=>1956}]
|
134
|
+
["prime checker", :prime?, "49", {:pid=>1958}]
|
135
|
+
["prime checker", :prime?, "50", {:pid=>1957}]
|
@@ -0,0 +1,19 @@
|
|
1
|
+
MAX = 1000
|
2
|
+
|
3
|
+
class Fixnum
|
4
|
+
def prime?
|
5
|
+
('1' * self) !~ /^1?$|^(11+?)\1+$/
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class PrimeChecker
|
10
|
+
def is_prime? number
|
11
|
+
number.prime?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
prime_checker = PrimeChecker.new
|
16
|
+
|
17
|
+
(10_000...(10_000+MAX)).each do |n|
|
18
|
+
prime_checker.is_prime? n
|
19
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
+
require 'mq'
|
3
|
+
|
4
|
+
MAX = 500
|
5
|
+
|
6
|
+
def log *args
|
7
|
+
p args
|
8
|
+
end
|
9
|
+
|
10
|
+
# MQ.logging = true
|
11
|
+
|
12
|
+
EM.run{
|
13
|
+
|
14
|
+
# worker
|
15
|
+
|
16
|
+
log "prime checker", Process.pid, :started
|
17
|
+
|
18
|
+
class Fixnum
|
19
|
+
def prime?
|
20
|
+
('1' * self) !~ /^1?$|^(11+?)\1+$/
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
MQ.queue('prime checker').subscribe{ |info, num|
|
25
|
+
EM.defer(proc{
|
26
|
+
|
27
|
+
log "prime checker #{Process.pid}-#{Thread.current.object_id}", :prime?, num
|
28
|
+
if Integer(num).prime?
|
29
|
+
MQ.queue(info.reply_to).publish(num, :reply_to => "#{Process.pid}-#{Thread.current.object_id}")
|
30
|
+
EM.stop_event_loop if num == '499'
|
31
|
+
end
|
32
|
+
|
33
|
+
})
|
34
|
+
}
|
35
|
+
|
36
|
+
# controller
|
37
|
+
|
38
|
+
MQ.queue('prime collector').subscribe{ |info, prime|
|
39
|
+
log 'prime collector', :received, prime, :from, info.reply_to
|
40
|
+
(@primes ||= []) << Integer(prime)
|
41
|
+
}
|
42
|
+
|
43
|
+
MAX.times do |i|
|
44
|
+
EM.next_tick do
|
45
|
+
MQ.queue('prime checker').publish((i+1).to_s, :reply_to => 'prime collector')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
}
|
data/examples/primes.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
+
require 'mq'
|
3
|
+
|
4
|
+
# check MAX numbers for prime-ness
|
5
|
+
MAX = 1000
|
6
|
+
|
7
|
+
# logging
|
8
|
+
def log *args
|
9
|
+
p args
|
10
|
+
end
|
11
|
+
|
12
|
+
# spawn workers
|
13
|
+
workers = ARGV[0] ? (Integer(ARGV[0]) rescue 1) : 1
|
14
|
+
EM.fork(workers) do
|
15
|
+
|
16
|
+
log MQ.id, :started
|
17
|
+
|
18
|
+
class Fixnum
|
19
|
+
def prime?
|
20
|
+
('1' * self) !~ /^1?$|^(11+?)\1+$/
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class PrimeChecker
|
25
|
+
def is_prime? number
|
26
|
+
log "prime checker #{MQ.id}", :prime?, number
|
27
|
+
number.prime?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
MQ.rpc('prime checker', PrimeChecker.new)
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
# use workers to check which numbers are prime
|
36
|
+
EM.run{
|
37
|
+
|
38
|
+
prime_checker = MQ.rpc('prime checker')
|
39
|
+
|
40
|
+
(10_000...(10_000+MAX)).each do |num|
|
41
|
+
log :checking, num
|
42
|
+
|
43
|
+
prime_checker.is_prime?(num) { |is_prime|
|
44
|
+
log :prime?, num, is_prime
|
45
|
+
(@primes||=[]) << num if is_prime
|
46
|
+
|
47
|
+
if (@responses = (@responses || 0) + 1) == MAX
|
48
|
+
log :primes=, @primes
|
49
|
+
EM.stop_event_loop
|
50
|
+
end
|
51
|
+
}
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
}
|
56
|
+
|
57
|
+
__END__
|
58
|
+
|
59
|
+
$ uname -a
|
60
|
+
Linux gc 2.6.24-ARCH #1 SMP PREEMPT Sun Mar 30 10:50:22 CEST 2008 x86_64 Intel(R) Xeon(R) CPU X3220 @ 2.40GHz GenuineIntel GNU/Linux
|
61
|
+
|
62
|
+
$ cat /proc/cpuinfo | grep processor | wc -l
|
63
|
+
4
|
64
|
+
|
65
|
+
$ time ruby primes-simple.rb
|
66
|
+
|
67
|
+
real 0m16.055s
|
68
|
+
user 0m16.052s
|
69
|
+
sys 0m0.000s
|
70
|
+
|
71
|
+
$ time ruby primes.rb 1 >/dev/null
|
72
|
+
|
73
|
+
real 0m18.278s
|
74
|
+
user 0m0.993s
|
75
|
+
sys 0m0.027s
|
76
|
+
|
77
|
+
$ time ruby primes.rb 2 >/dev/null
|
78
|
+
|
79
|
+
real 0m17.316s
|
80
|
+
user 0m0.967s
|
81
|
+
sys 0m0.053s
|
82
|
+
|
83
|
+
$ time ruby primes.rb 4 >/dev/null
|
84
|
+
|
85
|
+
real 0m8.229s
|
86
|
+
user 0m1.010s
|
87
|
+
sys 0m0.030s
|
88
|
+
|
89
|
+
$ time ruby primes.rb 8 >/dev/null
|
90
|
+
|
91
|
+
real 0m5.893s
|
92
|
+
user 0m1.023s
|
93
|
+
sys 0m0.050s
|
94
|
+
|
95
|
+
$ time ruby primes.rb 16 >/dev/null
|
96
|
+
|
97
|
+
real 0m5.601s
|
98
|
+
user 0m0.990s
|
99
|
+
sys 0m0.043s
|
data/examples/stocks.rb
CHANGED
@@ -13,7 +13,7 @@ EM.run{
|
|
13
13
|
puts
|
14
14
|
|
15
15
|
log :publishing, 'stock.usd.appl', price = 170+rand(1000)/100.0
|
16
|
-
MQ.topic(:key => 'stock.usd.appl'
|
16
|
+
MQ.topic.publish(price, :key => 'stock.usd.appl', :headers => {:symbol => 'appl'})
|
17
17
|
|
18
18
|
log :publishing, 'stock.usd.msft', price = 22+rand(500)/100.0
|
19
19
|
MQ.topic.publish(price, :key => 'stock.usd.msft', :headers => {:symbol => 'msft'})
|
data/lib/amqp/buffer.rb
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
|
1
|
+
if [].map.respond_to? :with_index
|
2
|
+
class Array
|
3
|
+
def enum_with_index
|
4
|
+
each.with_index
|
5
|
+
end
|
6
|
+
end
|
7
|
+
else
|
8
|
+
require 'enumerator'
|
9
|
+
end
|
2
10
|
|
3
11
|
module AMQP
|
4
12
|
class Buffer
|
@@ -102,17 +110,17 @@ module AMQP
|
|
102
110
|
key, type = table.read(:shortstr, :octet)
|
103
111
|
key = key.intern
|
104
112
|
t[key] ||= case type
|
105
|
-
when
|
113
|
+
when 83 # 'S'
|
106
114
|
table.read(:longstr)
|
107
|
-
when
|
115
|
+
when 73 # 'I'
|
108
116
|
table.read(:long)
|
109
|
-
when
|
117
|
+
when 68 # 'D'
|
110
118
|
exp = table.read(:octet)
|
111
119
|
num = table.read(:long)
|
112
120
|
num / 10.0**exp
|
113
|
-
when
|
121
|
+
when 84 # 'T'
|
114
122
|
table.read(:timestamp)
|
115
|
-
when
|
123
|
+
when 70 # 'F'
|
116
124
|
table.read(:table)
|
117
125
|
end
|
118
126
|
end
|
@@ -164,23 +172,23 @@ module AMQP
|
|
164
172
|
|
165
173
|
case value
|
166
174
|
when String
|
167
|
-
table.write(:octet,
|
175
|
+
table.write(:octet, 83) # 'S'
|
168
176
|
table.write(:longstr, value.to_s)
|
169
177
|
when Fixnum
|
170
|
-
table.write(:octet,
|
178
|
+
table.write(:octet, 73) # 'I'
|
171
179
|
table.write(:long, value)
|
172
180
|
when Float
|
173
|
-
table.write(:octet,
|
181
|
+
table.write(:octet, 68) # 'D'
|
174
182
|
# XXX there's gotta be a better way to do this..
|
175
|
-
exp = value.to_s.
|
183
|
+
exp = value.to_s.split('.').last.length
|
176
184
|
num = value * 10**exp
|
177
185
|
table.write(:octet, exp)
|
178
186
|
table.write(:long, num)
|
179
187
|
when Time
|
180
|
-
table.write(:octet,
|
188
|
+
table.write(:octet, 84) # 'T'
|
181
189
|
table.write(:timestamp, value)
|
182
190
|
when Hash
|
183
|
-
table.write(:octet,
|
191
|
+
table.write(:octet, 70) # 'F'
|
184
192
|
table.write(:table, value)
|
185
193
|
end
|
186
194
|
|
data/lib/amqp/client.rb
CHANGED
@@ -73,7 +73,7 @@ module AMQP
|
|
73
73
|
|
74
74
|
def receive_data data
|
75
75
|
@buf << data
|
76
|
-
|
76
|
+
log 'receive_data', data
|
77
77
|
|
78
78
|
while frame = Frame.parse(@buf)
|
79
79
|
log 'receive', frame
|
@@ -95,7 +95,7 @@ module AMQP
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def send_data data
|
98
|
-
|
98
|
+
log 'send_data', data
|
99
99
|
super
|
100
100
|
end
|
101
101
|
|
data/lib/amqp/spec.rb
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
|
2
|
+
# this file was autogenerated on Sun Jul 20 04:06:05 -0700 2008
|
3
|
+
# using amqp-0.8.json (mtime: Wed Jul 16 12:10:42 -0700 2008)
|
4
|
+
#
|
5
|
+
# DO NOT EDIT! (edit protocol/codegen.rb instead, and run `rake codegen`)
|
6
|
+
|
2
7
|
module AMQP
|
3
8
|
HEADER = "AMQP".freeze
|
4
9
|
VERSION_MAJOR = 8
|
data/lib/emfork.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
EMFORK = $0 == __FILE__
|
2
|
+
|
3
|
+
if EMFORK
|
4
|
+
require 'rubygems'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'eventmachine'
|
8
|
+
|
9
|
+
# helper to fork off EM reactors
|
10
|
+
def EM.fork num = 1, &blk
|
11
|
+
unless @forks
|
12
|
+
trap('CHLD'){
|
13
|
+
pid = Process.wait
|
14
|
+
p [:pid, pid, :died] if EMFORK
|
15
|
+
block = @forks.delete(pid)
|
16
|
+
EM.fork(1, &block)
|
17
|
+
}
|
18
|
+
|
19
|
+
trap('EXIT'){
|
20
|
+
p [:pid, Process.pid, :exit] if EMFORK
|
21
|
+
@forks.keys.each{ |pid|
|
22
|
+
p [:pid, Process.pid, :killing, pid] if EMFORK
|
23
|
+
Process.kill('USR1', pid)
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
@forks = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
num.times do
|
31
|
+
pid = EM.fork_reactor do
|
32
|
+
p [:pid, Process.pid, :started] if EMFORK
|
33
|
+
|
34
|
+
trap('USR1'){ EM.stop_event_loop }
|
35
|
+
trap('CHLD'){}
|
36
|
+
trap('EXIT'){}
|
37
|
+
|
38
|
+
blk.call
|
39
|
+
end
|
40
|
+
|
41
|
+
@forks[pid] = blk
|
42
|
+
p [:children, EM.forks] if EMFORK
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def EM.forks
|
47
|
+
@forks.keys
|
48
|
+
end
|
49
|
+
|
50
|
+
if EMFORK
|
51
|
+
p 'starting reactor'
|
52
|
+
|
53
|
+
trap('INT'){ EM.stop_event_loop }
|
54
|
+
|
55
|
+
EM.run{
|
56
|
+
p [:parent, Process.pid]
|
57
|
+
|
58
|
+
EM.fork(2){
|
59
|
+
EM.add_periodic_timer(1) do
|
60
|
+
p [:fork, Process.pid, :ping]
|
61
|
+
end
|
62
|
+
}
|
63
|
+
|
64
|
+
}
|
65
|
+
|
66
|
+
p 'reactor stopped'
|
67
|
+
end
|
data/lib/mq.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
$:.unshift File.expand_path(File.dirname(File.expand_path(__FILE__)))
|
2
2
|
require 'amqp'
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
class MQ
|
5
|
+
%w[ exchange queue rpc ].each do |file|
|
6
|
+
require "mq/#{file}"
|
7
|
+
end
|
6
8
|
|
7
|
-
class
|
8
|
-
|
9
|
+
class << self
|
10
|
+
@logging = false
|
11
|
+
attr_accessor :logging
|
9
12
|
end
|
10
13
|
end
|
11
14
|
|
@@ -13,129 +16,6 @@ class MQ
|
|
13
16
|
include AMQP
|
14
17
|
include EM::Deferrable
|
15
18
|
|
16
|
-
class Exchange
|
17
|
-
include AMQP
|
18
|
-
|
19
|
-
def initialize mq, type, name, opts = {}
|
20
|
-
if name.is_a? Hash
|
21
|
-
opts = name
|
22
|
-
name = "amq.#{type}"
|
23
|
-
end
|
24
|
-
|
25
|
-
@mq = mq
|
26
|
-
@type, @name = type, name
|
27
|
-
@key = opts[:key]
|
28
|
-
|
29
|
-
@mq.callback{
|
30
|
-
@mq.send Protocol::Exchange::Declare.new({ :exchange => name,
|
31
|
-
:type => type,
|
32
|
-
:nowait => true }.merge(opts))
|
33
|
-
} unless name == "amq.#{type}"
|
34
|
-
end
|
35
|
-
attr_reader :name, :type, :key
|
36
|
-
|
37
|
-
def publish data, opts = {}
|
38
|
-
@mq.callback{
|
39
|
-
@mq.send Protocol::Basic::Publish.new({ :exchange => name,
|
40
|
-
:routing_key => opts.delete(:key) || @key }.merge(opts))
|
41
|
-
|
42
|
-
data = data.to_s
|
43
|
-
|
44
|
-
@mq.send Protocol::Header.new(Protocol::Basic,
|
45
|
-
data.length, { :content_type => 'application/octet-stream',
|
46
|
-
:delivery_mode => 1,
|
47
|
-
:priority => 0 }.merge(opts))
|
48
|
-
@mq.send Frame::Body.new(data)
|
49
|
-
}
|
50
|
-
self
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
class Queue
|
55
|
-
include AMQP
|
56
|
-
|
57
|
-
def initialize mq, name, opts = {}
|
58
|
-
@mq = mq
|
59
|
-
@name = name
|
60
|
-
@mq.callback{
|
61
|
-
@mq.send Protocol::Queue::Declare.new({ :queue => name,
|
62
|
-
:nowait => true }.merge(opts))
|
63
|
-
}
|
64
|
-
bind(@mq.direct, :key => name)
|
65
|
-
end
|
66
|
-
attr_reader :name
|
67
|
-
|
68
|
-
def bind exchange, opts = {}
|
69
|
-
@mq.callback{
|
70
|
-
@mq.send Protocol::Queue::Bind.new({ :queue => name,
|
71
|
-
:exchange => exchange.respond_to?(:name) ? exchange.name : exchange,
|
72
|
-
:routing_key => opts.delete(:key),
|
73
|
-
:nowait => true }.merge(opts))
|
74
|
-
}
|
75
|
-
self
|
76
|
-
end
|
77
|
-
|
78
|
-
def subscribe opts = {}, &blk
|
79
|
-
@on_msg = blk
|
80
|
-
@mq.callback{
|
81
|
-
@mq.send Protocol::Basic::Consume.new({ :queue => name,
|
82
|
-
:consumer_tag => name,
|
83
|
-
:no_ack => true,
|
84
|
-
:nowait => true }.merge(opts))
|
85
|
-
}
|
86
|
-
self
|
87
|
-
end
|
88
|
-
|
89
|
-
def receive headers, body
|
90
|
-
if @on_msg
|
91
|
-
@on_msg.call *(@on_msg.arity == 1 ? [body] : [headers, body])
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
class RPC < BlankSlate
|
97
|
-
def initialize mq, queue, obj = nil
|
98
|
-
@mq = mq
|
99
|
-
|
100
|
-
if obj
|
101
|
-
@obj = case obj
|
102
|
-
when Class
|
103
|
-
obj.new
|
104
|
-
when Module
|
105
|
-
(::Class.new do include(obj) end).new
|
106
|
-
else
|
107
|
-
obj
|
108
|
-
end
|
109
|
-
|
110
|
-
@mq.queue(queue).subscribe{ |info, request|
|
111
|
-
method, *args = Marshal.load(request)
|
112
|
-
ret = @obj.__send__(method, *args)
|
113
|
-
|
114
|
-
if info.reply_to
|
115
|
-
@mq.direct.publish(Marshal.dump(ret), :key => info.reply_to, :message_id => info.message_id)
|
116
|
-
end
|
117
|
-
}
|
118
|
-
else
|
119
|
-
@callbacks ||= {}
|
120
|
-
@queue = @mq.queue(@name = 'some random identifier for me').subscribe{|info, msg|
|
121
|
-
ret = Marshal.load(msg)
|
122
|
-
if blk = @callbacks.delete(info.message_id)
|
123
|
-
blk.call(ret)
|
124
|
-
end
|
125
|
-
}
|
126
|
-
@exchange = @mq.direct(:key => queue)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
def method_missing meth, *args, &blk
|
131
|
-
message_id = "random message id #{rand(999_999_999_999)}"
|
132
|
-
@callbacks[message_id] = blk if blk
|
133
|
-
@exchange.publish(Marshal.dump([meth, *args]), :reply_to => blk ? @name : nil, :message_id => message_id)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
class MQ
|
139
19
|
def initialize
|
140
20
|
conn.callback{ |c|
|
141
21
|
@channel = c.add_channel(self)
|
@@ -145,6 +25,8 @@ class MQ
|
|
145
25
|
attr_reader :channel
|
146
26
|
|
147
27
|
def process_frame frame
|
28
|
+
log :received, frame
|
29
|
+
|
148
30
|
case frame
|
149
31
|
when Frame::Header
|
150
32
|
@header = frame.payload
|
@@ -180,6 +62,7 @@ class MQ
|
|
180
62
|
def send data
|
181
63
|
data.ticket = @ticket if @ticket and data.respond_to? :ticket
|
182
64
|
conn.callback{ |c|
|
65
|
+
log :sending, data
|
183
66
|
c.send data, :channel => @channel
|
184
67
|
}
|
185
68
|
end
|
@@ -202,6 +85,14 @@ class MQ
|
|
202
85
|
|
203
86
|
private
|
204
87
|
|
88
|
+
def log *args
|
89
|
+
return unless MQ.logging
|
90
|
+
pp args
|
91
|
+
puts
|
92
|
+
end
|
93
|
+
|
94
|
+
# keep track of proxy objects
|
95
|
+
|
205
96
|
def exchanges
|
206
97
|
@exchanges ||= {}
|
207
98
|
end
|
@@ -214,16 +105,29 @@ class MQ
|
|
214
105
|
@rcps ||= {}
|
215
106
|
end
|
216
107
|
|
108
|
+
# create a class level connection on demand
|
109
|
+
|
217
110
|
def connection
|
218
111
|
@@connection ||= AMQP.start
|
219
112
|
end
|
220
113
|
alias :conn :connection
|
114
|
+
end
|
115
|
+
|
116
|
+
# convenience wrapper for thread-local MQ object
|
117
|
+
|
118
|
+
class MQ
|
119
|
+
def MQ.default
|
120
|
+
Thread.current[:mq] ||= MQ.new
|
121
|
+
end
|
221
122
|
|
222
123
|
def MQ.method_missing meth, *args, &blk
|
223
124
|
MQ.default.__send__(meth, *args, &blk)
|
224
125
|
end
|
225
|
-
|
226
|
-
|
227
|
-
|
126
|
+
end
|
127
|
+
|
128
|
+
# unique identifier
|
129
|
+
class MQ
|
130
|
+
def MQ.id
|
131
|
+
Thread.current[:mq_id] ||= "#{`hostname`.strip}-#{Process.pid}-#{Thread.current.object_id}"
|
228
132
|
end
|
229
133
|
end
|
data/lib/mq/exchange.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
class MQ
|
2
|
+
class Exchange
|
3
|
+
include AMQP
|
4
|
+
|
5
|
+
def initialize mq, type, name, opts = {}
|
6
|
+
@mq = mq
|
7
|
+
@type, @name = type, name
|
8
|
+
@key = opts[:key]
|
9
|
+
|
10
|
+
@mq.callback{
|
11
|
+
@mq.send Protocol::Exchange::Declare.new({ :exchange => name,
|
12
|
+
:type => type,
|
13
|
+
:nowait => true }.merge(opts))
|
14
|
+
} unless name == "amq.#{type}" or name == ''
|
15
|
+
end
|
16
|
+
attr_reader :name, :type, :key
|
17
|
+
|
18
|
+
def publish data, opts = {}
|
19
|
+
@mq.callback{
|
20
|
+
EM.next_tick do
|
21
|
+
@mq.send Protocol::Basic::Publish.new({ :exchange => name,
|
22
|
+
:routing_key => opts.delete(:key) || @key }.merge(opts))
|
23
|
+
|
24
|
+
data = data.to_s
|
25
|
+
|
26
|
+
@mq.send Protocol::Header.new(Protocol::Basic,
|
27
|
+
data.length, { :content_type => 'application/octet-stream',
|
28
|
+
:delivery_mode => 1,
|
29
|
+
:priority => 0 }.merge(opts))
|
30
|
+
@mq.send Frame::Body.new(data)
|
31
|
+
end
|
32
|
+
}
|
33
|
+
self
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/mq/queue.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
class MQ
|
2
|
+
class Queue
|
3
|
+
include AMQP
|
4
|
+
|
5
|
+
def initialize mq, name, opts = {}
|
6
|
+
@mq = mq
|
7
|
+
@name = name
|
8
|
+
@mq.callback{
|
9
|
+
@mq.send Protocol::Queue::Declare.new({ :queue => name,
|
10
|
+
:nowait => true }.merge(opts))
|
11
|
+
}
|
12
|
+
end
|
13
|
+
attr_reader :name
|
14
|
+
|
15
|
+
def bind exchange, opts = {}
|
16
|
+
@mq.callback{
|
17
|
+
@mq.send Protocol::Queue::Bind.new({ :queue => name,
|
18
|
+
:exchange => exchange.respond_to?(:name) ? exchange.name : exchange,
|
19
|
+
:routing_key => opts.delete(:key),
|
20
|
+
:nowait => true }.merge(opts))
|
21
|
+
}
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def subscribe opts = {}, &blk
|
26
|
+
@on_msg = blk
|
27
|
+
@mq.callback{
|
28
|
+
@mq.send Protocol::Basic::Consume.new({ :queue => name,
|
29
|
+
:consumer_tag => name,
|
30
|
+
:no_ack => true,
|
31
|
+
:nowait => true }.merge(opts))
|
32
|
+
}
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def publish data, opts = {}
|
37
|
+
exchange.publish(data, opts)
|
38
|
+
end
|
39
|
+
|
40
|
+
def receive headers, body
|
41
|
+
if @on_msg
|
42
|
+
@on_msg.call *(@on_msg.arity == 1 ? [body] : [headers, body])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def exchange
|
49
|
+
@exchange ||= Exchange.new(@mq, :direct, '', :key => name)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/mq/rpc.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'emfork'
|
2
|
+
|
3
|
+
unless defined?(BlankSlate)
|
4
|
+
class BlankSlate < BasicObject; end if defined?(BasicObject)
|
5
|
+
|
6
|
+
class BlankSlate
|
7
|
+
instance_methods.each { |m| undef_method m unless m =~ /^__/ }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class MQ
|
12
|
+
class RPC < BlankSlate
|
13
|
+
def initialize mq, queue, obj = nil
|
14
|
+
@mq = mq
|
15
|
+
|
16
|
+
if obj
|
17
|
+
@obj = case obj
|
18
|
+
when ::Class
|
19
|
+
obj.new
|
20
|
+
when ::Module
|
21
|
+
(::Class.new do include(obj) end).new
|
22
|
+
else
|
23
|
+
obj
|
24
|
+
end
|
25
|
+
|
26
|
+
@mq.queue(queue).subscribe{ |info, request|
|
27
|
+
method, *args = ::Marshal.load(request)
|
28
|
+
ret = @obj.__send__(method, *args)
|
29
|
+
|
30
|
+
if info.reply_to
|
31
|
+
@mq.queue(info.reply_to).publish(::Marshal.dump(ret), :key => info.reply_to, :message_id => info.message_id)
|
32
|
+
end
|
33
|
+
}
|
34
|
+
else
|
35
|
+
@callbacks ||= {}
|
36
|
+
@queue = @mq.queue(@name = 'some random identifier for me').subscribe{|info, msg|
|
37
|
+
if blk = @callbacks.delete(info.message_id)
|
38
|
+
blk.call ::Marshal.load(msg)
|
39
|
+
end
|
40
|
+
}
|
41
|
+
@remote = @mq.queue(queue)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def method_missing meth, *args, &blk
|
46
|
+
message_id = "random message id #{::Kernel.rand(999_999_999_999)}"
|
47
|
+
@callbacks[message_id] = blk if blk
|
48
|
+
@remote.publish(::Marshal.dump([meth, *args]), :reply_to => blk ? @name : nil, :message_id => message_id)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/protocol/codegen.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'json'
|
3
3
|
|
4
|
-
|
4
|
+
name = 'amqp-0.8.json'
|
5
|
+
path = File.dirname(__FILE__)+'/'+name
|
6
|
+
s = JSON.parse(File.read(path))
|
5
7
|
|
6
8
|
# require 'pp'
|
7
9
|
# pp(s)
|
@@ -10,6 +12,11 @@ s = JSON.parse(File.read(File.dirname(__FILE__)+'/amqp-0.8.json'))
|
|
10
12
|
require 'erb'
|
11
13
|
|
12
14
|
puts ERB.new(%q[
|
15
|
+
# this file was autogenerated on <%= Time.now.to_s %>
|
16
|
+
# using <%= name.ljust(16) %> (mtime: <%= File.mtime(path) %>)
|
17
|
+
#
|
18
|
+
# DO NOT EDIT! (edit protocol/codegen.rb instead, and run `rake codegen`)
|
19
|
+
|
13
20
|
module AMQP
|
14
21
|
HEADER = <%= s['name'].dump %>.freeze
|
15
22
|
VERSION_MAJOR = <%= s['major-version'] %>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amqp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aman Gupta
|
@@ -9,10 +9,19 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-07-
|
12
|
+
date: 2008-07-21 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: eventmachine
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.12.1
|
24
|
+
version:
|
16
25
|
description: AMQP client implementation in Ruby/EventMachine
|
17
26
|
email: amqp@tmm1.net
|
18
27
|
executables: []
|
@@ -22,9 +31,15 @@ extensions: []
|
|
22
31
|
extra_rdoc_files: []
|
23
32
|
|
24
33
|
files:
|
34
|
+
- README
|
25
35
|
- examples/clock.rb
|
26
36
|
- examples/hashtable.rb
|
27
37
|
- examples/pingpong.rb
|
38
|
+
- examples/primes-forked.rb
|
39
|
+
- examples/primes-processes.rb
|
40
|
+
- examples/primes-simple.rb
|
41
|
+
- examples/primes-threaded.rb
|
42
|
+
- examples/primes.rb
|
28
43
|
- examples/simple.rb
|
29
44
|
- examples/stocks.rb
|
30
45
|
- lib/amqp/buffer.rb
|
@@ -33,12 +48,15 @@ files:
|
|
33
48
|
- lib/amqp/protocol.rb
|
34
49
|
- lib/amqp/spec.rb
|
35
50
|
- lib/amqp.rb
|
51
|
+
- lib/emfork.rb
|
52
|
+
- lib/mq/exchange.rb
|
53
|
+
- lib/mq/queue.rb
|
54
|
+
- lib/mq/rpc.rb
|
36
55
|
- lib/mq.rb
|
37
56
|
- protocol/amqp-0.8.json
|
38
57
|
- protocol/codegen.rb
|
39
58
|
- protocol/doc.txt
|
40
59
|
- protocol/amqp-0.8.xml
|
41
|
-
- README
|
42
60
|
has_rdoc: false
|
43
61
|
homepage: http://amqp.rubyforge.org/
|
44
62
|
post_install_message:
|