amqp 0.6.0 → 0.6.4

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 CHANGED
@@ -21,10 +21,14 @@ To use with RabbitMQ, first run the server:
21
21
 
22
22
  To get started, refer to the various bundled examples:
23
23
 
24
- ruby examples/mq/simple.rb # low-level Queue/Exchange api
25
24
  ruby examples/mq/pingpong.rb # 1-1 communication using amq.direct
26
25
  ruby examples/mq/clock.rb # 1-N communication using amq.fanout
27
26
  ruby examples/mq/stocks.rb # 1-subscriber communication using amq.topic
27
+
28
+ ruby examples/mq/multiclock.rb # header based routing (new rabbitmq feature)
29
+ ruby examples/mq/ack.rb # using ack
30
+ ruby examples/mq/pop.rb # pop off messages one at a time
31
+
28
32
  ruby examples/mq/hashtable.rb # simple async rpc layer
29
33
  ruby examples/mq/primes.rb 4 # parallelized prime number generation
30
34
  ruby examples/mq/logger.rb # simple logging api
@@ -32,6 +36,7 @@ To get started, refer to the various bundled examples:
32
36
  For more details into the lower level AMQP client API, run the simple client example:
33
37
 
34
38
  ruby examples/amqp/simple.rb # low-level AMQP api
39
+ ruby examples/mq/internal.rb # low-level Queue/Exchange api
35
40
 
36
41
  Or refer to protocol/doc.txt, which enumerates packets sent between a server and client
