bunny 2.24.0 → 3.1.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.
@@ -0,0 +1,824 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ require "set"
5
+ require "bunny/topology_recovery_filter"
6
+
7
+ module Bunny
8
+ # As queues, exchanges, bindings are created and deleted,
9
+ # connections keep track of the topology using this registry.
10
+ #
11
+ # Then, when the connection and its channels are recovered,
12
+ # this registry is used as the source of truth during topology
13
+ # recovery.
14
+ #
15
+ # This registry takes care of dropping auto-delete exchanges or queues
16
+ # when their respective conditions for removal hold.
17
+ #
18
+ # @param opts [Hash<Symbol, Object>]
19
+ # @option opts :topology_recovery_filter Filters out objects so that they are skipped during topology recovery
20
+ #
21
+ # @see #record_queue
22
+ # @see #delete_recorded_queue
23
+ # @see #delete_recorded_queue_named
24
+ # @see #record_exchange
25
+ # @see #delete_recorded_exchange
26
+ # @see #delete_recorded_exchange_named
27
+ # @see #record_exchange_binding_with
28
+ # @see #delete_recorded_exchange_binding
29
+ # @see #record_queue_binding_with
30
+ # @see #delete_recorded_queue_binding
31
+ # @see #record_consumer_with
32
+ # @see #delete_recorded_consumer
33
+ class TopologyRegistry
34
+ def initialize(opts = {})
35
+ @filter = opts.fetch(:topology_recovery_filter, DefaultTopologyRecoveryFilter.new)
36
+
37
+ self.reset!
38
+ end
39
+
40
+ def reset!
41
+ @queues = {}
42
+ @exchanges = {}
43
+ @queue_bindings = Set.new
44
+ @exchange_bindings = Set.new
45
+ @consumers = {}
46
+
47
+ @queue_mutex = Monitor.new
48
+ @exchange_mutex = Monitor.new
49
+ @binding_mutex = Monitor.new
50
+ @consumer_mutex = Monitor.new
51
+ end
52
+
53
+ #
54
+ # Queues
55
+ #
56
+
57
+ # @!group Queues
58
+
59
+ # @return [Hash<String, Bunny::RecordedQueue>]
60
+ attr_reader :queues
61
+
62
+ # @return [Array<Bunny::RecordedQueue>]
63
+ # @see Bunny::TopologyRecoveryFilter
64
+ def filtered_queues
65
+ @filter.filter_queues(@queues.values)
66
+ end
67
+
68
+ # @param [Bunny::Queue] queue
69
+ def record_queue(queue)
70
+ @queue_mutex.synchronize { @queues[queue.name] = RecordedQueue::from(queue) }
71
+ end
72
+
73
+ # @param [Bunny::Channel] ch
74
+ # @param [String] name
75
+ # @param [Boolean] server_named
76
+ # @param [Boolean] durable
77
+ # @param [Boolean] auto_delete
78
+ # @param [Boolean] exclusive
79
+ # @param [Hash] arguments
80
+ def record_queue_with(ch, name, server_named, durable, auto_delete, exclusive, arguments)
81
+ queue = RecordedQueue.new(ch, name)
82
+ .with_server_named(server_named)
83
+ .with_durable(durable)
84
+ .with_auto_delete(auto_delete)
85
+ .with_exclusive(exclusive)
86
+ .with_arguments(arguments)
87
+
88
+ @queue_mutex.synchronize { @queues[queue.name] = queue }
89
+ end
90
+
91
+ # @param [Bunny::Queue, Bunny::RecordedQueue] queue
92
+ def delete_recorded_queue(queue)
93
+ self.delete_recorded_queue_named(queue.name)
94
+ end
95
+
96
+ # @param [String] name
97
+ def delete_recorded_queue_named_without_cascading(name)
98
+ @queue_mutex.synchronize do
99
+ @queues.delete(name)
100
+ end
101
+ end
102
+
103
+ # @param [String] name
104
+ def delete_recorded_queue_named(name)
105
+ @queue_mutex.synchronize do
106
+ @queues.delete(name)
107
+
108
+ bs = self.remove_recorded_bindings_with_queue_destination(name)
109
+ bs.each do |b|
110
+ self.maybe_delete_recorded_auto_delete_exchange(b.source)
111
+ end
112
+ end
113
+ end
114
+
115
+ # @!endgroup
116
+
117
+ #
118
+ # Consumers
119
+ #
120
+
121
+ # @!group Consumers
122
+
123
+ # @return [Hash<String, Bunny::RecordedConsumer>]
124
+ attr_reader :consumers
125
+
126
+ # @return [Array<Bunny::RecordedConsumer>]
127
+ # @see Bunny::TopologyRecoveryFilter
128
+ def filtered_consumers
129
+ @filter.filter_consumers(@consumers.values)
130
+ end
131
+
132
+ # @param [Bunny::Channel] ch
133
+ # @param [String] consumer_tag
134
+ # @param [String] queue_name
135
+ # @param [#call] callable
136
+ # @param [Boolean] manual_ack
137
+ # @param [Boolean] exclusive
138
+ # @param [Hash] arguments
139
+ def record_consumer_with(ch, consumer_tag, queue_name, callable, manual_ack, exclusive, arguments)
140
+ @consumer_mutex.synchronize do
141
+ cons = RecordedConsumer.new(ch, queue_name)
142
+ .with_consumer_tag(consumer_tag)
143
+ .with_callable(callable)
144
+ .with_manual_ack(manual_ack)
145
+ .with_exclusive(exclusive)
146
+ .with_arguments(arguments)
147
+
148
+ @consumers[consumer_tag] = cons
149
+ end
150
+ end
151
+
152
+ # @param [String] consumer_tag
153
+ def delete_recorded_consumer(consumer_tag)
154
+ @consumer_mutex.synchronize do
155
+ if (val = @consumers.delete(consumer_tag))
156
+ self.maybe_delete_recorded_auto_delete_queue(val.queue_name)
157
+ end
158
+ end
159
+ end
160
+
161
+ # @param [String] old_name
162
+ # @param [String] new_name
163
+ # @private
164
+ def propagate_queue_name_change_to_consumers(old_name, new_name)
165
+ @consumer_mutex.synchronize do
166
+ @consumers.each do |_, rc|
167
+ rc.update_queue_name_to(new_name) if rc.queue_name == old_name
168
+ end
169
+ end
170
+ end
171
+
172
+ # @!endgroup
173
+
174
+ #
175
+ # Exchanges
176
+ #
177
+
178
+ # @!group Exchanges
179
+
180
+ # @return [Hash<String, Bunny::RecordedExchange>]
181
+ attr_reader :exchanges
182
+
183
+ # @return [Array<Bunny::RecordedExchange>]
184
+ # @see Bunny::TopologyRecoveryFilter
185
+ def filtered_exchanges
186
+ @filter.filter_exchanges(@exchanges.values)
187
+ end
188
+
189
+ # @param [Bunny::Exchange] exchange
190
+ def record_exchange(exchange)
191
+ @exchange_mutex.synchronize { @exchanges[exchange.name] = RecordedExchange::from(exchange) }
192
+ end
193
+
194
+ # @param [Bunny::Channel] ch
195
+ # @param [String] name
196
+ # @param [String] type
197
+ # @param [Boolean] durable
198
+ # @param [Boolean] auto_delete
199
+ # @param [Hash] arguments
200
+ def record_exchange_with(ch, name, type, durable, auto_delete, arguments)
201
+ exchange = RecordedExchange.new(ch, name)
202
+ .with_type(type)
203
+ .with_durable(durable)
204
+ .with_auto_delete(auto_delete)
205
+ .with_arguments(arguments)
206
+
207
+ @exchange_mutex.synchronize { @exchanges[exchange.name] = exchange }
208
+ end
209
+
210
+ # @param [Bunny::Exchange, Bunny::RecordedExchange] exchange
211
+ def delete_recorded_exchange(exchange)
212
+ self.delete_recorded_exchange_named(exchange.name)
213
+ end
214
+
215
+ # @param [String] name
216
+ def delete_recorded_exchange_named(name)
217
+ @exchange_mutex.synchronize do
218
+ @exchanges.delete(name)
219
+ bs1 = self.remove_recorded_bindings_with_source(name)
220
+ bs2 = self.remove_recorded_bindings_with_exchange_destination(name)
221
+
222
+ bs1.each do |b|
223
+ self.maybe_delete_recorded_auto_delete_exchange(b.source)
224
+ end
225
+
226
+ bs2.each do |b|
227
+ self.maybe_delete_recorded_auto_delete_exchange(b.source)
228
+ end
229
+ end
230
+ end
231
+
232
+ # @!endgroup
233
+
234
+ #
235
+ # Bindings
236
+ #
237
+
238
+ # !@group Bindings
239
+
240
+ # @return [Set<Bunny::RecordedQueueBinding>]
241
+ attr_reader :queue_bindings
242
+
243
+ # @return [Array<Bunny::RecordedQueueBinding>]
244
+ # @see Bunny::TopologyRecoveryFilter
245
+ def filtered_queue_bindings
246
+ @filter.filter_queue_bindings(@queue_bindings)
247
+ end
248
+
249
+ # @return [Set<Bunny::RecordedExchangeBinding>]
250
+ attr_reader :exchange_bindings
251
+
252
+ # @return [Array<Bunny::RecordedExchangeBinding>]
253
+ # @see Bunny::TopologyRecoveryFilter
254
+ def filtered_exchange_bindings
255
+ @filter.filter_exchange_bindings(@exchange_bindings)
256
+ end
257
+
258
+ # @param [Bunny::Channel] ch
259
+ # @param [String] exchange_name
260
+ # @param [String] queue_name
261
+ # @param [String] routing_key
262
+ # @param [Hash] arguments
263
+ def record_queue_binding_with(ch, exchange_name, queue_name, routing_key, arguments)
264
+ b = RecordedQueueBinding.new(ch)
265
+ .with_source(exchange_name)
266
+ .with_destination(queue_name)
267
+ .with_routing_key(routing_key)
268
+ .with_arguments(arguments)
269
+
270
+ @binding_mutex.synchronize { @queue_bindings.add(b) }
271
+ end
272
+
273
+ # @param [Bunny::Channel] ch
274
+ # @param [String] exchange_name
275
+ # @param [String] queue_name
276
+ # @param [String] routing_key
277
+ # @param [Hash] arguments
278
+ def delete_recorded_queue_binding(ch, exchange_name, queue_name, routing_key, arguments)
279
+ b = RecordedQueueBinding.new(ch)
280
+ .with_source(exchange_name)
281
+ .with_destination(queue_name)
282
+ .with_routing_key(routing_key)
283
+ .with_arguments(arguments)
284
+
285
+ @binding_mutex.synchronize { @queue_bindings.delete(b) }
286
+ end
287
+
288
+ # @param [Bunny::Channel] ch
289
+ # @param [String] source_name
290
+ # @param [String] destination_name
291
+ # @param [String] routing_key
292
+ # @param [Hash] arguments
293
+ def record_exchange_binding_with(ch, source_name, destination_name, routing_key, arguments)
294
+ b = RecordedExchangeBinding.new(ch)
295
+ .with_source(source_name)
296
+ .with_destination(destination_name)
297
+ .with_routing_key(routing_key)
298
+ .with_arguments(arguments)
299
+
300
+ @binding_mutex.synchronize { @exchange_bindings.add(b) }
301
+ end
302
+
303
+ # @param [Bunny::Channel] ch
304
+ # @param [String] source_name
305
+ # @param [String] destination_name
306
+ # @param [String] routing_key
307
+ # @param [Hash] arguments
308
+ def delete_recorded_exchange_binding(ch, source_name, destination_name, routing_key, arguments)
309
+ b = RecordedExchangeBinding.new(ch)
310
+ .with_source(source_name)
311
+ .with_destination(destination_name)
312
+ .with_routing_key(routing_key)
313
+ .with_arguments(arguments)
314
+
315
+ @binding_mutex.synchronize do
316
+ if @exchange_bindings.delete?(b)
317
+ self.maybe_delete_recorded_auto_delete_exchange(source_name)
318
+ end
319
+ end
320
+ end
321
+
322
+ # @param [String] old_name
323
+ # @param [String] new_name
324
+ # @private
325
+ def record_queue_name_change(old_name, new_name)
326
+ # update the recorded queue itself
327
+ @queue_mutex.synchronize do
328
+ if (orig = @queues[old_name])
329
+ @queues.delete(old_name)
330
+
331
+ orig.update_name_to(new_name)
332
+ @queues[new_name] = orig.dup
333
+ end
334
+ end
335
+
336
+ self.propagate_queue_name_change_to_bindings(old_name, new_name)
337
+ self.propagate_queue_name_change_to_consumers(old_name, new_name)
338
+ # Make sure the original name is removed and won't be recovered
339
+ # but do not cascade
340
+ self.delete_recorded_queue_named_without_cascading(old_name)
341
+ end
342
+
343
+ # @param [String] old_name
344
+ # @param [String] new_name
345
+ # @private
346
+ def propagate_queue_name_change_to_bindings(old_name, new_name)
347
+ @binding_mutex.synchronize do
348
+ @queue_bindings.each do |rb|
349
+ rb.update_destination_to(new_name) if rb.destination == old_name
350
+ end
351
+ end
352
+ end
353
+
354
+ # @!endgroup
355
+
356
+ #
357
+ # Implementation
358
+ #
359
+
360
+ # @param name [String] Auto-delete queue name
361
+ def maybe_delete_recorded_auto_delete_queue(name)
362
+ @queue_mutex.synchronize do
363
+ if (q = @queues[name]) && q.auto_delete?
364
+ unless self.has_more_consumers_on_queue?(@consumers.values, name)
365
+ self.delete_recorded_queue(q)
366
+ end
367
+ end
368
+ end
369
+ end
370
+
371
+ # @param name [String] Auto-delete exchange name
372
+ def maybe_delete_recorded_auto_delete_exchange(name)
373
+ @exchange_mutex.synchronize do
374
+ if (x = @exchanges[name]) && x.auto_delete
375
+ unless self.has_more_destinations_bound_to_exchange?(@queue_bindings.dup, @exchange_bindings.dup, name)
376
+ self.delete_recorded_exchange_named(name)
377
+ end
378
+ end
379
+ end
380
+ end
381
+
382
+ # @param name [String]
383
+ # @return [Array<Bunny::RecordedBinding>]
384
+ def remove_recorded_bindings_with_source(name)
385
+ @binding_mutex.synchronize do
386
+ matching_qbs = self.queue_bindings.filter { |b| b.source == name }
387
+ matching_xbs = self.exchange_bindings.filter { |b| b.source == name }
388
+
389
+ matches = matching_qbs + matching_xbs
390
+ matches.each do |b|
391
+ @queue_bindings.delete(b)
392
+ @exchange_bindings.delete(b)
393
+ end
394
+
395
+ matches
396
+ end
397
+ end
398
+
399
+ # @param name [String]
400
+ # @return [Array<Bunny::RecordedBinding>]
401
+ def remove_recorded_bindings_with_queue_destination(name)
402
+ @binding_mutex.synchronize do
403
+ matches = self.queue_bindings.filter { |b| b.destination == name }
404
+ @queue_bindings = Set.new(@queue_bindings.reject { |b| b.destination == name })
405
+ matches
406
+ end
407
+ end
408
+
409
+ # @param name [String]
410
+ # @return [Array<Bunny::RecordedBinding>]
411
+ def remove_recorded_bindings_with_exchange_destination(name)
412
+ @binding_mutex.synchronize do
413
+ matches = self.exchange_bindings.filter { |b| b.destination == name }
414
+ @exchange_bindings = Set.new(@exchange_bindings.reject { |b| b.destination == name })
415
+ matches
416
+ end
417
+ end
418
+
419
+ # @param consumers [Array<Bunny::RecordedConsumer]
420
+ # @param name [String]
421
+ def has_more_consumers_on_queue?(consumers, name)
422
+ return false if consumers.empty?
423
+
424
+ consumers.any? { |val| val.queue_name == name }
425
+ end
426
+
427
+ # @param queue_bindings [Set<Bunny::RecordedBinding>]
428
+ # @param exchange_bindings [Set<Bunny::RecordedBinding>]
429
+ # @param name [String] Auto-delete exchange name
430
+ def has_more_destinations_bound_to_exchange?(queue_bindings, exchange_bindings, name)
431
+ return false if queue_bindings.empty? && exchange_bindings.empty?
432
+
433
+ condition_one = queue_bindings.any? { |val| val.source == name }
434
+ condition_two = exchange_bindings.any? { |val| val.source == name }
435
+
436
+ condition_one || condition_two
437
+ end
438
+ end
439
+
440
+ #
441
+ # Recordable, Recoverable Entities
442
+ #
443
+
444
+ # @abstract
445
+ class RecordedEntity
446
+ # @return [Bunny::Channel]
447
+ attr_reader :channel
448
+
449
+ # @param ch [Bunny::Channel]
450
+ def initialize(ch)
451
+ @channel = ch
452
+ end
453
+ end
454
+ # @abstract Represents a named topology entity
455
+ class RecordedNamedEntity < RecordedEntity
456
+ # @return [String]
457
+ attr_reader :name
458
+
459
+ # @param ch [Bunny::Channel]
460
+ # @param name [String]
461
+ def initialize(ch, name)
462
+ @name = name
463
+
464
+ super(ch)
465
+ end
466
+ end
467
+
468
+ # Represents an exchange declaration intent that can be repeated.
469
+ class RecordedExchange < RecordedNamedEntity
470
+ # @return [String]
471
+ attr_reader :type
472
+ # @return [Boolean]
473
+ attr_reader :durable
474
+ # @return [Boolean]
475
+ attr_reader :auto_delete
476
+ # @return [Hash]
477
+ attr_reader :arguments
478
+
479
+ # @param ch [Bunny::Channel]
480
+ # @param name [String]
481
+ def initialize(ch, name)
482
+ super(ch, name)
483
+
484
+ @type = nil
485
+ @durable = true
486
+ @auto_delete = false
487
+ @arguments = nil
488
+ end
489
+
490
+ # @return [Boolean] true if this exchange is a pre-defined one (amq.direct, amq.fanout, amq.match and so on)
491
+ def predefined?
492
+ (@name == AMQ::Protocol::EMPTY_STRING) || !!(@name =~ /^amq\.(direct|fanout|topic|headers|match)/i)
493
+ end # predefined?
494
+ alias predeclared? predefined?
495
+
496
+ # @param value [Boolean]
497
+ def with_durable(value)
498
+ @durable = value
499
+ self
500
+ end
501
+
502
+ # @param value [Boolean]
503
+ def with_auto_delete(value)
504
+ @auto_delete = value
505
+ self
506
+ end
507
+
508
+ # @param value [Symbol]
509
+ def with_type(value)
510
+ @type = value
511
+ self
512
+ end
513
+
514
+ # @param value [Hash]
515
+ def with_arguments(value)
516
+ @arguments = value
517
+ self
518
+ end
519
+
520
+ # @return [Integer]
521
+ def hash
522
+ [self.class, self.channel, self.name, @type, @durable, @auto_delete, @arguments].hash
523
+ end
524
+
525
+ # @return [Boolean]
526
+ def eql?(other)
527
+ self == other
528
+ end
529
+
530
+ # @return [Boolean]
531
+ def ==(other)
532
+ other.class == self.class &&
533
+ other.name == self.name &&
534
+ other.channel == self.channel &&
535
+ other.durable == self.durable &&
536
+ other.auto_delete == self.auto_delete &&
537
+ other.type == self.type &&
538
+ other.arguments == self.arguments
539
+ end
540
+
541
+ # @param [Bunny::Exchange] x
542
+ def self.from(x)
543
+ new(x.channel, x.name)
544
+ .with_type(x.type)
545
+ .with_durable(x.durable?)
546
+ .with_auto_delete(x.auto_delete?)
547
+ .with_arguments(x.arguments)
548
+ end
549
+ end
550
+
551
+ # Represents an exchange declaration intent that can be repeated.
552
+ #
553
+ # Server-named queues will acquire a new server-generated name.
554
+ class RecordedQueue < RecordedNamedEntity
555
+ EMPTY_STRING = "".freeze
556
+
557
+ # @return [Boolean]
558
+ attr_reader :durable, :auto_delete, :exclusive
559
+ # @return [Hash]
560
+ attr_reader :arguments
561
+
562
+ # @param ch [Bunny::Channel]
563
+ # @param name [String]
564
+ def initialize(ch, name)
565
+ super ch, name
566
+
567
+ @durable = true
568
+ @auto_delete = false
569
+ @exclusive = false
570
+ @server_named = false
571
+ @arguments = nil
572
+ end
573
+
574
+ # @param value [String]
575
+ def update_name_to(value)
576
+ @name = value
577
+ self
578
+ end
579
+
580
+ # @param value [Boolean]
581
+ def with_durable(value)
582
+ @durable = value
583
+ self
584
+ end
585
+
586
+ # @param value [Boolean]
587
+ def with_auto_delete(value)
588
+ @auto_delete = value
589
+ self
590
+ end
591
+
592
+ def auto_delete?
593
+ @auto_delete
594
+ end
595
+
596
+ # @param value [Boolean]
597
+ def with_exclusive(value)
598
+ @exclusive = value
599
+ self
600
+ end
601
+
602
+ def exclusive?
603
+ @exclusive
604
+ end
605
+
606
+ # @param value [Boolean]
607
+ def with_server_named(value)
608
+ @server_named = value
609
+ self
610
+ end
611
+
612
+ # @return [Boolean]
613
+ def server_named?
614
+ !!@server_named
615
+ end
616
+
617
+ # @param value [Hash]
618
+ def with_arguments(value)
619
+ @arguments = value
620
+ self
621
+ end
622
+
623
+ # @return [String]
624
+ def name_to_use_for_recovery
625
+ if server_named?
626
+ EMPTY_STRING
627
+ else
628
+ self.name
629
+ end
630
+ end
631
+
632
+ # @return [Boolean]
633
+ def eql?(other)
634
+ self == other
635
+ end
636
+
637
+ # @return [Boolean]
638
+ def ==(other)
639
+ other.class == self.class &&
640
+ other.name == self.name &&
641
+ other.channel == self.channel &&
642
+ other.durable == self.durable &&
643
+ other.auto_delete == self.auto_delete &&
644
+ other.exclusive == self.exclusive &&
645
+ other.arguments == self.arguments
646
+ end
647
+
648
+ def hash
649
+ [self.class, self.channel, @name, @durable].hash
650
+ end
651
+
652
+ # @param [Bunny::Queue] q
653
+ def self.from(q)
654
+ new(q.channel, q.name)
655
+ .with_server_named(q.server_named?)
656
+ .with_durable(q.durable?)
657
+ .with_auto_delete(q.auto_delete?)
658
+ .with_exclusive(q.exclusive?)
659
+ .with_arguments(q.arguments)
660
+ end
661
+ end
662
+
663
+ # Represents a consumer (subscription) registration intent that can be repeated.
664
+ class RecordedConsumer < RecordedEntity
665
+ # @return [String]
666
+ attr_reader :queue_name, :consumer_tag
667
+ # @return [#call]
668
+ attr_reader :callable
669
+ # @return [Boolean]
670
+ attr_reader :exclusive, :manual_ack
671
+ # @return [Hash]
672
+ attr_reader :arguments
673
+
674
+ # @param ch [Bunny::Channel]
675
+ # @param queue_name [String]
676
+ def initialize(ch, queue_name)
677
+ super ch
678
+
679
+ @queue_name = queue_name
680
+ @consumer_tag = nil
681
+ @callable = nil
682
+ @exclusive = false
683
+ @manual_ack = true
684
+ @arguments = Hash.new
685
+ end
686
+
687
+ # @param value [String]
688
+ def update_queue_name_to(value)
689
+ @queue_name = value
690
+ self
691
+ end
692
+
693
+ # @param value [String]
694
+ def with_queue_name(value)
695
+ @queue_name = value
696
+ self
697
+ end
698
+
699
+ # @param value [String]
700
+ def with_consumer_tag(value)
701
+ @consumer_tag = value
702
+ self
703
+ end
704
+
705
+ # @param value [#call, Proc]
706
+ def with_callable(value)
707
+ @callable = value
708
+ self
709
+ end
710
+
711
+ def with_manual_ack(value)
712
+ @manual_ack = value
713
+ self
714
+ end
715
+
716
+ def with_exclusive(value)
717
+ @exclusive = value
718
+ self
719
+ end
720
+
721
+ # @param value [Hash]
722
+ def with_arguments(value)
723
+ @arguments = value
724
+ self
725
+ end
726
+
727
+ def eql?(other)
728
+ self == other
729
+ end
730
+
731
+ # @param other [Bunny::RecordedConsumer]
732
+ # @return [Boolean]
733
+ def ==(other)
734
+ other.class == self.class &&
735
+ other.channel == self.channel &&
736
+ other.queue_name == self.queue_name &&
737
+ other.callable == self.callable &&
738
+ other.manual_ack == self.manual_ack &&
739
+ other.exclusive == self.exclusive &&
740
+ other.arguments == self.arguments
741
+ end
742
+
743
+ def hash
744
+ [self.class, self.channel, @queue_name, @consumer_tag, @callable, @exclusive, @manual_ack, @arguments].hash
745
+ end
746
+ end
747
+
748
+ class RecordedBinding < RecordedEntity
749
+ # @return [String]
750
+ attr_reader :source
751
+ # @return [String]
752
+ attr_reader :destination
753
+ # @return [String]
754
+ attr_reader :routing_key
755
+ # @return [Hash]
756
+ attr_reader :arguments
757
+
758
+ def initialize(ch)
759
+ super ch
760
+
761
+ @source = nil
762
+ @destination = nil
763
+ @routing_key = nil
764
+ @arguments = Hash.new
765
+ end
766
+
767
+ # @param value [String]
768
+ def with_source(value)
769
+ @source = value
770
+ self
771
+ end
772
+
773
+ # @param value [String]
774
+ def with_destination(value)
775
+ @destination = value
776
+ self
777
+ end
778
+
779
+ # @param value [String]
780
+ def with_routing_key(value)
781
+ @routing_key = value
782
+ self
783
+ end
784
+
785
+ # @param value [Hash]
786
+ def with_arguments(value)
787
+ @arguments = value
788
+ self
789
+ end
790
+
791
+ def hash
792
+ [self.class, @source, @destination, @routing_key, @arguments].hash
793
+ end
794
+
795
+ # @param other [Bunny::RecordedBinding]
796
+ # @return [Boolean]
797
+ def eql?(other)
798
+ self == other
799
+ end
800
+
801
+ # @param other [Bunny::RecordedBinding]
802
+ # @return [Boolean]
803
+ def ==(other)
804
+ other.class == self.class &&
805
+ other.source == self.source &&
806
+ other.destination == self.destination &&
807
+ other.routing_key == self.routing_key &&
808
+ other.arguments == self.arguments
809
+ end
810
+ end
811
+
812
+ # Represents a queue binding intent that can be repeated.
813
+ class RecordedQueueBinding < RecordedBinding
814
+ # @param value [String]
815
+ def update_destination_to(value)
816
+ @destination = value
817
+ self
818
+ end
819
+ end
820
+
821
+ # Represents an exchange binding intent that can be repeated.
822
+ class RecordedExchangeBinding < RecordedBinding
823
+ end
824
+ end