brontes3d-amqp 0.6.4.3 → 0.6.7.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.
@@ -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'