37
42
  during a typical session, in both binary and decoded formats.
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ task :codegen do
2
+ sh 'ruby protocol/codegen.rb > lib/amqp/spec.rb'
3
+ sh 'ruby lib/amqp/spec.rb'
4
+ end
5
+
6
+ task :spec do
7
+ sh 'bacon lib/amqp.rb'
8
+ end
9
+
10
+ task :gem do
11
+ sh 'gem build *.gemspec'
12
+ end
13
+
14
+ task :pkg => :gem
15
+ task :package => :gem
data/amqp.gemspec ADDED
@@ -0,0 +1,83 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = 'amqp'
3
+ s.version = '0.6.4'
4
+ s.date = '2009-01-09'
5
+ s.summary = 'AMQP client implementation in Ruby/EventMachine'
6
+ s.email = "amqp@tmm1.net"
7
+ s.homepage = "http://amqp.rubyforge.org/"
8
+ s.description = "AMQP client implementation in Ruby/EventMachine"
9
+ s.has_rdoc = true
10
+ s.rdoc_options = '--include=examples'
11
+
12
+ # ruby -rpp -e' pp `git ls-files`.split("\n").grep(/^(doc|README)/) '
13
+ s.extra_rdoc_files = [
14
+ "README",
15
+ "doc/EXAMPLE_01_PINGPONG",
16
+ "doc/EXAMPLE_02_CLOCK",
17
+ "doc/EXAMPLE_03_STOCKS",
18
+ "doc/EXAMPLE_04_MULTICLOCK",
19
+ "doc/EXAMPLE_05_ACK",
20
+ "doc/EXAMPLE_05_POP",
21
+ "doc/EXAMPLE_06_HASHTABLE"
22
+ ]
23
+
24
+ s.authors = ["Aman Gupta"]
25
+ s.add_dependency('eventmachine', '>= 0.12.4')
26
+
27
+ # ruby -rpp -e' pp `git ls-files`.split("\n") '
28
+ s.files = [
29
+ "README",
30
+ "Rakefile",
31
+ "amqp.gemspec",
32
+ "amqp.todo",
33
+ "doc/EXAMPLE_01_PINGPONG",
34
+ "doc/EXAMPLE_02_CLOCK",
35
+ "doc/EXAMPLE_03_STOCKS",
36
+ "doc/EXAMPLE_04_MULTICLOCK",
37
+ "doc/EXAMPLE_05_ACK",
38
+ "doc/EXAMPLE_05_POP",
39
+ "doc/EXAMPLE_06_HASHTABLE",
40
+ "examples/amqp/simple.rb",
41
+ "examples/mq/ack.rb",
42
+ "examples/mq/clock.rb",
43
+ "examples/mq/pop.rb",
44
+ "examples/mq/hashtable.rb",
45
+ "examples/mq/internal.rb",
46
+ "examples/mq/logger.rb",
47
+ "examples/mq/multiclock.rb",
48
+ "examples/mq/pingpong.rb",
49
+ "examples/mq/primes-simple.rb",
50
+ "examples/mq/primes.rb",
51
+ "examples/mq/stocks.rb",
52
+ "lib/amqp.rb",
53
+ "lib/amqp/buffer.rb",
54
+ "lib/amqp/client.rb",
55
+ "lib/amqp/frame.rb",
56
+ "lib/amqp/protocol.rb",
57
+ "lib/amqp/server.rb",
58
+ "lib/amqp/spec.rb",
59
+ "lib/ext/blankslate.rb",
60
+ "lib/ext/em.rb",
61
+ "lib/ext/emfork.rb",
62
+ "lib/mq.rb",
63
+ "lib/mq/exchange.rb",
64
+ "lib/mq/header.rb",
65
+ "lib/mq/logger.rb",
66
+ "lib/mq/queue.rb",
67
+ "lib/mq/rpc.rb",
68
+ "old/README",
69
+ "old/Rakefile",
70
+ "old/amqp-0.8.json",
71
+ "old/amqp_spec.rb",
72
+ "old/amqpc.rb",
73
+ "old/codegen.rb",
74
+ "protocol/amqp-0.8.json",
75
+ "protocol/amqp-0.8.xml",
76
+ "protocol/codegen.rb",
77
+ "protocol/doc.txt",
78
+ "research/api.rb",
79
+ "research/primes-forked.rb",
80
+ "research/primes-processes.rb",
81
+ "research/primes-threaded.rb"
82
+ ]
83
+ end
data/amqp.todo ADDED
@@ -0,0 +1,32 @@
1
+ - breaks with header values that are nil
2
+ - breaks with header values that are ruby objects (convert to strings?)
3
+ - sending utf8 data in 1.9 breaks
4
+
5
+ - generate amqp/spec.rb from original xml spec
6
+ - add peek and pop to queues
7
+ - use rabbitmq generated consumer tag from basic.consume-ok reply
8
+
9
+ - allow temporary queues with amq.queue(nil) syntax (use uuids)
10
+ - use as temp queue in rpc
11
+ - use uuids for message ids in rpc
12
+
13
+ - add ack/completed responses for messages
14
+ - deleting queues/bindings/exchanges
15
+ + queue.unbind
16
+ - queue.remove or queue.close or queue.delete
17
+ - exchange.remove
18
+ - rpc.remove
19
+
20
+ - handle errors and exceptions
21
+ binding to a non-existent (or not yet created in clock.rb) exchange
22
+ #<AMQP::Protocol::Channel::Close:0x11d35d4
23
+ @class_id=50,
24
+ @debug=1,
25
+ @method_id=20,
26
+ @reply_code=404,
27
+ @reply_text="NOT_FOUND - no exchange 'clock' in vhost '/'">>]
28
+
29
+ - handle connection.redirect during connect (for rabbitmq in distributed mode) [or just set insist to true]
30
+
31
+ - add amq.queue('name').size{ |num| "#{num} messages in the queue" } (send declare passive, look at declare-ok response)
32
+ - clean up MQ.default on disconnect
@@ -0,0 +1,2 @@
1
+ == Ping Pong Example
2
+ :include: mq/pingpong.rb
@@ -0,0 +1,2 @@
1
+ == Clock Example
2
+ :include: mq/clock.rb
@@ -0,0 +1,2 @@
1
+ == Stocks Example
2
+ :include: mq/stocks.rb
@@ -0,0 +1,2 @@
1
+ == Muti-format Clock Example
2
+ :include: mq/multiclock.rb
@@ -0,0 +1,2 @@
1
+ == Ack Example
2
+ :include: mq/ack.rb
@@ -0,0 +1,2 @@
1
+ == Pop Example
2
+ :include: mq/pop.rb
@@ -0,0 +1,2 @@
1
+ == HashTable RPC Example
2
+ :include: mq/hashtable.rb
@@ -1,13 +1,12 @@
1
1
  $:.unshift File.dirname(__FILE__) + '/../../lib'
