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