amqp 0.5.2 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README +48 -18
- data/examples/{simple.rb → amqp/simple.rb} +1 -1
- data/examples/{clock.rb → mq/clock.rb} +1 -1
- data/examples/{hashtable.rb → mq/hashtable.rb} +1 -1
- data/examples/mq/logger.rb +139 -0
- data/examples/{pingpong.rb → mq/pingpong.rb} +1 -1
- data/examples/{primes-simple.rb → mq/primes-simple.rb} +0 -0
- data/examples/{primes.rb → mq/primes.rb} +1 -1
- data/examples/mq/simple.rb +41 -0
- data/examples/{stocks.rb → mq/stocks.rb} +1 -1
- data/lib/amqp.rb +40 -1
- data/lib/amqp/client.rb +28 -19
- data/lib/amqp/protocol.rb +8 -2
- data/lib/ext/blankslate.rb +7 -0
- data/lib/mq.rb +39 -6
- data/lib/mq/exchange.rb +10 -11
- data/lib/mq/queue.rb +1 -1
- data/lib/mq/rpc.rb +1 -8
- metadata +12 -9
data/README
CHANGED
@@ -1,4 +1,11 @@
|
|
1
|
-
Simple AMQP driver for Ruby/EventMachine
|
1
|
+
Simple AMQP driver for Ruby/EventMachine
|
2
|
+
(c) 2008 Aman Gupta (tmm1)
|
3
|
+
|
4
|
+
http://github.com/tmm1/amqp
|
5
|
+
http://rubyforge.org/projects/amqp
|
6
|
+
http://hopper.squarespace.com/blog/2008/7/22/simple-amqp-library-for-ruby.html
|
7
|
+
http://groups.google.com/group/ruby-amqp
|
8
|
+
http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2008-July/001417.html
|
2
9
|
|
3
10
|
This library was tested primarily with RabbitMQ, although it should be compatible with any
|
4
11
|
server implementing the AMQP 0-8 spec.
|
@@ -12,15 +19,17 @@ To use with RabbitMQ, first run the server:
|
|
12
19
|
|
13
20
|
To get started, refer to the various bundled examples:
|
14
21
|
|
15
|
-
ruby examples/
|
16
|
-
ruby examples/
|
17
|
-
ruby examples/
|
18
|
-
ruby examples/
|
19
|
-
ruby examples/
|
22
|
+
ruby examples/mq/simple.rb # low-level Queue/Exchange api
|
23
|
+
ruby examples/mq/pingpong.rb # 1-1 communication using amq.direct
|
24
|
+
ruby examples/mq/clock.rb # 1-N communication using amq.fanout
|
25
|
+
ruby examples/mq/stocks.rb # 1-subscriber communication using amq.topic
|
26
|
+
ruby examples/mq/hashtable.rb # simple async rpc layer
|
27
|
+
ruby examples/mq/primes.rb 4 # parallelized prime number generation
|
28
|
+
ruby examples/mq/logger.rb # simple logging api
|
20
29
|
|
21
30
|
For more details into the lower level AMQP client API, run the simple client example:
|
22
31
|
|
23
|
-
ruby examples/simple.rb
|
32
|
+
ruby examples/amqp/simple.rb # low-level AMQP api
|
24
33
|
|
25
34
|
Or refer to protocol/doc.txt, which enumerates packets sent between a server and client
|
26
35
|
during a typical session, in both binary and decoded formats.
|
@@ -36,32 +45,47 @@ The lib/amqp/spec.rb file is generated automatically based on the AMQP specifica
|
|
36
45
|
This project was inspired by py-amqplib, rabbitmq, qpid and rubbyt.
|
37
46
|
Special thanks to Dmitriy Samovskiy, Ben Hood and Tony Garnock-Jones.
|
38
47
|
|
39
|
-
|
48
|
+
AMQP resources:
|
40
49
|
|
41
50
|
Servers:
|
42
|
-
RabbitMQ (Rabbit Technologies, Erlang/OTP, MPL)
|
43
|
-
|
44
|
-
|
51
|
+
RabbitMQ (Rabbit Technologies, Erlang/OTP, MPL) - http://rabbitmq.com
|
52
|
+
ZeroMQ (iMatrix/FastMQ/Intel, C++, GPL3) - http://www.zeromq.org
|
53
|
+
OpenAMQ (iMatrix, C, GPL2) - http://openamq.org
|
54
|
+
ActiveMQ (Apache Foundation, Java, apache2) - http://activemq.apache.org/
|
45
55
|
|
46
|
-
|
56
|
+
Steve Vinoski explains AMQP in his column, Towards Integration
|
57
|
+
http://steve.vinoski.net/pdf/IEEE-Advanced_Message_Queuing_Protocol.pdf
|
58
|
+
|
59
|
+
John O'Hara on the history of AMQP
|
47
60
|
http://www.acmqueue.org/modules.php?name=Content&pa=showpage&pid=485
|
48
61
|
|
49
|
-
|
62
|
+
ZeroMQ's analysis of the messaging technology market
|
63
|
+
http://www.zeromq.org/whitepapers:market-analysis
|
64
|
+
|
65
|
+
ZeroMQ's background to AMQP
|
66
|
+
http://www.zeromq.org/whitepapers:amqp-analysis
|
67
|
+
|
68
|
+
Barry Pederson's py-amqplib
|
50
69
|
http://barryp.org/software/py-amqplib/
|
51
70
|
|
52
|
-
Ben Hood
|
71
|
+
Ben Hood on writing an AMQP client
|
53
72
|
http://hopper.squarespace.com/blog/2008/6/21/build-your-own-amqp-client.html
|
54
73
|
|
55
|
-
Dmitriy Samovskiy
|
74
|
+
Dmitriy Samovskiy introduces Ruby + QPid + RabbitMQ
|
56
75
|
http://somic-org.homelinux.org/blog/2008/06/24/ruby-amqp-rabbitmq-example/
|
57
76
|
|
58
|
-
Ben Hood's
|
77
|
+
Ben Hood's as3-amqp
|
59
78
|
http://github.com/0x6e6562/as3-amqp
|
79
|
+
http://hopper.squarespace.com/blog/2008/7/4/server-side-as3.html
|
80
|
+
http://hopper.squarespace.com/blog/2008/3/24/as3-amqp-client-first-cut.html
|
60
81
|
|
61
|
-
RabbitMQ's protocol code generator
|
82
|
+
RabbitMQ's protocol code generator
|
62
83
|
http://hg.rabbitmq.com/rabbitmq-codegen/
|
63
84
|
|
64
|
-
|
85
|
+
Erlang Exchange presentation on the implementation of RabbitMQ
|
86
|
+
http://www.lshift.net/blog/2008/07/01/slides-from-our-erlang-exchange-talk
|
87
|
+
|
88
|
+
Jonathan Conway's series on RabbitMQ and using it with Ruby/Merb
|
65
89
|
http://jaikoo.com/2008/3/20/daemonize-rabbitmq
|
66
90
|
http://jaikoo.com/2008/3/14/oh-hai-rabbitmq
|
67
91
|
http://jaikoo.com/2008/2/29/friday-round-up-2008-02-29
|
@@ -77,3 +101,9 @@ Messaging and distributed systems resources:
|
|
77
101
|
|
78
102
|
Convenience Over Correctness
|
79
103
|
http://steve.vinoski.net/pdf/IEEE-Convenience_Over_Correctness.pdf
|
104
|
+
|
105
|
+
Metaprotocol Taxonomy and Communications Patterns
|
106
|
+
http://hessian.caucho.com/doc/metaprotocol-taxonomy.xtp
|
107
|
+
|
108
|
+
Joe Armstrong on Erlang messaging vs RPC:
|
109
|
+
http://armstrongonsoftware.blogspot.com/2008/05/road-we-didnt-go-down.html
|
@@ -0,0 +1,139 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
2
|
+
require 'mq'
|
3
|
+
|
4
|
+
class Logger
|
5
|
+
def initialize *args, &block
|
6
|
+
opts = args.pop if args.last.is_a? Hash
|
7
|
+
opts ||= {}
|
8
|
+
printer(block) if block
|
9
|
+
@log = []
|
10
|
+
@tags = ([:timestamp] + args).uniq
|
11
|
+
end
|
12
|
+
|
13
|
+
def log severity, *args
|
14
|
+
opts = args.pop if args.last.is_a? Hash and args.size != 1
|
15
|
+
opts ||= {}
|
16
|
+
data = args.shift
|
17
|
+
|
18
|
+
data = {:type => :exception,
|
19
|
+
:name => data.class.to_s.intern,
|
20
|
+
:backtrace => data.backtrace,
|
21
|
+
:message => data.message} if data.is_a? Exception
|
22
|
+
|
23
|
+
(@tags + args).each do |tag|
|
24
|
+
tag = tag.to_sym
|
25
|
+
case tag
|
26
|
+
when :timestamp
|
27
|
+
opts.update :timestamp => Time.now.to_i
|
28
|
+
when :hostname
|
29
|
+
@hostname ||= { :hostname => `hostname`.strip }
|
30
|
+
opts.update @hostname
|
31
|
+
when :process
|
32
|
+
@process_id ||= { :process_id => Process.pid,
|
33
|
+
:process_name => $0,
|
34
|
+
:process_parent_id => Process.ppid,
|
35
|
+
:thread_id => Thread.current.object_id }
|
36
|
+
opts.update :process => @process_id
|
37
|
+
else
|
38
|
+
(opts[:tags] ||= []) << tag
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.update(:severity => severity,
|
43
|
+
:data => data)
|
44
|
+
|
45
|
+
print(opts)
|
46
|
+
MQ.queue('logger', :durable => true).publish(Marshal.dump(opts), :persistent => true)
|
47
|
+
opts
|
48
|
+
end
|
49
|
+
alias :method_missing :log
|
50
|
+
|
51
|
+
def print data = nil, &block
|
52
|
+
if block
|
53
|
+
@printer = block
|
54
|
+
elsif data.is_a? Proc
|
55
|
+
@printer = data
|
56
|
+
elsif @printer and data
|
57
|
+
@printer.call(data)
|
58
|
+
else
|
59
|
+
@printer
|
60
|
+
end
|
61
|
+
end
|
62
|
+
alias :printer :print
|
63
|
+
end
|
64
|
+
|
65
|
+
EM.run{
|
66
|
+
# AMQP.logging = true
|
67
|
+
# MQ.logging = true
|
68
|
+
|
69
|
+
if ARGV[0] == 'server'
|
70
|
+
|
71
|
+
MQ.queue('logger', :durable => true).subscribe{|msg|
|
72
|
+
msg = Marshal.load(msg)
|
73
|
+
require 'pp'
|
74
|
+
pp(msg)
|
75
|
+
puts
|
76
|
+
}
|
77
|
+
|
78
|
+
else
|
79
|
+
|
80
|
+
log = Logger.new
|
81
|
+
log.debug 'its working!'
|
82
|
+
|
83
|
+
log = Logger.new do |msg|
|
84
|
+
require 'pp'
|
85
|
+
pp msg
|
86
|
+
puts
|
87
|
+
end
|
88
|
+
|
89
|
+
log.info '123'
|
90
|
+
log.debug [1,2,3]
|
91
|
+
log.debug :one => 1, :two => 2
|
92
|
+
log.error Exception.new('123')
|
93
|
+
|
94
|
+
log.info '123', :process_id => Process.pid
|
95
|
+
log.info '123', :process
|
96
|
+
log.debug 'login', :session => 'abc', :user => 123
|
97
|
+
|
98
|
+
log = Logger.new(:webserver, :timestamp, :hostname, &log.printer)
|
99
|
+
log.info 'Request for /', :GET, :session => 'abc'
|
100
|
+
|
101
|
+
AMQP.stop
|
102
|
+
|
103
|
+
end
|
104
|
+
}
|
105
|
+
|
106
|
+
__END__
|
107
|
+
|
108
|
+
{:data=>"123", :timestamp=>1216846102, :severity=>:info}
|
109
|
+
|
110
|
+
{:data=>[1, 2, 3], :timestamp=>1216846102, :severity=>:debug}
|
111
|
+
|
112
|
+
{:data=>
|
113
|
+
{:type=>:exception, :name=>:Exception, :message=>"123", :backtrace=>nil},
|
114
|
+
:timestamp=>1216846102,
|
115
|
+
:severity=>:error}
|
116
|
+
|
117
|
+
{:data=>"123", :timestamp=>1216846102, :process_id=>1814, :severity=>:info}
|
118
|
+
|
119
|
+
{:process=>
|
120
|
+
{:thread_id=>109440,
|
121
|
+
:process_id=>1814,
|
122
|
+
:process_name=>"/Users/aman/code/amqp/examples/logger.rb",
|
123
|
+
:process_parent_id=>1813},
|
124
|
+
:data=>"123",
|
125
|
+
:timestamp=>1216846102,
|
126
|
+
:severity=>:info}
|
127
|
+
|
128
|
+
{:session=>"abc",
|
129
|
+
:data=>"login",
|
130
|
+
:timestamp=>1216846102,
|
131
|
+
:severity=>:debug,
|
132
|
+
:user=>123}
|
133
|
+
|
134
|
+
{:session=>"abc",
|
135
|
+
:tags=>[:webserver, :GET],
|
136
|
+
:data=>"Request for /",
|
137
|
+
:timestamp=>1216846102,
|
138
|
+
:severity=>:info,
|
139
|
+
:hostname=>"gc"}
|
File without changes
|
@@ -0,0 +1,41 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
2
|
+
require 'mq'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
EM.run do
|
6
|
+
|
7
|
+
# open a channel on the AMQP connection
|
8
|
+
channel = MQ.new
|
9
|
+
|
10
|
+
# declare a queue on the channel
|
11
|
+
queue = MQ::Queue.new(channel, 'queue name')
|
12
|
+
|
13
|
+
# use the default fanout exchange
|
14
|
+
exchange = MQ::Exchange.new(channel, :fanout, 'all queues')
|
15
|
+
|
16
|
+
# bind the queue to the exchange
|
17
|
+
queue.bind(exchange)
|
18
|
+
|
19
|
+
# publish a message to the exchange
|
20
|
+
exchange.publish('hello world')
|
21
|
+
|
22
|
+
# subscribe to messages from the queue
|
23
|
+
queue.subscribe do |headers, msg|
|
24
|
+
pp [:got, headers, msg]
|
25
|
+
AMQP.stop
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
__END__
|
31
|
+
|
32
|
+
[:got,
|
33
|
+
#<AMQP::Protocol::Header:0x118a438
|
34
|
+
@klass=AMQP::Protocol::Basic,
|
35
|
+
@properties=
|
36
|
+
{:priority=>0,
|
37
|
+
:delivery_mode=>1,
|
38
|
+
:content_type=>"application/octet-stream"},
|
39
|
+
@size=11,
|
40
|
+
@weight=0>,
|
41
|
+
"hello world"]
|
data/lib/amqp.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
module AMQP
|
2
|
+
VERSION = '0.5.3'
|
3
|
+
|
2
4
|
DIR = File.expand_path(File.dirname(File.expand_path(__FILE__)))
|
3
|
-
|
4
5
|
$:.unshift DIR
|
5
6
|
|
6
7
|
require 'ext/em'
|
8
|
+
require 'ext/blankslate'
|
7
9
|
|
8
10
|
%w[ buffer spec protocol frame client ].each do |file|
|
9
11
|
require "amqp/#{file}"
|
@@ -12,5 +14,42 @@ module AMQP
|
|
12
14
|
class << self
|
13
15
|
@logging = false
|
14
16
|
attr_accessor :logging
|
17
|
+
attr_reader :stopping
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.settings
|
21
|
+
@settings ||= {
|
22
|
+
:user => 'guest',
|
23
|
+
:pass => 'guest',
|
24
|
+
:vhost => '/'
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.start *args
|
29
|
+
@conn ||= Client.connect *args
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.stop stop_reactor = true, &on_stop
|
33
|
+
if @conn
|
34
|
+
@conn.callback{ |c|
|
35
|
+
if c.channels.keys.any?
|
36
|
+
c.channels.each do |_, mq|
|
37
|
+
mq.close
|
38
|
+
end
|
39
|
+
else
|
40
|
+
c.close
|
41
|
+
end
|
42
|
+
}
|
43
|
+
@on_stop = proc{
|
44
|
+
@conn = nil
|
45
|
+
on_stop.call if on_stop
|
46
|
+
EM.stop_event_loop if stop_reactor
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.stopped
|
52
|
+
@on_stop.call if @on_stop
|
53
|
+
@on_stop = nil
|
15
54
|
end
|
16
55
|
end
|
data/lib/amqp/client.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'amqp/frame'
|
2
|
-
require 'pp'
|
3
2
|
|
4
3
|
module AMQP
|
4
|
+
class Error < Exception; end
|
5
|
+
|
5
6
|
module BasicClient
|
6
7
|
def process_frame frame
|
7
8
|
if mq = channels[frame.channel]
|
@@ -16,10 +17,10 @@ module AMQP
|
|
16
17
|
send Protocol::Connection::StartOk.new({:platform => 'Ruby/EventMachine',
|
17
18
|
:product => 'AMQP',
|
18
19
|
:information => 'http://github.com/tmm1/amqp',
|
19
|
-
:version =>
|
20
|
+
:version => VERSION},
|
20
21
|
'AMQPLAIN',
|
21
|
-
{:LOGIN =>
|
22
|
-
:PASSWORD =>
|
22
|
+
{:LOGIN => @settings[:user],
|
23
|
+
:PASSWORD => @settings[:pass]},
|
23
24
|
'en_US')
|
24
25
|
|
25
26
|
when Protocol::Connection::Tune
|
@@ -27,12 +28,18 @@ module AMQP
|
|
27
28
|
:frame_max => 131072,
|
28
29
|
:heartbeat => 0)
|
29
30
|
|
30
|
-
send Protocol::Connection::Open.new(:virtual_host =>
|
31
|
+
send Protocol::Connection::Open.new(:virtual_host => @settings[:vhost],
|
31
32
|
:capabilities => '',
|
32
33
|
:insist => false)
|
33
34
|
|
34
35
|
when Protocol::Connection::OpenOk
|
35
36
|
@dfr.succeed(self)
|
37
|
+
|
38
|
+
when Protocol::Connection::Close
|
39
|
+
raise Error, "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]}"
|
40
|
+
|
41
|
+
when Protocol::Connection::CloseOk
|
42
|
+
AMQP.stopped
|
36
43
|
end
|
37
44
|
end
|
38
45
|
end
|
@@ -48,8 +55,9 @@ module AMQP
|
|
48
55
|
end
|
49
56
|
|
50
57
|
module Client
|
51
|
-
def initialize dfr
|
58
|
+
def initialize dfr, opts = {}
|
52
59
|
@dfr = dfr
|
60
|
+
@settings = opts
|
53
61
|
extend AMQP.client
|
54
62
|
end
|
55
63
|
|
@@ -70,8 +78,8 @@ module AMQP
|
|
70
78
|
end
|
71
79
|
|
72
80
|
def receive_data data
|
81
|
+
# log 'receive_data', data
|
73
82
|
@buf << data
|
74
|
-
log 'receive_data', data
|
75
83
|
|
76
84
|
while frame = Frame.parse(@buf)
|
77
85
|
log 'receive', frame
|
@@ -92,9 +100,16 @@ module AMQP
|
|
92
100
|
send_data data.to_s
|
93
101
|
end
|
94
102
|
|
95
|
-
def send_data data
|
96
|
-
|
97
|
-
|
103
|
+
# def send_data data
|
104
|
+
# log 'send_data', data
|
105
|
+
# super
|
106
|
+
# end
|
107
|
+
|
108
|
+
def close
|
109
|
+
send Protocol::Connection::Close.new(:reply_code => 200,
|
110
|
+
:reply_text => 'Goodbye',
|
111
|
+
:class_id => 0,
|
112
|
+
:method_id => 0)
|
98
113
|
end
|
99
114
|
|
100
115
|
def unbind
|
@@ -102,13 +117,14 @@ module AMQP
|
|
102
117
|
end
|
103
118
|
|
104
119
|
def self.connect opts = {}
|
120
|
+
opts = AMQP.settings.merge(opts)
|
105
121
|
opts[:host] ||= 'localhost'
|
106
122
|
opts[:port] ||= PORT
|
107
123
|
|
108
124
|
dfr = EM::DefaultDeferrable.new
|
109
125
|
|
110
126
|
EM.run{
|
111
|
-
EM.connect opts[:host], opts[:port], self, dfr
|
127
|
+
EM.connect opts[:host], opts[:port], self, dfr, opts
|
112
128
|
}
|
113
129
|
|
114
130
|
dfr
|
@@ -118,16 +134,9 @@ module AMQP
|
|
118
134
|
|
119
135
|
def log *args
|
120
136
|
return unless AMQP.logging
|
137
|
+
require 'pp'
|
121
138
|
pp args
|
122
139
|
puts
|
123
140
|
end
|
124
141
|
end
|
125
|
-
|
126
|
-
def self.start *args
|
127
|
-
@conn ||= Client.connect *args
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
if $0 == __FILE__
|
132
|
-
AMQP.start
|
133
142
|
end
|
data/lib/amqp/protocol.rb
CHANGED
@@ -23,6 +23,12 @@ module AMQP
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
def arguments
|
27
|
+
self.class.arguments.inject({}) do |hash, (type, name)|
|
28
|
+
hash.update name => instance_variable_get("@#{name}")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
26
32
|
def to_binary
|
27
33
|
buf = Buffer.new
|
28
34
|
buf.write :short, self.class.parent.id
|
@@ -116,8 +122,8 @@ module AMQP
|
|
116
122
|
end
|
117
123
|
|
118
124
|
def method_missing meth, *args, &blk
|
119
|
-
@klass.properties.
|
120
|
-
|
125
|
+
@properties.has_key?(meth) || @klass.properties.find{|_,name| name == meth } ? @properties[meth] :
|
126
|
+
super
|
121
127
|
end
|
122
128
|
end
|
123
129
|
|
data/lib/mq.rb
CHANGED
@@ -10,6 +10,8 @@ class MQ
|
|
10
10
|
@logging = false
|
11
11
|
attr_accessor :logging
|
12
12
|
end
|
13
|
+
|
14
|
+
class Error < Exception; end
|
13
15
|
end
|
14
16
|
|
15
17
|
class MQ
|
@@ -35,6 +37,7 @@ class MQ
|
|
35
37
|
when Frame::Body
|
36
38
|
@body << frame.payload
|
37
39
|
if @body.length >= @header.size
|
40
|
+
@header.properties.update(@method.arguments)
|
38
41
|
@consumer.receive @header, @body
|
39
42
|
@body = ''
|
40
43
|
end
|
@@ -49,12 +52,30 @@ class MQ
|
|
49
52
|
|
50
53
|
when Protocol::Access::RequestOk
|
51
54
|
@ticket = method.ticket
|
55
|
+
callback{
|
56
|
+
send Protocol::Channel::Close.new(:reply_code => 200,
|
57
|
+
:reply_text => 'bye',
|
58
|
+
:method_id => 0,
|
59
|
+
:class_id => 0)
|
60
|
+
} if @closing
|
52
61
|
succeed
|
53
62
|
|
54
63
|
when Protocol::Basic::Deliver
|
64
|
+
@method = method
|
55
65
|
@header = nil
|
56
66
|
@body = ''
|
57
67
|
@consumer = queues[ method.consumer_tag ]
|
68
|
+
|
69
|
+
|
70
|
+
when Protocol::Channel::Close
|
71
|
+
raise Error, "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]}"
|
72
|
+
|
73
|
+
when Protocol::Channel::CloseOk
|
74
|
+
@closing = false
|
75
|
+
conn.callback{ |c|
|
76
|
+
c.channels.delete(@channel)
|
77
|
+
c.close unless c.channels.keys.any?
|
78
|
+
}
|
58
79
|
end
|
59
80
|
end
|
60
81
|
end
|
@@ -83,12 +104,15 @@ class MQ
|
|
83
104
|
rpcs[name] ||= RPC.new(self, name, obj)
|
84
105
|
end
|
85
106
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
107
|
+
def close
|
108
|
+
if @deferred_status == :succeeded
|
109
|
+
send Protocol::Channel::Close.new(:reply_code => 200,
|
110
|
+
:reply_text => 'bye',
|
111
|
+
:method_id => 0,
|
112
|
+
:class_id => 0)
|
113
|
+
else
|
114
|
+
@closing = true
|
115
|
+
end
|
92
116
|
end
|
93
117
|
|
94
118
|
# keep track of proxy objects
|
@@ -105,9 +129,18 @@ class MQ
|
|
105
129
|
@rcps ||= {}
|
106
130
|
end
|
107
131
|
|
132
|
+
private
|
133
|
+
|
134
|
+
def log *args
|
135
|
+
return unless MQ.logging
|
136
|
+
pp args
|
137
|
+
puts
|
138
|
+
end
|
139
|
+
|
108
140
|
# create a class level connection on demand
|
109
141
|
|
110
142
|
def connection
|
143
|
+
raise 'MQ can only be used within EM.run{}' unless EM.reactor_running?
|
111
144
|
@@connection ||= AMQP.start
|
112
145
|
end
|
113
146
|
alias :conn :connection
|
data/lib/mq/exchange.rb
CHANGED
@@ -5,6 +5,7 @@ class MQ
|
|
5
5
|
def initialize mq, type, name, opts = {}
|
6
6
|
@mq = mq
|
7
7
|
@type, @name = type, name
|
8
|
+
@mq.exchanges[@name = name] ||= self
|
8
9
|
@key = opts[:key]
|
9
10
|
|
10
11
|
@mq.callback{
|
@@ -17,18 +18,16 @@ class MQ
|
|
17
18
|
|
18
19
|
def publish data, opts = {}
|
19
20
|
@mq.callback{
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
data = data.to_s
|
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
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
26
|
+
@mq.send Protocol::Header.new(Protocol::Basic,
|
27
|
+
data.length, { :content_type => 'application/octet-stream',
|
28
|
+
:delivery_mode => (opts.delete(:persistent) ? 2 : 1),
|
29
|
+
:priority => 0 }.merge(opts))
|
30
|
+
@mq.send Frame::Body.new(data)
|
32
31
|
}
|
33
32
|
self
|
34
33
|
end
|
data/lib/mq/queue.rb
CHANGED
data/lib/mq/rpc.rb
CHANGED
@@ -1,15 +1,8 @@
|
|
1
|
-
unless defined?(BlankSlate)
|
2
|
-
class BlankSlate < BasicObject; end if defined?(BasicObject)
|
3
|
-
|
4
|
-
class BlankSlate
|
5
|
-
instance_methods.each { |m| undef_method m unless m =~ /^__/ }
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
1
|
class MQ
|
10
2
|
class RPC < BlankSlate
|
11
3
|
def initialize mq, queue, obj = nil
|
12
4
|
@mq = mq
|
5
|
+
@mq.rpcs[queue] ||= self
|
13
6
|
|
14
7
|
if obj
|
15
8
|
@obj = case obj
|
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.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aman Gupta
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-07-
|
12
|
+
date: 2008-07-29 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -32,19 +32,22 @@ extra_rdoc_files: []
|
|
32
32
|
|
33
33
|
files:
|
34
34
|
- README
|
35
|
-
- examples/
|
36
|
-
- examples/
|
37
|
-
- examples/
|
38
|
-
- examples/
|
39
|
-
- examples/
|
40
|
-
- examples/simple.rb
|
41
|
-
- examples/
|
35
|
+
- examples/amqp/simple.rb
|
36
|
+
- examples/mq/clock.rb
|
37
|
+
- examples/mq/hashtable.rb
|
38
|
+
- examples/mq/logger.rb
|
39
|
+
- examples/mq/pingpong.rb
|
40
|
+
- examples/mq/primes-simple.rb
|
41
|
+
- examples/mq/primes.rb
|
42
|
+
- examples/mq/simple.rb
|
43
|
+
- examples/mq/stocks.rb
|
42
44
|
- lib/amqp/buffer.rb
|
43
45
|
- lib/amqp/client.rb
|
44
46
|
- lib/amqp/frame.rb
|
45
47
|
- lib/amqp/protocol.rb
|
46
48
|
- lib/amqp/spec.rb
|
47
49
|
- lib/amqp.rb
|
50
|
+
- lib/ext/blankslate.rb
|
48
51
|
- lib/ext/em.rb
|
49
52
|
- lib/ext/emfork.rb
|
50
53
|
- lib/mq/exchange.rb
|