2
2
  require 'mq'
3
- require 'pp'
4
3
 
5
- # For ack to work appropriatly you must shutdown AMQP gracefully,
4
+ # For ack to work appropriately you must shutdown AMQP gracefully,
6
5
  # otherwise all items in your queue will be returned
7
6
  Signal.trap('INT') { AMQP.stop{ EM.stop } }
8
7
  Signal.trap('TERM'){ AMQP.stop{ EM.stop } }
9
8
 
10
- EM.run do
9
+ AMQP.start(:host => 'localhost') do
11
10
  MQ.queue('awesome').publish('Totally rad 1')
12
11
  MQ.queue('awesome').publish('Totally rad 2')
13
12
  MQ.queue('awesome').publish('Totally rad 3')
data/examples/mq/clock.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  $:.unshift File.dirname(__FILE__) + '/../../lib'
2
2
  require 'mq'
3
3
 
4
- EM.run{
4
+ AMQP.start(:host => 'localhost') do
5
5
 
6
6
  def log *args
7
7
  p args
@@ -28,7 +28,7 @@ EM.run{
28
28
  log 'every 5 seconds', :received, time if time.strftime('%S').to_i%5 == 0
29
29
  }
30
30
 
31
- }
31
+ end
32
32
 
33
33
  __END__
34
34
 
@@ -1,7 +1,7 @@
1
1
  $:.unshift File.dirname(__FILE__) + '/../../lib'
2
2
  require 'mq'
3
3
 
