amqp 1.2.1 → 1.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8f2f4d10362c5c533ba2d5b430626abb8e1eaa98
4
- data.tar.gz: f80eecaca4102e7c3c0a2ff7522a2d090ddb23f4
3
+ metadata.gz: c7cd9670c82561f472831d5844d8aedf21704384
4
+ data.tar.gz: 72de0158e4620a8c11468fa6ae141770f5eb5c40
5
5
  SHA512:
6
- metadata.gz: 0499db6a9bcf66885c76c95824a913571e2833e88fedf6d2b659ca01b3c21c52d30f3fb779eada43918bff9d5b0dbe705f29cc9ff11a32643cf6a592ccca996e
7
- data.tar.gz: 58bc2ac9aa9412196ab37aaea1c3f968fdf76b8f5ff1bfa430ceec516cc04ed473b4e01dd8ef353184c055d05c5d37ebe80354f91f9d60d663895eec83a16b3f
6
+ metadata.gz: 0590210e5493862466fc7c5bfaae3322f4fcd4c738f57eba25e811d4d76205b51b6bf327c44941f59a6b93a24436d6961baaafefeaf64c88b378a7faa6a24dba
7
+ data.tar.gz: b579abed8e4432158e908dd6d4e992c17e815029b89b3ccb6b0a7b15483eb2bb21a7dc49df7fe389e4d9adc04660b19d0dd8ef620a15578d880b18181932cfa9
data/ChangeLog.md CHANGED
@@ -1,4 +1,26 @@
1
- ## Changes Between 1.2.0 and 1.2.1
1
+ ## Changes Between 1.2.x and 1.3.0
2
+
3
+ ### Exchange-to-Exchange Bindings Support
4
+
5
+ amqp gem now supports [Exchange-to-Exchange Bindings](http://www.rabbitmq.com/e2e.html), a RabbitMQ
6
+ extension.
7
+
8
+ `AMQP::Exchange#bind` and `AMQP::Exchange#unbind` work very much like `AMQP::Queue#bind` and
9
+ `AMQP::Queue#unbind`, with the argument exchange being the source one.
10
+
11
+ Contributed by Stefan Kaes.
12
+
13
+ ### Internal Exchange Declaration
14
+
15
+ amqp gem now supports declaration of internal exchanges
16
+ (used via exchange-to-exchange bindings, cannot be published to
17
+ by clients).
18
+
19
+ To declare an exchange as internal, add `:internal => true` to
20
+ declaration options.
21
+
22
+ Contributed by Stefan Kaes.
23
+
2
24
 
3
25
  ### Initial Connection Failures Retries
4
26
 
@@ -7,7 +29,6 @@ means connection retries succeed.
7
29
 
8
30
  Contributed by Marius Hanne.
9
31
 
10
-
11
32
  ## Changes Between 1.1.0 and 1.2.0
12
33
 
13
34
  ### [Authentication Failure Notification](http://www.rabbitmq.com/auth-notification.html) Support
@@ -53,10 +74,6 @@ very short lived channels.
53
74
  `ConnectionClosedError` from `amq-client` is now defined again.
54
75
 
55
76
 
56
- ### amq-protocol Update
57
-
58
- Minimum `amq-protocol` version is now `1.9.0`.
59
-
60
77
  ### Fixed Exceptions in AMQP::Exchange#handle_declare_ok
61
78
 
62
79
  `AMQP::Exchange#handle_declare_ok` no longer raises an exception
data/lib/amqp/channel.rb CHANGED
@@ -172,7 +172,7 @@ module AMQP
172
172
 
173
173
  attr_reader :id
174
174
 
175
- attr_reader :exchanges_awaiting_declare_ok, :exchanges_awaiting_delete_ok
175
+ attr_reader :exchanges_awaiting_declare_ok, :exchanges_awaiting_delete_ok, :exchanges_awaiting_bind_ok, :exchanges_awaiting_unbind_ok
176
176
  attr_reader :queues_awaiting_declare_ok, :queues_awaiting_delete_ok, :queues_awaiting_bind_ok, :queues_awaiting_unbind_ok, :queues_awaiting_purge_ok, :queues_awaiting_get_response
177
177
  attr_reader :consumers_awaiting_consume_ok, :consumers_awaiting_cancel_ok
178
178
 
@@ -1424,6 +1424,8 @@ module AMQP
1424
1424
 
1425
1425
  @queues_awaiting_declare_ok = Array.new
1426
1426
  @exchanges_awaiting_declare_ok = Array.new
1427
+ @exchanges_awaiting_bind_ok = Array.new
1428
+ @exchanges_awaiting_unbind_ok = Array.new
1427
1429
 
1428
1430
  @queues_awaiting_delete_ok = Array.new
1429
1431
 
data/lib/amqp/exchange.rb CHANGED
@@ -365,9 +365,9 @@ module AMQP
365
365
  end
366
366
  end
367
367
 
368
- self.exchange_declare(passive = @opts[:passive], durable = @opts[:durable], auto_delete = @opts[:auto_delete], nowait = @opts[:nowait], @opts[:arguments], &shim)
368
+ self.exchange_declare(@opts[:passive], @opts[:durable], @opts[:auto_delete], @opts[:internal], @opts[:nowait], @opts[:arguments], &shim)
369
369
  else
370
- self.exchange_declare(passive = @opts[:passive], durable = @opts[:durable], auto_delete = @opts[:auto_delete], nowait = @opts[:nowait], @opts[:arguments])
370
+ self.exchange_declare(@opts[:passive], @opts[:durable], @opts[:auto_delete], @opts[:internal], @opts[:nowait], @opts[:arguments])
371
371
  end
372
372
  end
373
373
  end
@@ -422,6 +422,10 @@ module AMQP
422
422
  @name && ((@name == AMQ::Protocol::EMPTY_STRING) || !!(@name =~ /^amq\.(direct|fanout|topic|headers|match)/i))
423
423
  end # predefined?
424
424
 
425
+ # @return [Boolean] true if this exchange is an internal exchange
426
+ def internal?
427
+ @opts[:internal]
428
+ end
425
429
 
426
430
  # Publishes message to the exchange. The message will be routed to queues by the exchange
427
431
  # and distributed to any active consumers. Routing logic is determined by exchange type and
@@ -604,14 +608,15 @@ module AMQP
604
608
  # @group Declaration
605
609
 
606
610
  # @api public
607
- def exchange_declare(passive = false, durable = false, auto_delete = false, nowait = false, arguments = nil, &block)
611
+ def exchange_declare(passive = false, durable = false, auto_delete = false, internal = false, nowait = false, arguments = nil, &block)
608
612
  # for re-declaration
609
613
  @passive = passive
610
614
  @durable = durable
611
615
  @auto_delete = auto_delete
612
616
  @arguments = arguments
617
+ @internal = internal
613
618
 
614
- @connection.send_frame(AMQ::Protocol::Exchange::Declare.encode(@channel.id, @name, @type.to_s, passive, durable, auto_delete, false, nowait, arguments))
619
+ @connection.send_frame(AMQ::Protocol::Exchange::Declare.encode(@channel.id, @name, @type.to_s, passive, durable, auto_delete, internal, nowait, arguments))
615
620
 
616
621
  unless nowait
617
622
  self.define_callback(:declare, &block)
@@ -625,7 +630,7 @@ module AMQP
625
630
  # @api public
626
631
  def redeclare(&block)
627
632
  nowait = block.nil?
628
- @connection.send_frame(AMQ::Protocol::Exchange::Declare.encode(@channel.id, @name, @type.to_s, @passive, @durable, @auto_delete, false, nowait, @arguments))
633
+ @connection.send_frame(AMQ::Protocol::Exchange::Declare.encode(@channel.id, @name, @type.to_s, @passive, @durable, @auto_delete, @internal, nowait, @arguments))
629
634
 
630
635
  unless nowait
631
636
  self.define_callback(:declare, &block)
@@ -653,6 +658,111 @@ module AMQP
653
658
  end # delete(if_unused = false, nowait = false)
654
659
 
655
660
 
661
+ # @group Exchange to Exchange Bindings
662
+
663
+ # This method binds a source exchange to a destination exchange. Messages
664
+ # sent to the source exchange are forwarded to the destination exchange, provided
665
+ # the message routing key matches the routing key specified when binding the
666
+ # exchanges.
667
+ #
668
+ # A valid exchange name (or reference) must be passed as the first
669
+ # parameter.
670
+ # @example Binding two source exchanges to a destination exchange
671
+ #
672
+ # ch = AMQP::Channel.new(connection)
673
+ # source1 = ch.fanout('backlog-events-datacenter-1')
674
+ # source2 = ch.fanout('backlog-events-datacenter-2')
675
+ # destination = ch.fanout('baklog-events')
676
+ # destination.bind(source1).bind(source2)
677
+ #
678
+ #
679
+ # @param [Exchange] Exchange to bind to. May also be a string or any object that responds to #name.
680
+ #
681
+ # @option opts [String] :routing_key Specifies the routing key for the binding. The routing key is
682
+ # used for routing messages depending on the exchange configuration.
683
+ # Not all exchanges use a routing key! Refer to the specific
684
+ # exchange documentation.
685
+ #
686
+ # @option opts [Hash] :arguments (nil) A hash of optional arguments with the declaration. Headers exchange type uses these metadata
687
+ # attributes for routing matching.
688
+ # In addition, brokers may implement AMQP extensions using x-prefixed declaration arguments.
689
+ #
690
+ # @option opts [Boolean] :nowait (true) If set, the server will not respond to the method. The client should
691
+ # not wait for a reply method. If the server could not complete the
692
+ # method it will raise a channel or connection exception.
693
+ # @return [Exchange] Self
694
+ #
695
+ #
696
+ # @yield [] Since exchange.bind-ok carries no attributes, no parameters are yielded to the block.
697
+ #
698
+
699
+ # @api public
700
+ def bind(source, opts = {}, &block)
701
+ source = source.name if source.respond_to?(:name)
702
+ routing_key = opts[:key] || opts[:routing_key] || AMQ::Protocol::EMPTY_STRING
703
+ arguments = opts[:arguments] || {}
704
+ nowait = opts[:nowait] || block.nil?
705
+ @channel.once_open do
706
+ @connection.send_frame(AMQ::Protocol::Exchange::Bind.encode(@channel.id, @name, source, routing_key, nowait, arguments))
707
+ unless nowait
708
+ self.define_callback(:bind, &block)
709
+ @channel.exchanges_awaiting_bind_ok.push(self)
710
+ end
711
+ end
712
+ self
713
+ end
714
+
715
+ # This method unbinds a source exchange from a previously bound destination exchange.
716
+ #
717
+ # A valid exchange name (or reference) must be passed as the first
718
+ # parameter.
719
+ # @example Binding and unbinding two exchanges
720
+ #
721
+ # ch = AMQP::Channel.new(connection)
722
+ # source = ch.fanout('backlog-events')
723
+ # destination = ch.fanout('backlog-events-copy')
724
+ # destination.bind(source)
725
+ # ...
726
+ # destination.unbind(source)
727
+ #
728
+ #
729
+ # @param [Exchange] Exchange to bind to. May also be a string or any object that responds to #name.
730
+ #
731
+ # @option opts [String] :routing_key Specifies the routing key for the binding. The routing key is
732
+ # used for routing messages depending on the exchange configuration.
733
+ # Not all exchanges use a routing key! Refer to the specific
734
+ # exchange documentation.
735
+ #
736
+ # @option opts [Hash] :arguments (nil) A hash of optional arguments with the declaration. Headers exchange type uses these metadata
737
+ # attributes for routing matching.
738
+ # In addition, brokers may implement AMQP extensions using x-prefixed declaration arguments.
739
+ #
740
+ # @option opts [Boolean] :nowait (true) If set, the server will not respond to the method. The client should
741
+ # not wait for a reply method. If the server could not complete the
742
+ # method it will raise a channel or connection exception.
743
+ # @return [Exchange] Self
744
+ #
745
+ #
746
+ # @yield [] Since exchange.unbind-ok carries no attributes, no parameters are yielded to the block.
747
+ #
748
+
749
+ # @api public
750
+ def unbind(source, opts = {}, &block)
751
+ source = source.name if source.respond_to?(:name)
752
+ routing_key = opts[:key] || opts[:routing_key] || AMQ::Protocol::EMPTY_STRING
753
+ arguments = opts[:arguments] || {}
754
+ nowait = opts[:nowait] || block.nil?
755
+ @channel.once_open do
756
+ @connection.send_frame(AMQ::Protocol::Exchange::Unbind.encode(@channel.id, @name, source, routing_key, nowait, arguments))
757
+ unless nowait
758
+ self.define_callback(:unbind, &block)
759
+ @channel.exchanges_awaiting_unbind_ok.push(self)
760
+ end
761
+ end
762
+ self
763
+ end
764
+
765
+ # @endgroup
656
766
 
657
767
  # @group Publishing Messages
658
768
 
@@ -750,10 +860,17 @@ module AMQP
750
860
  self.exec_callback_once_yielding_self(:declare, method)
751
861
  end
752
862
 
863
+ def handle_bind_ok(method)
864
+ self.exec_callback_once(:bind, method)
865
+ end
866
+
867
+ def handle_unbind_ok(method)
868
+ self.exec_callback_once(:unbind, method)
869
+ end
870
+
753
871
  def handle_delete_ok(method)
754
872
  self.exec_callback_once(:delete, method)
755
- end # handle_delete_ok(method)
756
-
873
+ end
757
874
 
758
875
 
759
876
  self.handle(AMQ::Protocol::Exchange::DeclareOk) do |connection, frame|
@@ -764,6 +881,21 @@ module AMQP
764
881
  exchange.handle_declare_ok(method)
765
882
  end # handle
766
883
 
884
+ self.handle(AMQ::Protocol::Exchange::BindOk) do |connection, frame|
885
+ method = frame.decode_payload
886
+ channel = connection.channels[frame.channel]
887
+ exchange = channel.exchanges_awaiting_bind_ok.shift
888
+
889
+ exchange.handle_bind_ok(method)
890
+ end # handle
891
+
892
+ self.handle(AMQ::Protocol::Exchange::UnbindOk) do |connection, frame|
893
+ method = frame.decode_payload
894
+ channel = connection.channels[frame.channel]
895
+ exchange = channel.exchanges_awaiting_unbind_ok.shift
896
+
897
+ exchange.handle_unbind_ok(method)
898
+ end # handle
767
899
 
768
900
  self.handle(AMQ::Protocol::Exchange::DeleteOk) do |connection, frame|
769
901
  channel = connection.channels[frame.channel]
@@ -789,7 +921,7 @@ module AMQP
789
921
 
790
922
  # @private
791
923
  def self.add_default_options(type, name, opts, block)
792
- { :exchange => name, :type => type, :nowait => block.nil? }.merge(opts)
924
+ { :exchange => name, :type => type, :nowait => block.nil?, :internal => false }.merge(opts)
793
925
  end
794
926
  end # Exchange
795
927
  end # AMQP
data/lib/amqp/version.rb CHANGED
@@ -6,5 +6,5 @@ module AMQP
6
6
  #
7
7
  # @see AMQ::Protocol::VERSION
8
8
  # @return [String] AMQP gem version
9
- VERSION = '1.2.1'
9
+ VERSION = '1.3.0'
10
10
  end
@@ -472,6 +472,28 @@ describe AMQP::Channel do
472
472
  end # it
473
473
  end # context
474
474
 
475
+ context "when exchange is declared with or without :internal parameter" do
476
+ it "should create a public exchange by default" do
477
+ exchange = @channel.topic("a new public topic exchange")
478
+
479
+ exchange.should_not be_internal
480
+ done
481
+ end # it
482
+
483
+ it "should create a public exchange when :internal is false" do
484
+ exchange = @channel.topic("a new-public topic exchange", :internal => false)
485
+
486
+ exchange.should_not be_internal
487
+ done
488
+ end # it
489
+
490
+ it "should create an internal exchange when :internal is true" do
491
+ exchange = @channel.topic("a new internal topic exchange", :internal => true)
492
+
493
+ exchange.should be_internal
494
+ done
495
+ end # it
496
+ end # context
475
497
 
476
498
  context "when exchange is re-declared with parameters different from the original declaration" do
477
499
  amqp_after do
@@ -0,0 +1,124 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe AMQP::Channel do
6
+
7
+ #
8
+ # Environment
9
+ #
10
+
11
+ include EventedSpec::AMQPSpec
12
+
13
+ default_options AMQP_OPTS
14
+ default_timeout 2
15
+
16
+
17
+ amqp_before do
18
+ @channel = AMQP::Channel.new
19
+ end
20
+
21
+ #
22
+ # Examples
23
+ #
24
+
25
+ describe "exchange to exchange bindings" do
26
+ context "basic properties" do
27
+ it "bind returns self" do
28
+ source1 = @channel.fanout("fanout-exchange-source-1")
29
+ source2 = @channel.fanout("fanout-exchange-source-2")
30
+ destination = @channel.fanout("fanout-exchange-destination-multi")
31
+ destination.bind(source1).bind(source2).should == destination
32
+ done
33
+ end
34
+
35
+ it "bind can work with strings for source exchange parameter" do
36
+ @channel.fanout("fanout-exchange-source-3")
37
+ destination = @channel.fanout("fanout-exchange-destination-multi-2")
38
+ destination.bind('fanout-exchange-source-3').should == destination
39
+ done
40
+ end
41
+ end
42
+
43
+ context "fanout exchanges" do
44
+ it "are bindable and forward messages" do
45
+ source = @channel.fanout("fanout-exchange-source")
46
+ destination = @channel.fanout("fanout-exchange-destination")
47
+ messages = []
48
+ destination.bind(source) do
49
+ queue = @channel.queue("fanout-forwarding", :auto_delete => true)
50
+ queue.subscribe do |metadata, payload|
51
+ messages << payload
52
+ end
53
+ queue.bind(destination) do
54
+ source.publish("x")
55
+ end
56
+ end
57
+ done(0.1) { messages.should == ["x"] }
58
+ end
59
+
60
+ it "can be unbound" do
61
+ source = @channel.fanout("fanout-exchange-source-2")
62
+ destination = @channel.fanout("fanout-exchange-destination-2")
63
+ destination.bind(source) do
64
+ destination.unbind(source) do
65
+ done
66
+ end
67
+ end
68
+ end
69
+
70
+ it "can be unbound without callbacks" do
71
+ source = @channel.fanout("fanout-exchange-source-2")
72
+ destination = @channel.fanout("fanout-exchange-destination-2")
73
+ destination.bind(source)
74
+ destination.unbind(source)
75
+ done
76
+ end
77
+
78
+ it "using :nowait => true should not call a passed in block" do
79
+ source = @channel.fanout("fanout-exchange-source-no-wait")
80
+ destination = @channel.fanout("fanout-exchange-destination-no-wait")
81
+ callback_called = false
82
+ destination.bind(source, :nowait => true) do
83
+ callback_called = true
84
+ end
85
+ done(0.1) { callback_called.should be_false}
86
+ end
87
+
88
+ end #context
89
+
90
+ context "topic exchanges" do
91
+ it "using routing key '#'" do
92
+ source = @channel.topic("topic-exchange-source")
93
+ destination = @channel.topic("topic-exchange-destination")
94
+ messages = []
95
+ destination.bind(source) do
96
+ queue = @channel.queue("ex-to-ex-default-key", :auto_delete => true)
97
+ queue.subscribe do |metadata, payload|
98
+ messages << payload
99
+ end
100
+ queue.bind(destination, :routing_key => "#") do
101
+ source.publish("a", :routing_key => "lalalala")
102
+ end
103
+ end
104
+ done(0.1) { messages.should == ["a"] }
105
+ end
106
+
107
+ it "using routing key 'foo'" do
108
+ source = @channel.topic("topic-exchange-source-foo")
109
+ destination = @channel.topic("topic-exchange-destination-foo")
110
+ messages = []
111
+ destination.bind(source, :routing_key => 'foo') do
112
+ queue = @channel.queue("foo-foo", :auto_delete => true)
113
+ queue.subscribe do |metadata, payload|
114
+ messages << payload
115
+ end
116
+ queue.bind(destination, :routing_key => "foo") do
117
+ source.publish("b", :routing_key => "foo")
118
+ end
119
+ end
120
+ done(0.1) { messages.should == ["b"]}
121
+ end
122
+ end #context
123
+ end # describe
124
+ end # describe AMQP
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: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aman Gupta
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-01-23 00:00:00.000000000 Z
13
+ date: 2014-02-03 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: eventmachine
@@ -272,6 +272,7 @@ files:
272
272
  - spec/integration/declare_one_hundred_server_named_queues_spec.rb
273
273
  - spec/integration/direct_exchange_routing_spec.rb
274
274
  - spec/integration/exchange_declaration_spec.rb
275
+ - spec/integration/exchange_to_exchange_binding_spec.rb
275
276
  - spec/integration/extensions/rabbitmq/publisher_confirmations_spec.rb
276
277
  - spec/integration/fanout_exchange_routing_spec.rb
277
278
  - spec/integration/headers_exchange_routing_spec.rb