brontes3d-amqp 0.6.4.3 → 0.6.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,143 @@
1
+ What AMQP gem is
2
+ ===================
3
+
4
+ Simple asynchronous AMQP driver for Ruby/EventMachine
5
+ This library works with Ruby 1.8, Ruby 1.9, JRuby and Rubinius, and is licensed under [the Ruby License](http://www.ruby-lang.org/en/LICENSE.txt).
6
+
7
+ This library was tested primarily with RabbitMQ, although it should be compatible with any
8
+ server implementing the [AMQP 0-8 spec](http://www.amqp.org/confluence/download/attachments/720900/amqp0-8.pdf).
9
+
10
+ Getting started
11
+ ===============
12
+
13
+ To use examples with RabbitMQ, first [install the broker](http://www.rabbitmq.com/install.html). If you have Mercurial
14
+ and Erlang/OTP installed, here is how to do it in 4 lines:
15
+
16
+ hg clone http://hg.rabbitmq.com/rabbitmq-codegen
17
+ hg clone http://hg.rabbitmq.com/rabbitmq-server
18
+ cd rabbitmq-server
19
+ make run
20
+
21
+ Then have a look at the various bundled examples:
22
+
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
+
27
+ ruby examples/mq/multiclock.rb # header based routing (new rabbitmq feature)
28
+ ruby examples/mq/ack.rb # using ack
29
+ ruby examples/mq/pop.rb # pop off messages one at a time
30
+
31
+ ruby examples/mq/hashtable.rb # simple async rpc layer
32
+ ruby examples/mq/primes.rb 4 # parallelized prime number generation
33
+ ruby examples/mq/logger.rb # simple logging api
34
+
35
+ For high level API documentation see MQ class.
36
+ For more details into the lower level AMQP client API, run the simple client example:
37
+
38
+ ruby examples/amqp/simple.rb # low-level AMQP api
39
+ ruby examples/mq/internal.rb # low-level Queue/Exchange api
40
+
41
+ Or refer to protocol/doc.txt, which enumerates packets sent between a server and client
42
+ during a typical session, in both binary and decoded formats.
43
+
44
+ How to use AMQP gem with Ruby on Rails, Merb, Sinatra and other web frameworks
45
+ ==============================================================================
46
+
47
+ To use AMQP gem from web applications, you would need to have EventMachine reactor running.
48
+ If you use [Thin](http://code.macournoyer.com/thin/), you are set: Thin uses EventMachine under
49
+ the hook.
50
+
51
+ With other web servers, you need to start EventMachine reactor in it's own thread like this:
52
+
53
+ Thread.new { EM.run }
54
+
55
+ because otherwise EventMachine will block current thread. Then connect to AMQP broker:
56
+
57
+ AMQP.connect(:host => "localhost", :user => "guest", :pass => "guest", :vhost => "/")
58
+
59
+ In a Ruby on Rails app, probably the best place for this code is initializer
60
+ (like config/initializers/amqp.rb). For Merb apps, it is config/init.rb. For
61
+ Sinatra and pure Rack applications, place it next to other configuration
62
+ code.
63
+
64
+ Same separate thread technique can be used to make EventMachine play nicely with other
65
+ libraries that would block current thread (like [File::Tail](http://rubygems.org/gems/file-tail)).
66
+
67
+ AMQP gem mailing list
68
+ ==============================
69
+
70
+ * [AMQP gem mailing list](http://groups.google.com/group/ruby-amqp)
71
+ * [AMQP gem at GitHub](http://github.com/tmm1/amqp)
72
+ * [AMQP gem at Gemcutter](http://rubygems.org/gems/amqp)
73
+
74
+ Running specifications suite
75
+ ============================
76
+
77
+ To run the test suite make sure you have [bacon](http://gemcutter.org/gems/bacon) gem installed and run:
78
+
79
+ rake spec
80
+
81
+ The lib/amqp/spec.rb file is generated automatically based on the [AMQP specification](http://www.amqp.org/confluence/display/AMQP/AMQP+Specification). To generate it:
82
+
83
+ rake codegen
84
+
85
+ Credits and more information
86
+ ============================
87
+
88
+ (c) 2008—2010 [Aman Gupta](http://github.com/tmm1) (tmm1)
89
+
90
+ This project was inspired by [py-amqplib](http://barryp.org/software/py-amqplib/), [rabbitmq](http://rabbitmq.com), [qpid](http://qpid.apache.org/) and [rubbyt](http://github.com/rubbyt/rubbyt).
91
+ Special thanks to Dmitriy Samovskiy, Ben Hood and Tony Garnock-Jones.
92
+
93
+ AMQP brokers
94
+ ------------
95
+
96
+ * [RabbitMQ](http://rabbitmq.com) (Rabbit Technologies, Erlang/OTP, MPL)
97
+ * [ZeroMQ](http://www.zeromq.org) (iMatix/FastMQ/Intel, C++, GPL3)
98
+ * [OpenAMQ](http://openamq.org) (iMatix, C, GPL2)
99
+ * [ActiveMQ](http://activemq.apache.org) (Apache Foundation, Java, Apache2)
100
+
101
+ AMQP resources
102
+ --------------
103
+
104
+ * Steve Vinoski [explains AMQP](http://steve.vinoski.net/pdf/IEEE-Advanced_Message_Queuing_Protocol.pdf) in his column, Towards Integration
105
+
106
+ * John O'Hara on [the history of AMQP](http://www.acmqueue.org/modules.php?name=Content&pa=showpage&pid=485)
107
+
108
+ * Dmitriy's [presentation on RabbitMQ/AMQP](http://somic-org.homelinux.org/blog/2008/07/31/slides-for-my-amqprabbitmq-talk/)
109
+
110
+ * ZeroMQ's [analysis of the messaging technology market](http://www.zeromq.org/whitepapers:market-analysis)
111
+
112
+ * Pieter Hintjens's [background to AMQP](http://www.openamq.org/doc:amqp-background)
113
+
114
+ * Barry Pederson's [py-amqplib](http://barryp.org/software/py-amqplib/)
115
+
116
+ * Ben Hood on [writing an AMQP client](http://hopper.squarespace.com/blog/2008/6/21/build-your-own-amqp-client.html)
117
+
118
+ * Dmitriy Samovskiy introduces [Ruby + QPid + RabbitMQ](http://somic-org.homelinux.org/blog/2008/06/24/ruby-amqp-rabbitmq-example/)
119
+
120
+ * Ben Hood's [as3-amqp](http://github.com/0x6e6562/as3-amqp) ([two](http://hopper.squarespace.com/blog/2008/7/4/server-side-as3.html), [three](http://hopper.squarespace.com/blog/2008/3/24/as3-amqp-client-first-cut.html))
121
+
122
+ * RabbitMQ's [AMQP protocol code generator](http://hg.rabbitmq.com/rabbitmq-codegen/)
123
+
124
+ * Erlang Exchange [presentation on the implementation of RabbitMQ](http://skillsmatter.com/podcast/erlang/presenting-rabbitmq-an-erlang-based-implementatio-nof-amqp) (and on the [LShift blog](http://www.lshift.net/blog/2008/07/01/slides-from-our-erlang-exchange-talk))
125
+
126
+ * Jonathan Conway's series on RabbitMQ and using it with Ruby and Merb: [One](http://jaikoo.com/2007/9/4/didn-t-you-get-the-memo), [Two](http://jaikoo.com/2008/2/29/friday-round-up-2008-02-29), [Three](http://jaikoo.com/2008/3/14/oh-hai-rabbitmq), [Four](http://jaikoo.com/2008/3/20/daemonize-rabbitmq)
127
+
128
+ * Open Enterprise's series on messaging middleware and AMQP: [Part 1](http://www1.interopsystems.com/analysis/can-amqp-break-ibms-mom-monopoly-part-1.html), [Part 2](http://www1.interopsystems.com/analysis/can-amqp-break-ibms-mom-monopoly-part-2.html), [Part 3](http://www1.interopsystems.com/analysis/can-amqp-break-ibms-mom-monopoly-part-3.html)
129
+
130
+ Messaging and distributed systems resources
131
+ -------------------------------------------
132
+
133
+ * [A Critique of the Remote Procedure Call Paradigm](http://www.cs.vu.nl/~ast/publications/euteco-1988.pdf)
134
+
135
+ * [A Note on Distributed Computing](http://research.sun.com/techrep/1994/smli_tr-94-29.pdf)
136
+
137
+ * [Convenience Over Correctness](http://steve.vinoski.net/pdf/IEEE-Convenience_Over_Correctness.pdf)
138
+
139
+ * [Metaprotocol Taxonomy and Communications Patterns](http://hessian.caucho.com/doc/metaprotocol-taxonomy.xtp)
140
+
141
+ * Joe Armstrong on [Erlang messaging vs RPC](http://armstrongonsoftware.blogspot.com/2008/05/road-we-didnt-go-down.html)
142
+
143
+ * [SEDA: scalable internet services using message queues](http://www.eecs.harvard.edu/~mdw/papers/seda-sosp01.pdf)
data/Rakefile CHANGED
@@ -1,16 +1,22 @@
1
+ desc "Generate AMQP specification classes"
1
2
  task :codegen do
2
3
  sh 'ruby protocol/codegen.rb > lib/amqp/spec.rb'
3
4
  sh 'ruby lib/amqp/spec.rb'
4
5
  end
5
6
 
7
+ desc "Run spec suite (uses bacon gem)"
6
8
  task :spec do
7
9
  sh 'bacon lib/amqp.rb'
8
10
  end
9
11
 
12
+ desc "Build the gem"
10
13
  task :gem do
11
14
  sh 'gem build *.gemspec'
12
15
  end
13
16
 
17
+ desc "Synonym for gem"
14
18
  task :pkg => :gem
19
+ desc "Synonym for gem"
15
20
  task :package => :gem
16
- task :default => :spec
21
+
22
+ task :default => :spec
@@ -1,17 +1,20 @@
1
+ require File.expand_path('../lib/amqp/version', __FILE__)
2
+
1
3
  spec = Gem::Specification.new do |s|
2
4
  s.name = 'amqp'
3
- s.version = '0.6.4.3'
4
- s.date = '2009-01-09'
5
+ s.version = AMQP::VERSION
6
+ s.date = '2009-12-29'
5
7
  s.summary = 'AMQP client implementation in Ruby/EventMachine'
6
8
  s.email = "amqp@tmm1.net"
7
9
  s.homepage = "http://amqp.rubyforge.org/"
8
- s.description = "AMQP client implementation in Ruby/EventMachine"
10
+ s.rubyforge_project = 'amqp'
11
+ s.description = "An implementation of the AMQP protocol in Ruby/EventMachine for writing clients to the RabbitMQ message broker"
9
12
  s.has_rdoc = true
10
13
  s.rdoc_options = '--include=examples'
11
14
 
12
15
  # ruby -rpp -e' pp `git ls-files`.split("\n").grep(/^(doc|README)/) '
13
16
  s.extra_rdoc_files = [
14
- "README",
17
+ "README.md",
15
18
  "doc/EXAMPLE_01_PINGPONG",
16
19
  "doc/EXAMPLE_02_CLOCK",
17
20
  "doc/EXAMPLE_03_STOCKS",
@@ -26,7 +29,7 @@ spec = Gem::Specification.new do |s|
26
29
 
27
30
  # ruby -rpp -e' pp `git ls-files`.split("\n") '
28
31
  s.files = [
29
- "README",
32
+ "README.md",
30
33
  "Rakefile",
31
34
  "amqp.gemspec",
32
35
  "amqp.todo",
@@ -50,6 +53,7 @@ spec = Gem::Specification.new do |s|
50
53
  "examples/mq/primes.rb",
51
54
  "examples/mq/stocks.rb",
52
55
  "lib/amqp.rb",
56
+ "lib/amqp/version.rb",
53
57
  "lib/amqp/buffer.rb",
54
58
  "lib/amqp/client.rb",
55
59
  "lib/amqp/frame.rb",
@@ -57,7 +61,6 @@ spec = Gem::Specification.new do |s|
57
61
  "lib/amqp/server.rb",
58
62
  "lib/amqp/spec.rb",
59
63
  "lib/ext/blankslate.rb",
60
- "lib/ext/em.rb",
61
64
  "lib/ext/emfork.rb",
62
65
  "lib/mq.rb",
63
66
  "lib/mq/exchange.rb",
@@ -1,5 +1,7 @@
1
1
  # this is the bacon spec for AMQP client
2
2
  # you can find other specs inline in frame.rb, buffer.rb and protocol.rb
3
+ # to run just 1 test use:
4
+ # bacon lib/amqp.rb --name "should ..."
3
5
  # this one couldn't be written in line because:
4
6
  # due to the load order 'AMQP' isn't completely defined yet when Client is loaded
5
7
  require 'mocha'
@@ -14,6 +16,7 @@ describe Client do
14
16
  AMQP.instance_eval{ @closing = false }
15
17
  Client.class_eval{ @retry_count = 0 }
16
18
  Client.class_eval{ @server_to_select = 0 }
19
+ EM.instance_eval{ @next_tick_queue = nil }
17
20
  end
18
21
 
19
22
  should 'reconnect on disconnect after connection_completed (use reconnect_timer)' do
@@ -71,7 +74,7 @@ describe Client do
71
74
  end
72
75
  end
73
76
 
74
- should "use fallback servers on reconnect" do
77
+ should "use fallback servers on reconnect without connection_completed" do
75
78
  @times_connected = 0
76
79
  @connect_args = []
77
80
 
@@ -291,5 +294,24 @@ describe Client do
291
294
  @amqp_conn.should == @client
292
295
  end
293
296
 
297
+ should "send Heartbeat frames based on keepalive interval" do
298
+ @stuff_sent = []
299
+ EventMachine.stubs(:connect_server).returns(99).with do |arg1, arg2|
300
+ EM.next_tick do
301
+ @client = EM.class_eval{ @conns }[99]
302
+ @amqp_conn = AMQP.class_eval{ @conn }
303
+ @client.stubs(:send).returns(true).with do |what_to_send|
304
+ @stuff_sent << what_to_send.class
305
+ true
306
+ end
307
+ @client.connection_completed
308
+ end
309
+ true
310
+ end
311
+ EM.next_tick{ EM.add_timer(0.5){ EM.stop_event_loop } }
312
+ AMQP.start(:host => 'nonexistanthost', :keepalive => 0.2)
313
+ @stuff_sent.should == [AMQP::Frame::Heartbeat, AMQP::Frame::Heartbeat]
314
+ end
315
+
294
316
 
295
317
  end
@@ -1,16 +1,22 @@
1
- module AMQP
2
- VERSION = '0.5.9'
3
-
4
- DIR = File.expand_path(File.dirname(File.expand_path(__FILE__)))
5
- $:.unshift DIR
6
-
7
- require 'ext/em'
8
- require 'ext/blankslate'
9
-
10
- %w[ buffer spec protocol frame client ].each do |file|
11
- require "amqp/#{file}"
1
+ unless defined?(EM)
2
+ begin
3
+ require 'eventmachine'
4
+ rescue LoadError
5
+ require 'rubygems'
6
+ require 'eventmachine'
12
7
  end
8
+ end
9
+
10
+ library_root = File.expand_path("..", __FILE__)
11
+ $LOAD_PATH << library_root unless $LOAD_PATH.include?(library_root)
12
+ require 'ext/emfork'
13
+ require 'ext/blankslate'
13
14
 
15
+ %w[ version buffer spec protocol frame client ].each do |file|
16
+ require "amqp/#{file}"
17
+ end
18
+
19
+ module AMQP
14
20
  class << self
15
21
  @logging = false
16
22
  attr_accessor :logging
@@ -81,7 +87,7 @@ module AMQP
81
87
  # block. See the code examples in MQ for details.
82
88
  #
83
89
  def self.start *args, &blk
84
- EM.run{
90
+ EM.run {
85
91
  @conn ||= connect *args
86
92
  @conn.callback(&blk) if blk
87
93
  @conn
@@ -91,11 +97,11 @@ module AMQP
91
97
  class << self
92
98
  alias :run :start
93
99
  end
94
-
100
+
95
101
  def self.stop
96
102
  if @conn and not @closing
97
103
  @closing = true
98
- @conn.close{
104
+ @conn.close {
99
105
  yield if block_given?
100
106
  @conn = nil
101
107
  @closing = false
@@ -95,6 +95,12 @@ module AMQP
95
95
  @buf = Buffer.new
96
96
  send_data HEADER
97
97
  send_data [1, 1, VERSION_MAJOR, VERSION_MINOR].pack('C4')
98
+
99
+ if @settings[:keepalive]
100
+ EM.add_periodic_timer(@settings[:keepalive]) do
101
+ send Frame::Heartbeat.new
102
+ end
103
+ end
98
104
  end
99
105
 
100
106
  def connected?
@@ -121,4 +121,4 @@ if $0 =~ /bacon/ or $0 == __FILE__
121
121
  copy.should == orig
122
122
  end
123
123
  end
124
- end
124
+ end
@@ -8,9 +8,9 @@ module AMQP
8
8
  def initialize *args
9
9
  opts = args.pop if args.last.is_a? Hash
10
10
  opts ||= {}
11
-
11
+
12
12
  @debug = 1 # XXX hack, p(obj) == '' if no instance vars are set
13
-
13
+
14
14
  if args.size == 1 and args.first.is_a? Buffer
15
15
  buf = args.shift
16
16
  else
@@ -209,4 +209,4 @@ if $0 =~ /bacon/ or $0 == __FILE__
209
209
  Protocol::Header.new(orig.to_binary).should == orig
210
210
  end
211
211
  end
212
- end
212
+ end
@@ -96,4 +96,4 @@ if __FILE__ == $0
96
96
  EM.run{
97
97
  AMQP::Server.start
98
98
  }
99
- end
99
+ end
@@ -0,0 +1,10 @@
1
+ # Generally this kind of guard is a sign of a bad require, and that is
2
+ # arguably true here as well. amqp.gemspec requires this file, but later
3
+ # we want people to be able to require 'amqp/version' without getting a warning.
4
+ # On the other hand, we aren't in the load path when the gemspec is evaluated,
5
+ # so we can't use a relative require there.
6
+ unless defined?(::AMQP::VERSION)
7
+ module AMQP
8
+ VERSION = '0.6.7.1'
9
+ end
10
+ end
data/lib/mq.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  #:main: README
2
2
  #
3
3
 
4
- $:.unshift File.expand_path(File.dirname(File.expand_path(__FILE__)))
5
4
  require 'amqp'
6
5
 
7
6
  class MQ
@@ -199,7 +198,7 @@ class MQ
199
198
  end
200
199
 
201
200
  when Protocol::Queue::DeclareOk
202
- queues[ method.queue ].recieve_status method
201
+ queues[ method.queue ].receive_status method
203
202
 
204
203
  when Protocol::Basic::Deliver, Protocol::Basic::GetOk
205
204
  @method = method
@@ -230,6 +229,13 @@ class MQ
230
229
  c.channels.delete @channel
231
230
  c.close if c.channels.empty?
232
231
  }
232
+
233
+ when Protocol::Basic::ConsumeOk
234
+ if @consumer = consumers[ method.consumer_tag ]
235
+ @consumer.confirm_subscribe
236
+ else
237
+ MQ.error "Basic.ConsumeOk for invalid consumer tag: #{method.consumer_tag}"
238
+ end
233
239
  end
234
240
  end
235
241
  end
@@ -733,7 +739,22 @@ class MQ
733
739
  end
734
740
 
735
741
  def prefetch(size)
742
+ @prefetch_size = size
736
743
  send Protocol::Basic::Qos.new(:prefetch_size => 0, :prefetch_count => size, :global => false)
744
+ self
745
+ end
746
+
747
+ # Asks the broker to redeliver all unacknowledged messages on this
748
+ # channel.
749
+ #
750
+ # * requeue (default false)
751
+ # If this parameter is false, the message will be redelivered to the original recipient.
752
+ # If this flag is true, the server will attempt to requeue the message, potentially then
753
+ # delivering it to an alternative subscriber.
754
+ #
755
+ def recover requeue = false
756
+ send Protocol::Basic::Recover.new(:requeue => requeue)
757
+ self
737
758
  end
738
759
 
739
760
  # Returns a hash of all the exchange proxy objects.
@@ -786,6 +807,8 @@ class MQ
786
807
  qus = @queues
787
808
  @queues = {}
788
809
  qus.each{ |_,q| q.reset } if qus
810
+
811
+ prefetch(@prefetch_size) if @prefetch_size
789
812
  end
790
813
 
791
814
  private
@@ -820,4 +843,4 @@ class MQ
820
843
  def MQ.id
821
844
  Thread.current[:mq_id] ||= "#{`hostname`.strip}-#{Process.pid}-#{Thread.current.object_id}"
822
845
  end
823
- end
846
+ end
@@ -183,6 +183,16 @@ class MQ
183
183
  # not wait for a reply method. If the server could not complete the
184
184
  # method it will raise a channel or connection exception.
185
185
  #
186
+ # * :no_declare => true | false (default false)
187
+ # If set, the exchange will not be declared to the
188
+ # AMQP broker at instantiation-time. This allows the AMQP
189
+ # client to send messages to exchanges that were
190
+ # already declared by someone else, e.g. if the client
191
+ # does not have sufficient privilege to declare (create)
192
+ # an exchange. Use with caution, as binding to an exchange
193
+ # with the no-declare option causes your system to become
194
+ # sensitive to the ordering of clients' actions!
195
+ #
186
196
  # == Exceptions
187
197
  # Doing any of these activities are illegal and will raise MQ:Error.
188
198
  # * redeclare an already-declared exchange to a different type
@@ -194,11 +204,13 @@ class MQ
194
204
  @mq.exchanges[@name = name] ||= self
195
205
  @key = opts[:key]
196
206
 
197
- @mq.callback{
198
- @mq.send Protocol::Exchange::Declare.new({ :exchange => name,
199
- :type => type,
200
- :nowait => true }.merge(opts))
201
- } unless name == "amq.#{type}" or name == ''
207
+ unless name == "amq.#{type}" or name == '' or opts[:no_declare]
208
+ @mq.callback{
209
+ @mq.send Protocol::Exchange::Declare.new({ :exchange => name,
210
+ :type => type,
211
+ :nowait => true }.merge(opts))
212
+ }
213
+ end
202
214
  end
203
215
  attr_reader :name, :type, :key
204
216
 
@@ -247,13 +259,13 @@ class MQ
247
259
  out = []
248
260
 
249
261
  out << Protocol::Basic::Publish.new({ :exchange => name,
250
- :routing_key => opts.delete(:key) || @key }.merge(opts))
262
+ :routing_key => opts[:key] || @key }.merge(opts))
251
263
 
252
264
  data = data.to_s
253
265
 
254
266
  out << Protocol::Header.new(Protocol::Basic,
255
267
  data.length, { :content_type => 'application/octet-stream',
256
- :delivery_mode => (opts.delete(:persistent) ? 2 : 1),
268
+ :delivery_mode => (opts[:persistent] ? 2 : 1),
257
269
  :priority => 0 }.merge(opts))
258
270
 
259
271
  out << Frame::Body.new(data)
@@ -113,7 +113,7 @@ class MQ
113
113
  @mq.callback{
114
114
  @mq.send Protocol::Queue::Bind.new({ :queue => name,
115
115
  :exchange => exchange,
116
- :routing_key => opts.delete(:key),
116
+ :routing_key => opts[:key],
117
117
  :nowait => true }.merge(opts))
118
118
  }
119
119
  self
@@ -140,7 +140,7 @@ class MQ
140
140
  @mq.callback{
141
141
  @mq.send Protocol::Queue::Unbind.new({ :queue => name,
142
142
  :exchange => exchange,
143
- :routing_key => opts.delete(:key),
143
+ :routing_key => opts[:key],
144
144
  :nowait => true }.merge(opts))
145
145
  }
146
146
  self
@@ -175,6 +175,16 @@ class MQ
175
175
  nil
176
176
  end
177
177
 
178
+ # Purge all messages from the queue.
179
+ #
180
+ def purge opts = {}
181
+ @mq.callback{
182
+ @mq.send Protocol::Queue::Purge.new({ :queue => name,
183
+ :nowait => true }.merge(opts))
184
+ }
185
+ nil
186
+ end
187
+
178
188
  # This method provides a direct access to the messages in a queue
179
189
  # using a synchronous dialogue that is designed for specific types of
180
190
  # application where synchronous functionality is more important than
@@ -240,7 +250,7 @@ class MQ
240
250
  q.push(self)
241
251
  @mq.send Protocol::Basic::Get.new({ :queue => name,
242
252
  :consumer_tag => name,
243
- :no_ack => !opts.delete(:ack),
253
+ :no_ack => !opts[:ack],
244
254
  :nowait => true }.merge(opts))
245
255
  }
246
256
  }
@@ -296,6 +306,12 @@ class MQ
296
306
  # not wait for a reply method. If the server could not complete the
297
307
  # method it will raise a channel or connection exception.
298
308
  #
309
+ # * :confirm => proc (default nil)
310
+ # If set, this proc will be called when the server confirms subscription
311
+ # to the queue with a ConsumeOk message. Setting this option will
312
+ # automatically set :nowait => false. This is required for the server
313
+ # to send a confirmation.
314
+ #
299
315
  def subscribe opts = {}, &blk
300
316
  @consumer_tag = "#{name}-#{Kernel.rand(999_999_999_999)}"
301
317
  @mq.consumers[@consumer_tag] = self
@@ -304,11 +320,12 @@ class MQ
304
320
 
305
321
  @on_msg = blk
306
322
  @on_msg_opts = opts
323
+ opts[:nowait] = false if (@on_confirm_subscribe = opts[:confirm])
307
324
 
308
325
  @mq.callback{
309
326
  @mq.send Protocol::Basic::Consume.new({ :queue => name,
310
327
  :consumer_tag => @consumer_tag,
311
- :no_ack => !opts.delete(:ack),
328
+ :no_ack => !opts[:ack],
312
329
  :nowait => true }.merge(opts))
313
330
  }
314
331
  self
@@ -336,7 +353,6 @@ class MQ
336
353
  # method it will raise a channel or connection exception.
337
354
  #
338
355
  def unsubscribe opts = {}, &blk
339
- @on_msg = nil
340
356
  @on_cancel = blk
341
357
  @mq.callback{
342
358
  @mq.send Protocol::Basic::Cancel.new({ :consumer_tag => @consumer_tag }.merge(opts))
@@ -391,7 +407,7 @@ class MQ
391
407
  self
392
408
  end
393
409
 
394
- def recieve_status declare_ok
410
+ def receive_status declare_ok
395
411
  if @on_status
396
412
  m, c = declare_ok.message_count, declare_ok.consumer_count
397
413
  @on_status.call *(@on_status.arity == 1 ? [m] : [m, c])
@@ -399,10 +415,16 @@ class MQ
399
415
  end
400
416
  end
401
417
 
418
+ def confirm_subscribe
419
+ @on_confirm_subscribe.call if @on_confirm_subscribe
420
+ @on_confirm_subscribe = nil
421
+ end
422
+
402
423
  def cancelled
403
424
  @on_cancel.call if @on_cancel
404
425
  @on_cancel = @on_msg = nil
405
426
  @mq.consumers.delete @consumer_tag
427
+ @mq.queues.delete(@name) if @opts[:auto_delete]
406
428
  @consumer_tag = nil
407
429
  end
408
430
 
@@ -30,14 +30,14 @@ class MQ
30
30
  #
31
31
  # Marshalling and unmarshalling the objects is handled internally. This
32
32
  # marshalling is subject to the same restrictions as defined in the
33
- # Marshal[http://ruby-doc.org/core/classes/Marshal.html] standard
33
+ # Marshal[http://ruby-doc.org/core/classes/Marshal.html] standard
34
34
  # library. See that documentation for further reference.
35
35
  #
36
- # When the optional object is not passed, the returned rpc reference is
37
- # used to send messages and arguments to the queue. See #method_missing
38
- # which does all of the heavy lifting with the proxy. Some client
39
- # elsewhere must call this method *with* the optional block so that
40
- # there is a valid destination. Failure to do so will just enqueue
36
+ # When the optional object is not passed, the returned rpc reference is
37
+ # used to send messages and arguments to the queue. See #method_missing
38
+ # which does all of the heavy lifting with the proxy. Some client
39
+ # elsewhere must call this method *with* the optional block so that
40
+ # there is a valid destination. Failure to do so will just enqueue
41
41
  # marshalled messages that are never consumed.
42
42
  #
43
43
  def initialize mq, queue, obj = nil
@@ -53,7 +53,7 @@ class MQ
53
53
  else
54
54
  obj
55
55
  end
56
-
56
+
57
57
  @mq.queue(queue).subscribe(:ack=>true){ |info, request|
58
58
  method, *args = ::Marshal.load(request)
59
59
  ret = @obj.__send__(method, *args)
@@ -67,7 +67,7 @@ class MQ
67
67
  else
68
68
  @callbacks ||= {}
69
69
  # XXX implement and use queue(nil)
70
- @queue = @mq.queue(@name = "random identifier #{::Kernel.rand(999_999_999_999)}").subscribe{|info, msg|
70
+ @queue = @mq.queue(@name = "random identifier #{::Kernel.rand(999_999_999_999)}", :auto_delete => true).subscribe{|info, msg|
71
71
  if blk = @callbacks.delete(info.message_id)
72
72
  blk.call ::Marshal.load(msg)
73
73
  end
@@ -97,4 +97,4 @@ class MQ
97
97
  @remote.publish(::Marshal.dump([meth, *args]), :reply_to => blk ? @name : nil, :message_id => message_id)
98
98
  end
99
99
  end
100
- end
100
+ end
metadata CHANGED
@@ -1,35 +1,49 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brontes3d-amqp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.4.3
4
+ hash: 97
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 6
9
+ - 7
10
+ - 1
11
+ version: 0.6.7.1
5
12
  platform: ruby
6
13
  authors:
7
14
  - Aman Gupta
15
+ - Jacob Burkhart
8
16
  autorequire:
9
17
  bindir: bin
10
18
  cert_chain: []
11
19
 
12
- date: 2009-01-09 00:00:00 -08:00
20
+ date: 2010-06-04 00:00:00 -04:00
13
21
  default_executable:
14
22
  dependencies:
15
23
  - !ruby/object:Gem::Dependency
16
24
  name: eventmachine
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
20
28
  requirements:
21
29
  - - ">="
22
30
  - !ruby/object:Gem::Version
31
+ hash: 39
32
+ segments:
33
+ - 0
34
+ - 12
35
+ - 4
23
36
  version: 0.12.4
24
- version:
25
- description: AMQP client implementation in Ruby/EventMachine
26
- email: amqp@tmm1.net
37
+ type: :runtime
38
+ version_requirements: *id001
39
+ description: An implementation of the AMQP protocol in Ruby/EventMachine for writing clients to the RabbitMQ message broker
40
+ email: jacob@brontes3d.com
27
41
  executables: []
28
42
 
29
43
  extensions: []
30
44
 
31
45
  extra_rdoc_files:
32
- - README
46
+ - README.md
33
47
  - doc/EXAMPLE_01_PINGPONG
34
48
  - doc/EXAMPLE_02_CLOCK
35
49
  - doc/EXAMPLE_03_STOCKS
@@ -38,7 +52,7 @@ extra_rdoc_files:
38
52
  - doc/EXAMPLE_05_POP
39
53
  - doc/EXAMPLE_06_HASHTABLE
40
54
  files:
41
- - README
55
+ - README.md
42
56
  - Rakefile
43
57
  - amqp.gemspec
44
58
  - amqp.todo
@@ -62,6 +76,7 @@ files:
62
76
  - examples/mq/primes.rb
63
77
  - examples/mq/stocks.rb
64
78
  - lib/amqp.rb
79
+ - lib/amqp/version.rb
65
80
  - lib/amqp/buffer.rb
66
81
  - lib/amqp/client.rb
67
82
  - lib/amqp/frame.rb
@@ -69,7 +84,6 @@ files:
69
84
  - lib/amqp/server.rb
70
85
  - lib/amqp/spec.rb
71
86
  - lib/ext/blankslate.rb
72
- - lib/ext/em.rb
73
87
  - lib/ext/emfork.rb
74
88
  - lib/mq.rb
75
89
  - lib/mq/exchange.rb
@@ -93,30 +107,38 @@ files:
93
107
  - research/primes-threaded.rb
94
108
  - bacon/client.rb
95
109
  has_rdoc: true
96
- homepage: http://amqp.rubyforge.org/
110
+ homepage: http://github.com/brontes3d/amqp
111
+ licenses: []
112
+
97
113
  post_install_message:
98
114
  rdoc_options:
99
115
  - --include=examples
100
116
  require_paths:
101
117
  - lib
102
118
  required_ruby_version: !ruby/object:Gem::Requirement
119
+ none: false
103
120
  requirements:
104
121
  - - ">="
105
122
  - !ruby/object:Gem::Version
123
+ hash: 3
124
+ segments:
125
+ - 0
106
126
  version: "0"
107
- version:
108
127
  required_rubygems_version: !ruby/object:Gem::Requirement
128
+ none: false
109
129
  requirements:
110
130
  - - ">="
111
131
  - !ruby/object:Gem::Version
132
+ hash: 3
133
+ segments:
134
+ - 0
112
135
  version: "0"
113
- version:
114
136
  requirements: []
115
137
 
116
- rubyforge_project:
117
- rubygems_version: 1.2.0
138
+ rubyforge_project: amqp
139
+ rubygems_version: 1.3.7
118
140
  signing_key:
119
- specification_version: 2
141
+ specification_version: 3
120
142
  summary: AMQP client implementation in Ruby/EventMachine
121
143
  test_files: []
122
144
 
data/README DELETED
@@ -1,128 +0,0 @@
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
9
-
10
- This library works with Ruby 1.8, Ruby 1.9 and JRuby.
11
-
12
- This library was tested primarily with RabbitMQ, although it should be compatible with any
13
- server implementing the AMQP 0-8 spec.
14
-
15
- To use with RabbitMQ, first run the server:
16
-
17
- hg clone http://hg.rabbitmq.com/rabbitmq-codegen
18
- hg clone http://hg.rabbitmq.com/rabbitmq-server
19
- cd rabbitmq-server
20
- make run
21
-
22
- To get started, refer to the various bundled examples:
23
-
24
- ruby examples/mq/pingpong.rb # 1-1 communication using amq.direct
25
- ruby examples/mq/clock.rb # 1-N communication using amq.fanout
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
-
32
- ruby examples/mq/hashtable.rb # simple async rpc layer
33
- ruby examples/mq/primes.rb 4 # parallelized prime number generation
34
- ruby examples/mq/logger.rb # simple logging api
35
-
36
- For more details into the lower level AMQP client API, run the simple client example:
37
-
38
- ruby examples/amqp/simple.rb # low-level AMQP api
39
- ruby examples/mq/internal.rb # low-level Queue/Exchange api
40
-
41
- Or refer to protocol/doc.txt, which enumerates packets sent between a server and client
42
- during a typical session, in both binary and decoded formats.
43
-
44
- To run the test suite:
45
-
46
- rake spec
47
-
48
- The lib/amqp/spec.rb file is generated automatically based on the AMQP specification. To generate it:
49
-
50
- rake codegen
51
-
52
- This project was inspired by py-amqplib, rabbitmq, qpid and rubbyt.
53
- Special thanks to Dmitriy Samovskiy, Ben Hood and Tony Garnock-Jones.
54
-
55
- AMQP resources:
56
-
57
- Servers:
58
- RabbitMQ (Rabbit Technologies, Erlang/OTP, MPL) - http://rabbitmq.com
59
- ZeroMQ (iMatix/FastMQ/Intel, C++, GPL3) - http://www.zeromq.org
60
- OpenAMQ (iMatix, C, GPL2) - http://openamq.org
61
- ActiveMQ (Apache Foundation, Java, apache2) - http://activemq.apache.org
62
-
63
- Steve Vinoski explains AMQP in his column, Towards Integration
64
- http://steve.vinoski.net/pdf/IEEE-Advanced_Message_Queuing_Protocol.pdf
65
-
66
- John O'Hara on the history of AMQP
67
- http://www.acmqueue.org/modules.php?name=Content&pa=showpage&pid=485
68
-
69
- Dmitriy's presentation on RabbitMQ/AMQP
70
- http://somic-org.homelinux.org/blog/2008/07/31/slides-for-my-amqprabbitmq-talk/
71
-
72
- ZeroMQ's analysis of the messaging technology market
73
- http://www.zeromq.org/whitepapers:market-analysis
74
-
75
- Pieter Hintjens's background to AMQP
76
- http://www.openamq.org/doc:amqp-background
77
-
78
- Barry Pederson's py-amqplib
79
- http://barryp.org/software/py-amqplib/
80
-
81
- Ben Hood on writing an AMQP client
82
- http://hopper.squarespace.com/blog/2008/6/21/build-your-own-amqp-client.html
83
-
84
- Dmitriy Samovskiy introduces Ruby + QPid + RabbitMQ
85
- http://somic-org.homelinux.org/blog/2008/06/24/ruby-amqp-rabbitmq-example/
86
-
87
- Ben Hood's as3-amqp
88
- http://github.com/0x6e6562/as3-amqp
89
- http://hopper.squarespace.com/blog/2008/7/4/server-side-as3.html
90
- http://hopper.squarespace.com/blog/2008/3/24/as3-amqp-client-first-cut.html
91
-
92
- RabbitMQ's protocol code generator
93
- http://hg.rabbitmq.com/rabbitmq-codegen/
94
-
95
- Erlang Exchange presentation on the implementation of RabbitMQ
96
- http://skillsmatter.com/podcast/erlang/presenting-rabbitmq-an-erlang-based-implementatio-nof-amqp
97
- http://www.lshift.net/blog/2008/07/01/slides-from-our-erlang-exchange-talk
98
-
99
- Jonathan Conway's series on RabbitMQ and using it with Ruby/Merb
100
- http://jaikoo.com/2008/3/20/daemonize-rabbitmq
101
- http://jaikoo.com/2008/3/14/oh-hai-rabbitmq
102
- http://jaikoo.com/2008/2/29/friday-round-up-2008-02-29
103
- http://jaikoo.com/2007/9/4/didn-t-you-get-the-memo
104
-
105
- Open Enterprise's series on messaging middleware and AMQP
106
- http://www1.interopsystems.com/analysis/can-amqp-break-ibms-mom-monopoly-part-1.html
107
- http://www1.interopsystems.com/analysis/can-amqp-break-ibms-mom-monopoly-part-2.html
108
- http://www1.interopsystems.com/analysis/can-amqp-break-ibms-mom-monopoly-part-3.html
109
-
110
- Messaging and distributed systems resources:
111
-
112
- A Critique of the Remote Procedure Call Paradigm
113
- http://www.cs.vu.nl/~ast/publications/euteco-1988.pdf
114
-
115
- A Note on Distributed Computing
116
- http://research.sun.com/techrep/1994/smli_tr-94-29.pdf
117
-
118
- Convenience Over Correctness
119
- http://steve.vinoski.net/pdf/IEEE-Convenience_Over_Correctness.pdf
120
-
121
- Metaprotocol Taxonomy and Communications Patterns
122
- http://hessian.caucho.com/doc/metaprotocol-taxonomy.xtp
123
-
124
- Joe Armstrong on Erlang messaging vs RPC
125
- http://armstrongonsoftware.blogspot.com/2008/05/road-we-didnt-go-down.html
126
-
127
- SEDA: scalable internet services using message queues
128
- http://www.eecs.harvard.edu/~mdw/papers/seda-sosp01.pdf
@@ -1,51 +0,0 @@
1
- begin
2
- require 'eventmachine'
3
- rescue LoadError
4
- require 'rubygems'
5
- require 'eventmachine'
6
- end
7
-
8
- #:stopdoc:
9
-
10
- if EM::VERSION < '0.12.2'
11
-
12
- def EventMachine::run blk=nil, tail=nil, &block
13
- @tails ||= []
14
- tail and @tails.unshift(tail)
15
-
16
- if reactor_running?
17
- (b = blk || block) and b.call # next_tick(b)
18
- else
19
- @conns = {}
20
- @acceptors = {}
21
- @timers = {}
22
- begin
23
- @reactor_running = true
24
- initialize_event_machine
25
- (b = blk || block) and add_timer(0, b)
26
- run_machine
27
- ensure
28
- release_machine
29
- @reactor_running = false
30
- end
31
-
32
- until @tails.empty?
33
- @tails.pop.call
34
- end
35
- end
36
- end
37
-
38
- def EventMachine::fork_reactor &block
39
- Kernel.fork do
40
- if self.reactor_running?
41
- self.stop_event_loop
42
- self.release_machine
43
- self.instance_variable_set( '@reactor_running', false )
44
- end
45
- self.run block
46
- end
47
- end
48
-
49
- end
50
-
51
- require 'ext/emfork'