4
- EM.run{
4
+ AMQP.start(:host => 'localhost') do
5
5
 
6
6
  def log *args
7
7
  p args
@@ -37,10 +37,10 @@ EM.run{
37
37
  client.set(:one, 1)
38
38
  client.keys do |res|
39
39
  log 'client', :keys => res
40
- EM.stop_event_loop
40
+ AMQP.stop{ EM.stop }
41
41
  end
42
42
 
43
- }
43
+ end
44
44
 
45
45
  __END__
46
46
 
File without changes
@@ -4,7 +4,7 @@ require 'mq/logger'
4
4
 
5
5
  Logger = MQ::Logger
6
6
 
7
- EM.run{
7
+ AMQP.start(:host => 'localhost') do
8
8
  if ARGV[0] == 'server'
9
9
 
10
10
  MQ.queue('logger').bind(MQ.fanout('logging', :durable => true)).subscribe{|msg|
@@ -37,7 +37,7 @@ EM.run{
37
37
  log = Logger.new(:webserver, :timestamp, :hostname, &log.printer)
38
38
  log.info 'Request for /', :GET, :session => 'abc'
39
39
 
40
- AMQP.stop{ EM.stop_event_loop }
40
+ AMQP.stop{ EM.stop }
41
41
 
42
42
  else
43
43
 
@@ -50,7 +50,7 @@ EM.run{
50
50
  EM.stop
51
51
 
52
52
  end
53
- }
53
+ end
54
54
 
55
55
  __END__
56
56
 
@@ -0,0 +1,49 @@
1
+ $:.unshift File.dirname(__FILE__) + '/../../lib'
2
+ require 'mq'
3
+ require 'time'
4
+
5
+ AMQP.start(:host => 'localhost') do
6
+
7
+ def log *args
8
+ p args
9
+ end
10
+
11
+ #AMQP.logging = true
12
+
13
+ clock = MQ.new.headers('multiformat_clock')
14
+ EM.add_periodic_timer(1){
15
+ puts
16
+
17
+ time = Time.new
18
+ ["iso8601","rfc2822"].each do |format|
19
+ formatted_time = time.send(format)
20
+ log :publish, format, formatted_time
21
+ clock.publish "#{formatted_time}", :headers => {"format" => format}
22
+ end
23
+ }
24
+
25
+ ["iso8601","rfc2822"].each do |format|
26
+ amq = MQ.new
27
+ amq.queue(format.to_s).bind(amq.headers('multiformat_clock'), :arguments => {"format" => format}).subscribe{ |time|
28
+ log "received #{format}", time
29
+ }
30
+ end
31
+
32
+ end
33
+
34
+ __END__
35
+
36
+ [:publish, "iso8601", "2009-02-13T19:55:40-08:00"]
37
+ [:publish, "rfc2822", "Fri, 13 Feb 2009 19:55:40 -0800"]
38
+ ["received iso8601", "2009-02-13T19:55:40-08:00"]
39
+ ["received rfc2822", "Fri, 13 Feb 2009 19:55:40 -0800"]
40
+
41
+ [:publish, "iso8601", "2009-02-13T19:55:41-08:00"]
42
+ [:publish, "rfc2822", "Fri, 13 Feb 2009 19:55:41 -0800"]
43
+ ["received iso8601", "2009-02-13T19:55:41-08:00"]
44
+ ["received rfc2822", "Fri, 13 Feb 2009 19:55:41 -0800"]
45
+
46
+ [:publish, "iso8601", "2009-02-13T19:55:42-08:00"]
47
+ [:publish, "rfc2822", "Fri, 13 Feb 2009 19:55:42 -0800"]
48
+ ["received iso8601", "2009-02-13T19:55:42-08:00"]
49
+ ["received rfc2822", "Fri, 13 Feb 2009 19:55:42 -0800"]
@@ -1,7 +1,7 @@
1
1
  $:.unshift File.dirname(__FILE__) + '/../../lib'
2
2
  require 'mq'
3
3
 
4
- EM.run{
4
+ AMQP.start(:host => 'localhost') do
5
5
 
6
6
  def log *args
7
7
  p [ Time.now, *args ]
@@ -28,7 +28,7 @@ EM.run{
28
28
  log 'two', :received, msg
29
29
  }
30
30
 
31
- }
31
+ end
32
32
 
33
33
  __END__
34
34
 
File without changes
@@ -11,7 +11,7 @@ end
11
11
 
12
12
  # spawn workers
13
13
  workers = ARGV[0] ? (Integer(ARGV[0]) rescue 1) : 1
14
- EM.fork(workers) do
14
+ AMQP.fork(workers) do
15
15
 
16
16
  log MQ.id, :started
17
17
 
@@ -33,7 +33,7 @@ EM.fork(workers) do
33
33
  end
34
34
 
35
35
  # use workers to check which numbers are prime
36
- EM.run{
36
+ AMQP.start(:host => 'localhost') do
37
37
 
38
38
  prime_checker = MQ.rpc('prime checker')
39
39
 
@@ -52,7 +52,7 @@ EM.run{
52
52
 
53
53
  end
54
54
 
55
- }
55
+ end
56
56
 
57
57
  __END__
58
58
 
@@ -1,7 +1,7 @@
1
1
  $:.unshift File.dirname(__FILE__) + '/../../lib'
2
2
  require 'mq'
3
3
 
4
- EM.run{
4
+ AMQP.start(:host => 'localhost') do
5
5
 
6
6
  def log *args
7
7
  p [ Time.now, *args ]
@@ -41,7 +41,7 @@ EM.run{
41
41
  watch_appl_stock
42
42
  watch_us_stocks
43
43
 
44
- }
44
+ end
45
45
 
46
46
  __END__
47
47
 
data/lib/amqp.rb CHANGED
@@ -38,7 +38,10 @@ module AMQP
38
38
  :timeout => nil,
39
39
 
40
40
  # logging
41
- :logging => false
41
+ :logging => false,
42
+
43
+ # ssl
44
+ :ssl => false
42
45
  }
43
46
  end
44
47
 
@@ -99,4 +102,14 @@ module AMQP
99
102
  }
100
103
  end
101
104
  end
105
+
106
+ def self.fork workers
107
+ EM.fork(workers) do
108
+ # clean up globals in the fork
109
+ Thread.current[:mq] = nil
110
+ AMQP.instance_variable_set('@conn', nil)
111
+
112
+ yield
113
+ end
114
+ end
102
115
  end
data/lib/amqp/client.rb CHANGED
@@ -9,7 +9,7 @@ module AMQP
9
9
  mq.process_frame(frame)
10
10
  return
11
11
  end
12
-
12
+
13
13
  case frame
14
14
  when Frame::Method
15
15
  case method = frame.payload
@@ -49,7 +49,7 @@ module AMQP
49
49
  def self.client
50
50
  @client ||= BasicClient
51
51
  end
52
-
52
+
53
53
  def self.client= mod
54
54
  mod.__send__ :include, AMQP
55
55
  @client = mod
@@ -65,23 +65,35 @@ module AMQP
65
65
  @on_disconnect ||= proc{ raise Error, "Could not connect to server #{opts[:host]}:#{opts[:port]}" }
66
66
 
67
67
  timeout @settings[:timeout] if @settings[:timeout]
68
- errback{ @on_disconnect.call }
68
+ errback{ @on_disconnect.call } unless @reconnecting
69
+
70
+ @connected = false
69
71
  end
70
72
 
71
73
  def connection_completed
74
+ start_tls if @settings[:ssl]
72
75
  log 'connected'
73
76
  # @on_disconnect = proc{ raise Error, 'Disconnected from server' }
74
77
  unless @closing
75
- @on_disconnect = method(:reconnect)
78
+ @on_disconnect = method(:disconnected)
76
79
  @reconnecting = false
77
80
  end
81
+
82
+ @connected = true
83
+ @connection_status.call(:connected) if @connection_status
84
+
78
85
  @buf = Buffer.new
79
86
  send_data HEADER
80
87
  send_data [1, 1, VERSION_MAJOR, VERSION_MINOR].pack('C4')
81
88
  end
82
89
 
90
+ def connected?
91
+ @connected
92
+ end
93
+
83
94
  def unbind
84
95
  log 'disconnected'
96
+ @connected = false
85
97
  EM.next_tick{ @on_disconnect.call }
86
98
  end
87
99
 
@@ -95,7 +107,7 @@ module AMQP
95
107
  def channels
96
108
  @channels ||= {}
97
109
  end
98
-
110
+
99
111
  def receive_data data
100
112
  # log 'receive_data', data
101
113
  @buf << data
@@ -110,7 +122,7 @@ module AMQP
110
122
  # this is a stub meant to be
111
123
  # replaced by the module passed into initialize
112
124
  end
113
-
125
+
114
126
  def send data, opts = {}
115
127
  channel = opts[:channel] ||= 0
116
128
  data = data.to_frame(channel) unless data.is_a? Frame
@@ -158,14 +170,14 @@ module AMQP
158
170
  end
159
171
 
160
172
  unless @reconnecting
173
+ @reconnecting = true
174
+
161
175
  @deferred_status = nil
162
176
  initialize(@settings)
163
177
 
164
178
  mqs = @channels
165
179
  @channels = {}
166
180
  mqs.each{ |_,mq| mq.reset } if mqs
167
-
168
- @reconnecting = true
169
181
  end
170
182
 
171
183
  log 'reconnecting'
@@ -176,9 +188,18 @@ module AMQP
176
188
  opts = AMQP.settings.merge(opts)
177
189
  EM.connect opts[:host], opts[:port], self, opts
178
190
  end
179
-
191
+
192
+ def connection_status &blk
193
+ @connection_status = blk
194
+ end
195
+
180
196
  private
181
-
197
+
198
+ def disconnected
199
+ @connection_status.call(:disconnected) if @connection_status
200
+ reconnect
201
+ end
202
+
182
203
  def log *args
183
204
  return unless @settings[:logging] or AMQP.logging
184
205
  require 'pp'
@@ -186,4 +207,4 @@ module AMQP
186
207
  puts
187
208
  end
188
209
  end
189
- end
210
+ end