amqp 0.7.0.pre → 0.7.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.
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/CHANGELOG +8 -2
- data/CONTRIBUTORS +22 -0
- data/Gemfile +3 -3
- data/README.md +20 -11
- data/Rakefile +30 -6
- data/amqp.gemspec +1 -1
- data/bin/cleanify.rb +50 -0
- data/examples/amqp/simple.rb +6 -4
- data/examples/mq/ack.rb +8 -6
- data/examples/mq/automatic_binding_for_default_direct_exchange.rb +65 -0
- data/examples/mq/callbacks.rb +9 -1
- data/examples/mq/clock.rb +17 -17
- data/examples/mq/hashtable.rb +19 -10
- data/examples/mq/internal.rb +13 -11
- data/examples/mq/logger.rb +38 -36
- data/examples/mq/multiclock.rb +16 -7
- data/examples/mq/pingpong.rb +16 -7
- data/examples/mq/pop.rb +8 -6
- data/examples/mq/primes-simple.rb +2 -0
- data/examples/mq/primes.rb +7 -5
- data/examples/mq/stocks.rb +14 -5
- data/lib/amqp.rb +12 -8
- data/lib/amqp/buffer.rb +35 -158
- data/lib/amqp/client.rb +34 -22
- data/lib/amqp/frame.rb +8 -64
- data/lib/amqp/protocol.rb +21 -70
- data/lib/amqp/server.rb +11 -9
- data/lib/amqp/spec.rb +8 -6
- data/lib/amqp/version.rb +2 -0
- data/lib/ext/blankslate.rb +3 -1
- data/lib/ext/em.rb +2 -0
- data/lib/ext/emfork.rb +13 -11
- data/lib/mq.rb +253 -156
- data/lib/mq/collection.rb +6 -88
- data/lib/mq/exchange.rb +70 -13
- data/lib/mq/header.rb +12 -6
- data/lib/mq/logger.rb +9 -7
- data/lib/mq/queue.rb +42 -30
- data/lib/mq/rpc.rb +6 -4
- data/protocol/codegen.rb +20 -18
- data/research/api.rb +10 -46
- data/research/primes-forked.rb +9 -7
- data/research/primes-processes.rb +74 -72
- data/research/primes-threaded.rb +9 -7
- data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +61 -0
- data/spec/mq_helper.rb +70 -0
- data/spec/spec_helper.rb +84 -29
- data/spec/unit/amqp/buffer_spec.rb +178 -0
- data/spec/unit/amqp/client_spec.rb +472 -0
- data/spec/unit/amqp/frame_spec.rb +60 -0
- data/spec/unit/amqp/misc_spec.rb +123 -0
- data/spec/unit/amqp/protocol_spec.rb +53 -0
- data/spec/unit/mq/channel_close_spec.rb +15 -0
- data/spec/unit/mq/collection_spec.rb +129 -0
- data/spec/unit/mq/exchange_declaration_spec.rb +524 -0
- data/spec/unit/mq/misc_spec.rb +228 -0
- data/spec/unit/mq/mq_basic_spec.rb +39 -0
- data/spec/unit/mq/queue_declaration_spec.rb +97 -0
- data/spec/unit/mq/queue_spec.rb +71 -0
- metadata +33 -21
- data/Gemfile.lock +0 -16
- data/old/README +0 -30
- data/old/Rakefile +0 -12
- data/old/amqp-0.8.json +0 -606
- data/old/amqp_spec.rb +0 -796
- data/old/amqpc.rb +0 -695
- data/old/codegen.rb +0 -148
- data/spec/channel_close_spec.rb +0 -13
- data/spec/sync_async_spec.rb +0 -52
data/lib/mq.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
#:main: README
|
2
4
|
#
|
3
5
|
|
@@ -17,6 +19,18 @@ class MQ
|
|
17
19
|
|
18
20
|
# Raised whenever an illegal operation is attempted.
|
19
21
|
class Error < StandardError; end
|
22
|
+
|
23
|
+
class IncompatibleOptionsError < Error
|
24
|
+
def initialize(name, opts_1, opts_2)
|
25
|
+
super("There is already an instance called #{name} with options #{opts_1.inspect}, you can't define the same instance with different options (#{opts_2.inspect})!")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class ChannelClosedError < Error
|
30
|
+
def initialize(instance)
|
31
|
+
super("The channel #{instance.channel} was closed, you can't use it anymore!")
|
32
|
+
end
|
33
|
+
end
|
20
34
|
end
|
21
35
|
|
22
36
|
# The top-level class for building AMQP clients. This class contains several
|
@@ -116,9 +130,20 @@ end
|
|
116
130
|
# ["every 2 seconds", :received, Tue Jan 06 22:46:20 -0600 2009]
|
117
131
|
#
|
118
132
|
class MQ
|
133
|
+
|
134
|
+
#
|
135
|
+
# Behaviors
|
136
|
+
#
|
137
|
+
|
119
138
|
include AMQP
|
120
139
|
include EM::Deferrable
|
121
140
|
|
141
|
+
|
142
|
+
|
143
|
+
#
|
144
|
+
# API
|
145
|
+
#
|
146
|
+
|
122
147
|
# Returns a new channel. A channel is a bidirectional virtual
|
123
148
|
# connection between the client and the AMQP server. Elsewhere in the
|
124
149
|
# library the channel is referred to in parameter lists as +mq+.
|
@@ -136,148 +161,28 @@ class MQ
|
|
136
161
|
# channel = MQ.new AMQP::connect
|
137
162
|
# end
|
138
163
|
#
|
139
|
-
def initialize
|
140
|
-
raise 'MQ can only be used from within EM.run{}' unless EM.reactor_running?
|
164
|
+
def initialize(connection = nil)
|
165
|
+
raise 'MQ can only be used from within EM.run {}' unless EM.reactor_running?
|
166
|
+
|
167
|
+
@_send_mutex = Mutex.new
|
168
|
+
@get_queue_mutex = Mutex.new
|
141
169
|
|
142
170
|
@connection = connection || AMQP.start
|
143
171
|
|
144
|
-
conn.callback{ |c|
|
172
|
+
conn.callback { |c|
|
145
173
|
@channel = c.add_channel(self)
|
146
174
|
send Protocol::Channel::Open.new
|
147
175
|
}
|
148
176
|
end
|
149
|
-
attr_reader :channel, :connection
|
150
|
-
|
151
|
-
def check_content_completion
|
152
|
-
if @body.length >= @header.size
|
153
|
-
@header.properties.update(@method.arguments)
|
154
|
-
@consumer.receive @header, @body if @consumer
|
155
|
-
@body = @header = @consumer = @method = nil
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
# May raise a MQ::Error exception when the frame payload contains a
|
160
|
-
# Protocol::Channel::Close object.
|
161
|
-
#
|
162
|
-
# This usually occurs when a client attempts to perform an illegal
|
163
|
-
# operation. A short, and incomplete, list of potential illegal operations
|
164
|
-
# follows:
|
165
|
-
# * publish a message to a deleted exchange (NOT_FOUND)
|
166
|
-
# * declare an exchange using the reserved 'amq.' naming structure (ACCESS_REFUSED)
|
167
|
-
#
|
168
|
-
def process_frame frame
|
169
|
-
log :received, frame
|
170
|
-
|
171
|
-
case frame
|
172
|
-
when Frame::Header
|
173
|
-
@header = frame.payload
|
174
|
-
@body = ''
|
175
|
-
check_content_completion
|
176
|
-
|
177
|
-
when Frame::Body
|
178
|
-
@body << frame.payload
|
179
|
-
check_content_completion
|
180
|
-
|
181
|
-
when Frame::Method
|
182
|
-
case method = frame.payload
|
183
|
-
when Protocol::Channel::OpenOk
|
184
|
-
send Protocol::Access::Request.new(:realm => '/data',
|
185
|
-
:read => true,
|
186
|
-
:write => true,
|
187
|
-
:active => true,
|
188
|
-
:passive => true)
|
189
|
-
|
190
|
-
when Protocol::Access::RequestOk
|
191
|
-
@ticket = method.ticket
|
192
|
-
callback{
|
193
|
-
send Protocol::Channel::Close.new(:reply_code => 200,
|
194
|
-
:reply_text => 'bye',
|
195
|
-
:method_id => 0,
|
196
|
-
:class_id => 0)
|
197
|
-
} if @closing
|
198
|
-
succeed
|
199
|
-
|
200
|
-
when Protocol::Basic::CancelOk
|
201
|
-
if @consumer = consumers[ method.consumer_tag ]
|
202
|
-
@consumer.cancelled
|
203
|
-
else
|
204
|
-
MQ.error "Basic.CancelOk for invalid consumer tag: #{method.consumer_tag}"
|
205
|
-
end
|
206
177
|
|
207
|
-
|
208
|
-
|
209
|
-
# be an empty string, then AMQP broker generated a random one.
|
210
|
-
exchanges = self.exchanges.select { |exchange| exchange.opts[:nowait].eql?(false) }
|
211
|
-
exchange = exchanges.reverse.find { |exchange| exchange.status.eql?(:unfinished) }
|
212
|
-
exchange.receive_response method
|
213
|
-
|
214
|
-
when Protocol::Queue::DeclareOk
|
215
|
-
# We can't use queues[method.queue] because if the name would
|
216
|
-
# be an empty string, then AMQP broker generated a random one.
|
217
|
-
queues = self.queues.select { |queue| queue.opts[:nowait].eql?(false) }
|
218
|
-
queue = queues.reverse.find { |queue| queue.status.eql?(:unfinished) }
|
219
|
-
queue.receive_status method
|
220
|
-
|
221
|
-
when Protocol::Queue::BindOk
|
222
|
-
# We can't use queues[method.queue] because if the name would
|
223
|
-
# be an empty string, then AMQP broker generated a random one.
|
224
|
-
queues = self.queues.select { |queue| queue.opts[:nowait].eql?(false) }
|
225
|
-
queue = queues.reverse.find { |queue| queue.status.eql?(:unbound) }
|
226
|
-
queue.after_bind method
|
227
|
-
|
228
|
-
when Protocol::Basic::Deliver, Protocol::Basic::GetOk
|
229
|
-
@method = method
|
230
|
-
@header = nil
|
231
|
-
@body = ''
|
232
|
-
|
233
|
-
if method.is_a? Protocol::Basic::GetOk
|
234
|
-
@consumer = get_queue{|q| q.shift }
|
235
|
-
MQ.error "No pending Basic.GetOk requests" unless @consumer
|
236
|
-
else
|
237
|
-
@consumer = consumers[ method.consumer_tag ]
|
238
|
-
MQ.error "Basic.Deliver for invalid consumer tag: #{method.consumer_tag}" unless @consumer
|
239
|
-
end
|
240
|
-
|
241
|
-
when Protocol::Basic::GetEmpty
|
242
|
-
if @consumer = get_queue{|q| q.shift }
|
243
|
-
@consumer.receive nil, nil
|
244
|
-
else
|
245
|
-
MQ.error "Basic.GetEmpty for invalid consumer"
|
246
|
-
end
|
247
|
-
|
248
|
-
when Protocol::Channel::Close
|
249
|
-
raise Error, "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]} on #{@channel}"
|
250
|
-
|
251
|
-
when Protocol::Channel::CloseOk
|
252
|
-
@on_close && @on_close.call(self)
|
253
|
-
|
254
|
-
@closing = false
|
255
|
-
conn.callback{ |c|
|
256
|
-
c.channels.delete @channel
|
257
|
-
c.close if c.channels.empty?
|
258
|
-
}
|
178
|
+
attr_reader :channel, :connection, :status
|
179
|
+
alias :conn :connection
|
259
180
|
|
260
|
-
|
261
|
-
|
262
|
-
@consumer.confirm_subscribe
|
263
|
-
else
|
264
|
-
MQ.error "Basic.ConsumeOk for invalid consumer tag: #{method.consumer_tag}"
|
265
|
-
end
|
266
|
-
end
|
267
|
-
end
|
181
|
+
def closed?
|
182
|
+
@status.eql?(:closed)
|
268
183
|
end
|
269
184
|
|
270
|
-
|
271
|
-
conn.callback{ |c|
|
272
|
-
(@_send_mutex ||= Mutex.new).synchronize do
|
273
|
-
args.each do |data|
|
274
|
-
data.ticket = @ticket if @ticket and data.respond_to? :ticket=
|
275
|
-
log :sending, data
|
276
|
-
c.send data, :channel => @channel
|
277
|
-
end
|
278
|
-
end
|
279
|
-
}
|
280
|
-
end
|
185
|
+
|
281
186
|
|
282
187
|
# Defines, intializes and returns an Exchange to act as an ingress
|
283
188
|
# point for all published messages.
|
@@ -352,8 +257,16 @@ class MQ
|
|
352
257
|
# * redeclare an already-declared exchange to a different type
|
353
258
|
# * :passive => true and the exchange does not exist (NOT_FOUND)
|
354
259
|
#
|
355
|
-
def direct
|
356
|
-
self.exchanges
|
260
|
+
def direct(name = 'amq.direct', opts = {}, &block)
|
261
|
+
if exchange = self.exchanges.find { |exchange| exchange.name == name }
|
262
|
+
extended_opts = Exchange.add_default_options(:direct, name, opts, block)
|
263
|
+
|
264
|
+
validate_parameters_match!(exchange, extended_opts)
|
265
|
+
|
266
|
+
exchange
|
267
|
+
else
|
268
|
+
self.exchanges << Exchange.new(self, :direct, name, opts, &block)
|
269
|
+
end
|
357
270
|
end
|
358
271
|
|
359
272
|
# Defines, intializes and returns an Exchange to act as an ingress
|
@@ -438,8 +351,16 @@ class MQ
|
|
438
351
|
# * redeclare an already-declared exchange to a different type
|
439
352
|
# * :passive => true and the exchange does not exist (NOT_FOUND)
|
440
353
|
#
|
441
|
-
def fanout
|
442
|
-
self.exchanges
|
354
|
+
def fanout(name = 'amq.fanout', opts = {}, &block)
|
355
|
+
if exchange = self.exchanges.find { |exchange| exchange.name == name }
|
356
|
+
extended_opts = Exchange.add_default_options(:fanout, name, opts, block)
|
357
|
+
|
358
|
+
validate_parameters_match!(exchange, extended_opts)
|
359
|
+
|
360
|
+
exchange
|
361
|
+
else
|
362
|
+
self.exchanges << Exchange.new(self, :fanout, name, opts, &block)
|
363
|
+
end
|
443
364
|
end
|
444
365
|
|
445
366
|
# Defines, intializes and returns an Exchange to act as an ingress
|
@@ -550,8 +471,16 @@ class MQ
|
|
550
471
|
# * redeclare an already-declared exchange to a different type
|
551
472
|
# * :passive => true and the exchange does not exist (NOT_FOUND)
|
552
473
|
#
|
553
|
-
def topic
|
554
|
-
self.exchanges
|
474
|
+
def topic(name = 'amq.topic', opts = {}, &block)
|
475
|
+
if exchange = self.exchanges.find { |exchange| exchange.name == name }
|
476
|
+
extended_opts = Exchange.add_default_options(:topic, name, opts, block)
|
477
|
+
|
478
|
+
validate_parameters_match!(exchange, extended_opts)
|
479
|
+
|
480
|
+
exchange
|
481
|
+
else
|
482
|
+
self.exchanges << Exchange.new(self, :topic, name, opts, &block)
|
483
|
+
end
|
555
484
|
end
|
556
485
|
|
557
486
|
# Defines, intializes and returns an Exchange to act as an ingress
|
@@ -630,8 +559,16 @@ class MQ
|
|
630
559
|
# * redeclare an already-declared exchange to a different type
|
631
560
|
# * :passive => true and the exchange does not exist (NOT_FOUND)
|
632
561
|
# * using a value other than "any" or "all" for "x-match"
|
633
|
-
def headers
|
634
|
-
self.exchanges
|
562
|
+
def headers(name = 'amq.match', opts = {}, &block)
|
563
|
+
if exchange = self.exchanges.find { |exchange| exchange.name == name }
|
564
|
+
extended_opts = Exchange.add_default_options(:headers, name, opts, block)
|
565
|
+
|
566
|
+
validate_parameters_match!(exchange, extended_opts)
|
567
|
+
|
568
|
+
exchange
|
569
|
+
else
|
570
|
+
self.exchanges << Exchange.new(self, :headers, name, opts, &block)
|
571
|
+
end
|
635
572
|
end
|
636
573
|
|
637
574
|
# Queues store and forward messages. Queues can be configured in the server
|
@@ -647,8 +584,8 @@ class MQ
|
|
647
584
|
#
|
648
585
|
# == Options
|
649
586
|
# * :passive => true | false (default false)
|
650
|
-
# If set, the server will not create the
|
651
|
-
# already exist. The client can use this to check whether
|
587
|
+
# If set, the server will not create the queue if it does not
|
588
|
+
# already exist. The client can use this to check whether the queue
|
652
589
|
# exists without modifying the server state.
|
653
590
|
#
|
654
591
|
# * :durable => true | false (default false)
|
@@ -687,7 +624,7 @@ class MQ
|
|
687
624
|
#
|
688
625
|
# The server waits for a short period of time before
|
689
626
|
# determining the queue is unused to give time to the client code
|
690
|
-
# to bind
|
627
|
+
# to bind a queue to it.
|
691
628
|
#
|
692
629
|
# If the queue has been previously declared, this option is ignored
|
693
630
|
# on subsequent declarations.
|
@@ -700,11 +637,19 @@ class MQ
|
|
700
637
|
# not wait for a reply method. If the server could not complete the
|
701
638
|
# method it will raise a channel or connection exception.
|
702
639
|
#
|
703
|
-
def queue
|
704
|
-
self.queues
|
640
|
+
def queue(name, opts = {}, &block)
|
641
|
+
if queue = self.queues.find { |queue| queue.name == name }
|
642
|
+
extended_opts = Queue.add_default_options(name, opts, block)
|
643
|
+
|
644
|
+
validate_parameters_match!(queue, extended_opts)
|
645
|
+
|
646
|
+
queue
|
647
|
+
else
|
648
|
+
self.queues << Queue.new(self, name, opts, &block)
|
649
|
+
end
|
705
650
|
end
|
706
651
|
|
707
|
-
def queue!
|
652
|
+
def queue!(name, opts = {}, &block)
|
708
653
|
self.queues.add! Queue.new(self, name, opts, &block)
|
709
654
|
end
|
710
655
|
|
@@ -744,7 +689,7 @@ class MQ
|
|
744
689
|
# end
|
745
690
|
# end
|
746
691
|
#
|
747
|
-
def rpc
|
692
|
+
def rpc(name, obj = nil)
|
748
693
|
rpcs[name] ||= RPC.new(self, name, obj)
|
749
694
|
end
|
750
695
|
|
@@ -772,7 +717,9 @@ class MQ
|
|
772
717
|
|
773
718
|
def prefetch(size)
|
774
719
|
@prefetch_size = size
|
720
|
+
|
775
721
|
send Protocol::Basic::Qos.new(:prefetch_size => 0, :prefetch_count => size, :global => false)
|
722
|
+
|
776
723
|
self
|
777
724
|
end
|
778
725
|
|
@@ -784,7 +731,7 @@ class MQ
|
|
784
731
|
# If this flag is true, the server will attempt to requeue the message, potentially then
|
785
732
|
# delivering it to an alternative subscriber.
|
786
733
|
#
|
787
|
-
def recover
|
734
|
+
def recover(requeue = false)
|
788
735
|
send Protocol::Basic::Recover.new(:requeue => requeue)
|
789
736
|
self
|
790
737
|
end
|
@@ -805,7 +752,7 @@ class MQ
|
|
805
752
|
|
806
753
|
def get_queue
|
807
754
|
if block_given?
|
808
|
-
|
755
|
+
@get_queue_mutex.synchronize {
|
809
756
|
yield( @get_queue ||= [] )
|
810
757
|
}
|
811
758
|
end
|
@@ -833,26 +780,176 @@ class MQ
|
|
833
780
|
@consumers = {}
|
834
781
|
|
835
782
|
exs = @exchanges
|
836
|
-
@exchanges =
|
837
|
-
exs.each{ |
|
783
|
+
@exchanges = MQ::Collection.new
|
784
|
+
exs.each { |e| e.reset } if exs
|
838
785
|
|
839
786
|
qus = @queues
|
840
|
-
@queues =
|
841
|
-
qus.each{ |
|
787
|
+
@queues = MQ::Collection.new
|
788
|
+
qus.each { |q| q.reset } if qus
|
842
789
|
|
843
790
|
prefetch(@prefetch_size) if @prefetch_size
|
844
791
|
end
|
845
792
|
|
793
|
+
|
794
|
+
#
|
795
|
+
# Implementation
|
796
|
+
#
|
797
|
+
|
798
|
+
# May raise a MQ::Error exception when the frame payload contains a
|
799
|
+
# Protocol::Channel::Close object.
|
800
|
+
#
|
801
|
+
# This usually occurs when a client attempts to perform an illegal
|
802
|
+
# operation. A short, and incomplete, list of potential illegal operations
|
803
|
+
# follows:
|
804
|
+
# * publish a message to a deleted exchange (NOT_FOUND)
|
805
|
+
# * declare an exchange using the reserved 'amq.' naming structure (ACCESS_REFUSED)
|
806
|
+
#
|
807
|
+
def process_frame(frame)
|
808
|
+
log :received, frame
|
809
|
+
|
810
|
+
case frame
|
811
|
+
when Frame::Header
|
812
|
+
@header = frame.payload
|
813
|
+
@body = ''
|
814
|
+
check_content_completion
|
815
|
+
|
816
|
+
when Frame::Body
|
817
|
+
@body << frame.payload
|
818
|
+
check_content_completion
|
819
|
+
|
820
|
+
when Frame::Method
|
821
|
+
case method = frame.payload
|
822
|
+
when Protocol::Channel::OpenOk
|
823
|
+
send Protocol::Access::Request.new(:realm => '/data',
|
824
|
+
:read => true,
|
825
|
+
:write => true,
|
826
|
+
:active => true,
|
827
|
+
:passive => true)
|
828
|
+
|
829
|
+
when Protocol::Access::RequestOk
|
830
|
+
@ticket = method.ticket
|
831
|
+
callback {
|
832
|
+
send Protocol::Channel::Close.new(:reply_code => 200,
|
833
|
+
:reply_text => 'bye',
|
834
|
+
:method_id => 0,
|
835
|
+
:class_id => 0)
|
836
|
+
} if @closing
|
837
|
+
succeed
|
838
|
+
|
839
|
+
when Protocol::Basic::CancelOk
|
840
|
+
if @consumer = consumers[ method.consumer_tag ]
|
841
|
+
@consumer.cancelled
|
842
|
+
else
|
843
|
+
MQ.error "Basic.CancelOk for invalid consumer tag: #{method.consumer_tag}"
|
844
|
+
end
|
845
|
+
|
846
|
+
when Protocol::Exchange::DeclareOk
|
847
|
+
# We can't use exchanges[method.exchange] because if the name would
|
848
|
+
# be an empty string, then AMQP broker generated a random one.
|
849
|
+
exchanges = self.exchanges.select { |exchange| exchange.opts[:nowait].eql?(false) }
|
850
|
+
exchange = exchanges.reverse.find { |exchange| exchange.status.eql?(:unfinished) }
|
851
|
+
exchange.receive_response method
|
852
|
+
|
853
|
+
when Protocol::Queue::DeclareOk
|
854
|
+
# We can't use queues[method.queue] because if the name would
|
855
|
+
# be an empty string, then AMQP broker generated a random one.
|
856
|
+
queues = self.queues.select { |queue| queue.opts[:nowait].eql?(false) }
|
857
|
+
queue = queues.reverse.find { |queue| queue.status.eql?(:unfinished) }
|
858
|
+
queue.receive_status method
|
859
|
+
|
860
|
+
when Protocol::Queue::BindOk
|
861
|
+
# We can't use queues[method.queue] because if the name would
|
862
|
+
# be an empty string, then AMQP broker generated a random one.
|
863
|
+
queues = self.queues.select { |queue| queue.sync_bind }
|
864
|
+
queue = queues.reverse.find { |queue| queue.status.eql?(:unbound) }
|
865
|
+
queue.after_bind method
|
866
|
+
|
867
|
+
when Protocol::Basic::Deliver, Protocol::Basic::GetOk
|
868
|
+
@method = method
|
869
|
+
@header = nil
|
870
|
+
@body = ''
|
871
|
+
|
872
|
+
if method.is_a? Protocol::Basic::GetOk
|
873
|
+
@consumer = get_queue { |q| q.shift }
|
874
|
+
MQ.error "No pending Basic.GetOk requests" unless @consumer
|
875
|
+
else
|
876
|
+
@consumer = consumers[ method.consumer_tag ]
|
877
|
+
MQ.error "Basic.Deliver for invalid consumer tag: #{method.consumer_tag}" unless @consumer
|
878
|
+
end
|
879
|
+
|
880
|
+
when Protocol::Basic::GetEmpty
|
881
|
+
if @consumer = get_queue { |q| q.shift }
|
882
|
+
@consumer.receive nil, nil
|
883
|
+
else
|
884
|
+
MQ.error "Basic.GetEmpty for invalid consumer"
|
885
|
+
end
|
886
|
+
|
887
|
+
when Protocol::Channel::Close
|
888
|
+
@status = :closed
|
889
|
+
MQ.error "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]} on #{@channel}"
|
890
|
+
|
891
|
+
when Protocol::Channel::CloseOk
|
892
|
+
@status = :closed
|
893
|
+
@on_close && @on_close.call(self)
|
894
|
+
|
895
|
+
@closing = false
|
896
|
+
conn.callback { |c|
|
897
|
+
c.channels.delete @channel
|
898
|
+
c.close if c.channels.empty?
|
899
|
+
}
|
900
|
+
|
901
|
+
when Protocol::Basic::ConsumeOk
|
902
|
+
if @consumer = consumers[ method.consumer_tag ]
|
903
|
+
@consumer.confirm_subscribe
|
904
|
+
else
|
905
|
+
MQ.error "Basic.ConsumeOk for invalid consumer tag: #{method.consumer_tag}"
|
906
|
+
end
|
907
|
+
end
|
908
|
+
end
|
909
|
+
end # process_frame
|
910
|
+
|
911
|
+
|
912
|
+
def send(*args)
|
913
|
+
conn.callback { |c|
|
914
|
+
@_send_mutex.synchronize do
|
915
|
+
args.each do |data|
|
916
|
+
unless self.closed?
|
917
|
+
data.ticket = @ticket if @ticket and data.respond_to? :ticket=
|
918
|
+
log :sending, data
|
919
|
+
c.send data, :channel => @channel
|
920
|
+
else
|
921
|
+
unless data.class == AMQP::Protocol::Channel::CloseOk
|
922
|
+
raise ChannelClosedError.new(self)
|
923
|
+
end
|
924
|
+
end
|
925
|
+
end
|
926
|
+
end
|
927
|
+
}
|
928
|
+
end # send
|
929
|
+
|
930
|
+
|
931
|
+
def check_content_completion
|
932
|
+
if @body.length >= @header.size
|
933
|
+
@header.properties.update(@method.arguments)
|
934
|
+
@consumer.receive @header, @body if @consumer
|
935
|
+
@body = @header = @consumer = @method = nil
|
936
|
+
end
|
937
|
+
end # check_content_completion
|
938
|
+
|
939
|
+
|
846
940
|
private
|
847
941
|
|
848
|
-
def log
|
942
|
+
def log(*args)
|
849
943
|
return unless MQ.logging
|
850
944
|
pp args
|
851
945
|
puts
|
852
|
-
end
|
946
|
+
end # log
|
853
947
|
|
854
|
-
|
855
|
-
|
948
|
+
def validate_parameters_match!(entity, parameters)
|
949
|
+
unless entity.opts == parameters || parameters[:passive]
|
950
|
+
raise IncompatibleOptionsError.new(entity.name, entity.opts, parameters)
|
951
|
+
end
|
952
|
+
end # validate_parameters_match!(entity, parameters)
|
856
953
|
end
|
857
954
|
|
858
955
|
#-- convenience wrapper (read: HACK) for thread-local MQ object
|