amqp 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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