amqp 1.1.0.pre1 → 1.1.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+
3
+ module AMQP
4
+
5
+ # Manages the encoding of credentials for the EXTERNAL authentication
6
+ # mechanism.
7
+ class AuthMechanismAdapter::External < AuthMechanismAdapter
8
+
9
+ auth_mechanism "EXTERNAL"
10
+
11
+ # Encodes a username and password for the EXTERNAL mechanism. Since
12
+ # authentication is handled by an encapsulating protocol like SSL or
13
+ # UNIX domain sockets, EXTERNAL doesn't pass along any username or
14
+ # password information at all and this method always returns the
15
+ # empty string.
16
+ #
17
+ # @param [String] username The username to encode. This parameter is
18
+ # ignored.
19
+ # @param [String] password The password to encode. This parameter is
20
+ # ignored.
21
+ # @return [String] The username and password, encoded for the
22
+ # EXTERNAL mechanism. This is always the empty string.
23
+ def encode_credentials(username, password)
24
+ ""
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ module AMQP
4
+
5
+ # Manages the encoding of credentials for the PLAIN authentication
6
+ # mechanism.
7
+ class AuthMechanismAdapter::Plain < AuthMechanismAdapter
8
+
9
+ auth_mechanism "PLAIN"
10
+
11
+ # Encodes credentials for the given username and password. This
12
+ # involves sending the password across the wire in plaintext, so
13
+ # PLAIN authentication should only be used over a secure transport
14
+ # layer.
15
+ #
16
+ # @param [String] username The username to encode.
17
+ # @param [String] password The password to encode.
18
+ # @return [String] The username and password, encoded for the PLAIN
19
+ # mechanism.
20
+ def encode_credentials(username, password)
21
+ "\0#{username}\0#{password}"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,67 @@
1
+ module AMQP
2
+ module Callbacks
3
+
4
+ def redefine_callback(event, callable = nil, &block)
5
+ f = (callable || block)
6
+ # yes, re-assign!
7
+ @callbacks[event] = [f]
8
+
9
+ self
10
+ end
11
+
12
+ def define_callback(event, callable = nil, &block)
13
+ f = (callable || block)
14
+
15
+ @callbacks[event] ||= []
16
+ @callbacks[event] << f if f
17
+
18
+ self
19
+ end # define_callback(event, &block)
20
+ alias append_callback define_callback
21
+
22
+ def prepend_callback(event, &block)
23
+ @callbacks[event] ||= []
24
+ @callbacks[event].unshift(block)
25
+
26
+ self
27
+ end # prepend_callback(event, &block)
28
+
29
+ def clear_callbacks(event)
30
+ @callbacks[event].clear if @callbacks[event]
31
+ end # clear_callbacks(event)
32
+
33
+
34
+ def exec_callback(name, *args, &block)
35
+ list = Array(@callbacks[name])
36
+ if list.any?
37
+ list.each { |c| c.call(*args, &block) }
38
+ end
39
+ end
40
+
41
+ def exec_callback_once(name, *args, &block)
42
+ list = (@callbacks.delete(name) || Array.new)
43
+ if list.any?
44
+ list.each { |c| c.call(*args, &block) }
45
+ end
46
+ end
47
+
48
+ def exec_callback_yielding_self(name, *args, &block)
49
+ list = Array(@callbacks[name])
50
+ if list.any?
51
+ list.each { |c| c.call(self, *args, &block) }
52
+ end
53
+ end
54
+
55
+ def exec_callback_once_yielding_self(name, *args, &block)
56
+ list = (@callbacks.delete(name) || Array.new)
57
+
58
+ if list.any?
59
+ list.each { |c| c.call(self, *args, &block) }
60
+ end
61
+ end
62
+
63
+ def has_callback?(name)
64
+ @callbacks[name] && !@callbacks[name].empty?
65
+ end # has_callback?
66
+ end # Callbacks
67
+ end
@@ -141,7 +141,19 @@ module AMQP
141
141
  # Learn more in {file:docs/VendorSpecificExtensions.textile}
142
142
  #
143
143
  # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Specification.pdf AMQP 0.9.1 specification (Section 2.2.5)
144
- class Channel < AMQ::Client::Channel
144
+ class Channel
145
+
146
+ #
147
+ # Behaviours
148
+ #
149
+
150
+ extend RegisterEntityMixin
151
+ include Entity
152
+ extend ProtocolMethodHandlers
153
+
154
+ register_entity :queue, AMQP::Queue
155
+ register_entity :exchange, AMQP::Exchange
156
+
145
157
 
146
158
  #
147
159
  # API
@@ -156,6 +168,24 @@ module AMQP
156
168
  # @return [Symbol]
157
169
  attr_reader :status
158
170
 
171
+ DEFAULT_REPLY_TEXT = "Goodbye".freeze
172
+
173
+ attr_reader :id
174
+
175
+ attr_reader :exchanges_awaiting_declare_ok, :exchanges_awaiting_delete_ok
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
+ attr_reader :consumers_awaiting_consume_ok, :consumers_awaiting_cancel_ok
178
+
179
+ attr_accessor :flow_is_active
180
+
181
+ # Change publisher index. Publisher index is incremented
182
+ # by 1 after each Basic.Publish starting at 1. This is done
183
+ # on both client and server, hence this acknowledged messages
184
+ # can be matched via its delivery-tag.
185
+ #
186
+ # @api private
187
+ attr_writer :publisher_index
188
+
159
189
 
160
190
  # @param [AMQP::Session] connection Connection to open this channel on. If not given, default AMQP
161
191
  # connection (accessible via {AMQP.connection}) will be used.
@@ -211,7 +241,32 @@ module AMQP
211
241
  id = self.class.next_channel_id
212
242
  end
213
243
 
214
- super(@connection, id, options)
244
+ super(@connection)
245
+
246
+ @id = id
247
+ @exchanges = Hash.new
248
+ @queues = Hash.new
249
+ @consumers = Hash.new
250
+ @options = { :auto_recovery => @connection.auto_recovering? }.merge(options)
251
+ @auto_recovery = (!!@options[:auto_recovery])
252
+
253
+ # we must synchronize frameset delivery. MK.
254
+ @mutex = Mutex.new
255
+
256
+ reset_state!
257
+
258
+ # 65536 is here for cases when channel is opened without passing a callback in,
259
+ # otherwise channel_mix would be nil and it causes a lot of needless headaches.
260
+ # lets just have this default. MK.
261
+ channel_max = if @connection.open?
262
+ @connection.channel_max || 65536
263
+ else
264
+ 65536
265
+ end
266
+
267
+ if channel_max != 0 && !(0..channel_max).include?(id)
268
+ raise ArgumentError.new("Max channel for the connection is #{channel_max}, given: #{id}")
269
+ end
215
270
 
216
271
  # we need this deferrable to mimic what AMQP gem 0.7 does to enable
217
272
  # the following (pseudo-synchronous) style of programming some people use in their
@@ -224,7 +279,7 @@ module AMQP
224
279
  # ...
225
280
  #
226
281
  # Read more about EM::Deferrable#callback behavior in EventMachine documentation. MK.
227
- @channel_is_open_deferrable = AMQ::Client::EventMachineClient::Deferrable.new
282
+ @channel_is_open_deferrable = AMQP::Deferrable.new
228
283
 
229
284
  @parameter_checks = {:queue => [:durable, :exclusive, :auto_delete, :arguments], :exchange => [:type, :durable, :arguments]}
230
285
 
@@ -263,7 +318,7 @@ module AMQP
263
318
  return unless auto_recovering?
264
319
 
265
320
  @channel_is_open_deferrable.fail
266
- @channel_is_open_deferrable = AMQ::Client::EventMachineClient::Deferrable.new
321
+ @channel_is_open_deferrable = AMQP::Deferrable.new
267
322
 
268
323
  self.open do
269
324
  @channel_is_open_deferrable.succeed
@@ -292,7 +347,7 @@ module AMQP
292
347
  self.class.release_channel_id(old_id)
293
348
 
294
349
  @channel_is_open_deferrable.fail
295
- @channel_is_open_deferrable = AMQ::Client::EventMachineClient::Deferrable.new
350
+ @channel_is_open_deferrable = AMQP::Deferrable.new
296
351
 
297
352
  self.open do
298
353
  @channel_is_open_deferrable.succeed
@@ -820,13 +875,13 @@ module AMQP
820
875
  Queue.new(self, name, opts)
821
876
  else
822
877
  shim = Proc.new { |q, method|
823
- if block.arity == 1
824
- block.call(q)
825
- else
826
- queue = find_queue(method.queue)
827
- block.call(queue, method.consumer_count, method.message_count)
828
- end
829
- }
878
+ if block.arity == 1
879
+ block.call(q)
880
+ else
881
+ queue = find_queue(method.queue)
882
+ block.call(queue, method.consumer_count, method.message_count)
883
+ end
884
+ }
830
885
  Queue.new(self, name, opts, &shim)
831
886
  end
832
887
 
@@ -852,8 +907,14 @@ module AMQP
852
907
  # @note Instantiated channels are opened by default. This method should only be used for error recovery after network connection loss.
853
908
  # @api public
854
909
  def open(&block)
855
- super(&block)
910
+ @connection.send_frame(AMQ::Protocol::Channel::Open.encode(@id, AMQ::Protocol::EMPTY_STRING))
911
+ @connection.channels[@id] = self
912
+ self.status = :opening
913
+
914
+ self.redefine_callback :open, &block
856
915
  end
916
+ alias reopen open
917
+
857
918
 
858
919
  # @return [Boolean] true if channel is not closed.
859
920
  # @api public
@@ -889,9 +950,9 @@ module AMQP
889
950
  # @api public
890
951
  def close(reply_code = 200, reply_text = DEFAULT_REPLY_TEXT, class_id = 0, method_id = 0, &block)
891
952
  self.status = :closing
892
- r = super(reply_code, reply_text, class_id, method_id, &block)
953
+ @connection.send_frame(AMQ::Protocol::Channel::Close.encode(@id, reply_code, reply_text, class_id, method_id))
893
954
 
894
- r
955
+ self.redefine_callback :close, &block
895
956
  end
896
957
 
897
958
  # @endgroup
@@ -912,7 +973,10 @@ module AMQP
912
973
  # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Reference.pdf AMQP 0.9.1 protocol documentation (Section 1.5.2.3.)
913
974
  # @api public
914
975
  def flow(active = false, &block)
915
- super(active, &block)
976
+ @connection.send_frame(AMQ::Protocol::Channel::Flow.encode(@id, active))
977
+
978
+ self.redefine_callback :flow, &block
979
+ self
916
980
  end
917
981
 
918
982
  # @return [Boolean] True if flow in this channel is active (messages will be delivered to consumers that use this channel).
@@ -952,7 +1016,9 @@ module AMQP
952
1016
  # @see #recover
953
1017
  # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Reference.pdf AMQP 0.9.1 protocol documentation (Section 1.8.3.13.)
954
1018
  def acknowledge(delivery_tag, multiple = false)
955
- super(delivery_tag, multiple)
1019
+ @connection.send_frame(AMQ::Protocol::Basic::Ack.encode(self.id, delivery_tag, multiple))
1020
+
1021
+ self
956
1022
  end # acknowledge(delivery_tag, multiple = false)
957
1023
 
958
1024
  # Reject a message with given delivery tag.
@@ -961,8 +1027,14 @@ module AMQP
961
1027
  # @see #acknowledge
962
1028
  # @see #recover
963
1029
  # @see http://files.travis-ci.org/docs/amqp/0.9.1/AMQP091Reference.pdf AMQP 0.9.1 protocol documentation (Section 1.8.3.14.)
964
- def reject(delivery_tag, requeue = true)
965
- super(delivery_tag, requeue)
1030
+ def reject(delivery_tag, requeue = true, multi = false)
1031
+ if multi
1032
+ @connection.send_frame(AMQ::Protocol::Basic::Nack.encode(self.id, delivery_tag, multi, requeue))
1033
+ else
1034
+ @connection.send_frame(AMQ::Protocol::Basic::Reject.encode(self.id, delivery_tag, requeue))
1035
+ end
1036
+
1037
+ self
966
1038
  end # reject(delivery_tag, requeue = true)
967
1039
 
968
1040
  # Notifies AMQ broker that consumer has recovered and unacknowledged messages need
@@ -975,7 +1047,10 @@ module AMQP
975
1047
  # @see #acknowledge
976
1048
  # @api public
977
1049
  def recover(requeue = true, &block)
978
- super(requeue, &block)
1050
+ @connection.send_frame(AMQ::Protocol::Basic::Recover.encode(@id, requeue))
1051
+
1052
+ self.redefine_callback :recover, &block
1053
+ self
979
1054
  end # recover(requeue = false, &block)
980
1055
 
981
1056
  # @endgroup
@@ -990,21 +1065,30 @@ module AMQP
990
1065
  #
991
1066
  # @api public
992
1067
  def tx_select(&block)
993
- super(&block)
1068
+ @connection.send_frame(AMQ::Protocol::Tx::Select.encode(@id))
1069
+
1070
+ self.redefine_callback :tx_select, &block
1071
+ self
994
1072
  end # tx_select(&block)
995
1073
 
996
1074
  # Commits AMQP transaction.
997
1075
  #
998
1076
  # @api public
999
1077
  def tx_commit(&block)
1000
- super(&block)
1078
+ @connection.send_frame(AMQ::Protocol::Tx::Commit.encode(@id))
1079
+
1080
+ self.redefine_callback :tx_commit, &block
1081
+ self
1001
1082
  end # tx_commit(&block)
1002
1083
 
1003
1084
  # Rolls AMQP transaction back.
1004
1085
  #
1005
1086
  # @api public
1006
1087
  def tx_rollback(&block)
1007
- super(&block)
1088
+ @connection.send_frame(AMQ::Protocol::Tx::Rollback.encode(@id))
1089
+
1090
+ self.redefine_callback :tx_rollback, &block
1091
+ self
1008
1092
  end # tx_rollback(&block)
1009
1093
 
1010
1094
 
@@ -1021,7 +1105,7 @@ module AMQP
1021
1105
  #
1022
1106
  # @api public
1023
1107
  def on_error(&block)
1024
- super(&block)
1108
+ self.define_callback(:error, &block)
1025
1109
  end
1026
1110
 
1027
1111
  # @endgroup
@@ -1031,56 +1115,30 @@ module AMQP
1031
1115
 
1032
1116
  def confirm_select(nowait = false, &block)
1033
1117
  self.once_open do
1034
- super(nowait, &block)
1118
+ if nowait && block
1119
+ raise ArgumentError, "confirm.select with nowait = true and a callback makes no sense"
1035
1120
  end
1036
- end
1037
1121
 
1038
- # @endgroup
1039
-
1040
-
1041
- #
1042
- # Implementation
1043
- #
1122
+ @uses_publisher_confirmations = true
1123
+ reset_publisher_index!
1044
1124
 
1125
+ self.redefine_callback(:confirm_select, &block) unless nowait
1126
+ self.redefine_callback(:after_publish) do
1127
+ increment_publisher_index!
1128
+ end
1129
+ @connection.send_frame(AMQ::Protocol::Confirm::Select.encode(@id, nowait))
1045
1130
 
1046
- # Defines a global callback to be run on channel-level exception across
1047
- # all channels. Consider using Channel#on_error instead. This method is here for sake
1048
- # of backwards compatibility with 0.6.x and 0.7.x releases.
1049
- #
1050
- # @param [String] msg Error message that passed to previously defined handler
1051
- #
1052
- # @deprecated
1053
- # @api public
1054
- # @private
1055
- def self.error(msg = nil, &block)
1056
- if block
1057
- @global_error_handler = block
1058
- else
1059
- @global_error_handler.call(msg) if @global_error_handler && msg
1131
+ self
1060
1132
  end
1061
1133
  end
1062
1134
 
1135
+ # @endgroup
1063
1136
 
1064
- # Overrides AMQ::Client::Channel version to also call global callback
1065
- # (if defined) for backwards compatibility.
1066
- #
1067
- # @private
1068
- # @api private
1069
- def handle_close(method)
1070
- super(method)
1071
-
1072
- self.class.error(method.reply_text)
1073
- self.class.release_channel_id(@id)
1074
- end
1075
1137
 
1076
- # Overrides AMQ::Client::Channel version to also release the channel id
1077
1138
  #
1078
- # @private
1079
- # @api private
1080
- def handle_close_ok(method)
1081
- super(method)
1082
- self.class.release_channel_id(@id)
1083
- end
1139
+ # Implementation
1140
+ #
1141
+
1084
1142
  # Resets channel state (for example, list of registered queue objects and so on).
1085
1143
  #
1086
1144
  # Most of the time, this method is not
@@ -1089,11 +1147,11 @@ module AMQP
1089
1147
  # @private
1090
1148
  # @api plugin
1091
1149
  def reset(&block)
1092
- # See AMQ::Client::Channel
1150
+ # See AMQP::Channel
1093
1151
  self.reset_state!
1094
1152
 
1095
1153
  # there is no way to reset a deferrable; we have to use a new instance. MK.
1096
- @channel_is_open_deferrable = AMQ::Client::EventMachineClient::Deferrable.new
1154
+ @channel_is_open_deferrable = AMQP::Deferrable.new
1097
1155
  @channel_is_open_deferrable.callback(&block)
1098
1156
 
1099
1157
  @connection.on_connection do
@@ -1103,22 +1161,19 @@ module AMQP
1103
1161
  end
1104
1162
  end
1105
1163
 
1106
- # @private
1107
- # @api plugin
1108
- def reset_state!
1109
- super
1110
- end # reset_state!
1111
-
1112
-
1113
1164
  # Overrides superclass method to also re-create @channel_is_open_deferrable
1114
1165
  #
1115
1166
  # @api plugin
1116
1167
  # @private
1117
- def handle_connection_interruption(reason = nil)
1118
- super(reason)
1168
+ def handle_connection_interruption(method = nil)
1169
+ @queues.each { |name, q| q.handle_connection_interruption(method) }
1170
+ @exchanges.each { |name, e| e.handle_connection_interruption(method) }
1171
+
1172
+ self.exec_callback_yielding_self(:after_connection_interruption)
1173
+ self.reset_state!
1119
1174
 
1120
1175
  self.class.release_channel_id(@id) unless auto_recovering?
1121
- @channel_is_open_deferrable = AMQ::Client::EventMachineClient::Deferrable.new
1176
+ @channel_is_open_deferrable = AMQP::Deferrable.new
1122
1177
  end
1123
1178
 
1124
1179
 
@@ -1178,6 +1233,392 @@ module AMQP
1178
1233
  end # self.initialize_channel_id_allocator
1179
1234
 
1180
1235
 
1236
+ # @return [Boolean] true if this channel uses automatic recovery mode
1237
+ def auto_recovering?
1238
+ @auto_recovery
1239
+ end # auto_recovering?
1240
+
1241
+
1242
+ # @return [Hash<String, Consumer>]
1243
+ def consumers
1244
+ @consumers
1245
+ end # consumers
1246
+
1247
+ # @return [Array<Queue>] Collection of queues that were declared on this channel.
1248
+ def queues
1249
+ @queues.values
1250
+ end
1251
+
1252
+ # @return [Array<Exchange>] Collection of exchanges that were declared on this channel.
1253
+ def exchanges
1254
+ @exchanges.values
1255
+ end
1256
+
1257
+
1258
+ # AMQP connection this channel belongs to.
1259
+ #
1260
+ # @return [AMQP::Connection] Connection this channel belongs to.
1261
+ def connection
1262
+ @connection
1263
+ end # connection
1264
+
1265
+ # Synchronizes given block using this channel's mutex.
1266
+ # @api public
1267
+ def synchronize(&block)
1268
+ @mutex.synchronize(&block)
1269
+ end
1270
+
1271
+
1272
+
1273
+ # @group QoS and flow handling
1274
+
1275
+ # Requests a specific quality of service. The QoS can be specified for the current channel
1276
+ # or for all channels on the connection.
1277
+ #
1278
+ # @note RabbitMQ as of 2.3.1 does not support prefetch_size.
1279
+ # @api public
1280
+ def qos(prefetch_size = 0, prefetch_count = 32, global = false, &block)
1281
+ @connection.send_frame(AMQ::Protocol::Basic::Qos.encode(@id, prefetch_size, prefetch_count, global))
1282
+
1283
+ self.redefine_callback :qos, &block
1284
+ self
1285
+ end # qos
1286
+
1287
+ # @endgroup
1288
+
1289
+
1290
+
1291
+ # @group Error handling
1292
+
1293
+
1294
+ # Defines a callback that will be executed after TCP connection is interrupted (typically because of a network failure).
1295
+ # Only one callback can be defined (the one defined last replaces previously added ones).
1296
+ #
1297
+ # @api public
1298
+ def on_connection_interruption(&block)
1299
+ self.redefine_callback(:after_connection_interruption, &block)
1300
+ end # on_connection_interruption(&block)
1301
+ alias after_connection_interruption on_connection_interruption
1302
+
1303
+
1304
+ # Defines a callback that will be executed after TCP connection has recovered after a network failure
1305
+ # but before AMQP connection is re-opened.
1306
+ # Only one callback can be defined (the one defined last replaces previously added ones).
1307
+ #
1308
+ # @api public
1309
+ def before_recovery(&block)
1310
+ self.redefine_callback(:before_recovery, &block)
1311
+ end # before_recovery(&block)
1312
+
1313
+ # @private
1314
+ def run_before_recovery_callbacks
1315
+ self.exec_callback_yielding_self(:before_recovery)
1316
+
1317
+ @queues.each { |name, q| q.run_before_recovery_callbacks }
1318
+ @exchanges.each { |name, e| e.run_before_recovery_callbacks }
1319
+ end
1320
+
1321
+
1322
+
1323
+ # Defines a callback that will be executed after AMQP connection has recovered after a network failure.
1324
+ # Only one callback can be defined (the one defined last replaces previously added ones).
1325
+ #
1326
+ # @api public
1327
+ def on_recovery(&block)
1328
+ self.redefine_callback(:after_recovery, &block)
1329
+ end # on_recovery(&block)
1330
+ alias after_recovery on_recovery
1331
+
1332
+ # @private
1333
+ def run_after_recovery_callbacks
1334
+ self.exec_callback_yielding_self(:after_recovery)
1335
+
1336
+ @queues.each { |name, q| q.run_after_recovery_callbacks }
1337
+ @exchanges.each { |name, e| e.run_after_recovery_callbacks }
1338
+ end
1339
+
1340
+
1341
+ # Called by associated connection object when AMQP connection has been re-established
1342
+ # (for example, after a network failure).
1343
+ #
1344
+ # @api plugin
1345
+ def auto_recover
1346
+ return unless auto_recovering?
1347
+
1348
+ self.open do
1349
+ # exchanges must be recovered first because queue recovery includes recovery of bindings. MK.
1350
+ @exchanges.each { |name, e| e.auto_recover }
1351
+ @queues.each { |name, q| q.auto_recover }
1352
+ end
1353
+ end # auto_recover
1354
+
1355
+ # @endgroup
1356
+
1357
+
1358
+ # Publisher index is an index of the last message since
1359
+ # the confirmations were activated, started with 0. It's
1360
+ # incremented by 1 every time a message is published.
1361
+ # This is done on both client and server, hence this
1362
+ # acknowledged messages can be matched via its delivery-tag.
1363
+ #
1364
+ # @return [Integer] Current publisher index.
1365
+ # @api public
1366
+ def publisher_index
1367
+ @publisher_index ||= 0
1368
+ end
1369
+
1370
+ # Resets publisher index to 0
1371
+ #
1372
+ # @api plugin
1373
+ def reset_publisher_index!
1374
+ @publisher_index = 0
1375
+ end
1376
+
1377
+
1378
+ # This method is executed after publishing of each message via {Exchage#publish}.
1379
+ # Currently it just increments publisher index by 1, so messages
1380
+ # can be actually matched.
1381
+ #
1382
+ # @api plugin
1383
+ def increment_publisher_index!
1384
+ @publisher_index += 1
1385
+ end
1386
+
1387
+ # @return [Boolean]
1388
+ def uses_publisher_confirmations?
1389
+ @uses_publisher_confirmations
1390
+ end # uses_publisher_confirmations?
1391
+
1392
+
1393
+ # Turn on confirmations for this channel and, if given,
1394
+ # register callback for basic.ack from the broker.
1395
+ #
1396
+ # @raise [RuntimeError] Occurs when confirmations are already activated.
1397
+ # @raise [RuntimeError] Occurs when nowait is true and block is given.
1398
+ # @param [Boolean] nowait Whether we expect Confirm.Select-Ok to be returned by the broker or not.
1399
+ #
1400
+ # @yield [basick_ack] Callback which will be executed every time we receive Basic.Ack from the broker.
1401
+ # @yieldparam [AMQ::Protocol::Basic::Ack] basick_ack Protocol method class instance.
1402
+ #
1403
+ # @return [self] self.
1404
+ def on_ack(nowait = false, &block)
1405
+ self.define_callback(:ack, &block) if block
1406
+
1407
+ self
1408
+ end
1409
+
1410
+
1411
+ # Register error callback for Basic.Nack. It's called
1412
+ # when message(s) is rejected.
1413
+ #
1414
+ # @return [self] self
1415
+ def on_nack(&block)
1416
+ self.define_callback(:nack, &block) if block
1417
+
1418
+ self
1419
+ end
1420
+
1421
+
1422
+
1423
+
1424
+ # Handler for Confirm.Select-Ok. By default, it just
1425
+ # executes hook specified via the #confirmations method
1426
+ # with a single argument, a protocol method class
1427
+ # instance (an instance of AMQ::Protocol::Confirm::SelectOk)
1428
+ # and then it deletes the callback, since Confirm.Select
1429
+ # is supposed to be sent just once.
1430
+ #
1431
+ # @api plugin
1432
+ def handle_select_ok(method)
1433
+ self.exec_callback_once(:confirm_select, method)
1434
+ end
1435
+
1436
+ # Handler for Basic.Ack. By default, it just
1437
+ # executes hook specified via the #confirm method
1438
+ # with a single argument, a protocol method class
1439
+ # instance (an instance of AMQ::Protocol::Basic::Ack).
1440
+ #
1441
+ # @api plugin
1442
+ def handle_basic_ack(method)
1443
+ self.exec_callback(:ack, method)
1444
+ end
1445
+
1446
+
1447
+ # Handler for Basic.Nack. By default, it just
1448
+ # executes hook specified via the #confirm_failed method
1449
+ # with a single argument, a protocol method class
1450
+ # instance (an instance of AMQ::Protocol::Basic::Nack).
1451
+ #
1452
+ # @api plugin
1453
+ def handle_basic_nack(method)
1454
+ self.exec_callback(:nack, method)
1455
+ end
1456
+
1457
+
1458
+
1459
+ #
1460
+ # Implementation
1461
+ #
1462
+
1463
+ def register_exchange(exchange)
1464
+ raise ArgumentError, "argument is nil!" if exchange.nil?
1465
+
1466
+ @exchanges[exchange.name] = exchange
1467
+ end # register_exchange(exchange)
1468
+
1469
+ # Finds exchange in the exchanges cache on this channel by name. Exchange only exists in the cache if
1470
+ # it was previously instantiated on this channel.
1471
+ #
1472
+ # @param [String] name Exchange name
1473
+ # @return [AMQP::Exchange] Exchange (if found)
1474
+ # @api plugin
1475
+ def find_exchange(name)
1476
+ @exchanges[name]
1477
+ end
1478
+
1479
+ # @api plugin
1480
+ # @private
1481
+ def register_queue(queue)
1482
+ raise ArgumentError, "argument is nil!" if queue.nil?
1483
+
1484
+ @queues[queue.name] = queue
1485
+ end # register_queue(queue)
1486
+
1487
+ # @api plugin
1488
+ # @private
1489
+ def find_queue(name)
1490
+ @queues[name]
1491
+ end
1492
+
1493
+
1494
+ RECOVERY_EVENTS = [:after_connection_interruption, :before_recovery, :after_recovery].freeze
1495
+
1496
+
1497
+ # @api plugin
1498
+ # @private
1499
+ def reset_state!
1500
+ @flow_is_active = true
1501
+
1502
+ @queues_awaiting_declare_ok = Array.new
1503
+ @exchanges_awaiting_declare_ok = Array.new
1504
+
1505
+ @queues_awaiting_delete_ok = Array.new
1506
+
1507
+ @exchanges_awaiting_delete_ok = Array.new
1508
+ @queues_awaiting_purge_ok = Array.new
1509
+ @queues_awaiting_bind_ok = Array.new
1510
+ @queues_awaiting_unbind_ok = Array.new
1511
+ @consumers_awaiting_consume_ok = Array.new
1512
+ @consumers_awaiting_cancel_ok = Array.new
1513
+
1514
+ @queues_awaiting_get_response = Array.new
1515
+
1516
+ @callbacks = @callbacks.delete_if { |k, v| !RECOVERY_EVENTS.include?(k) }
1517
+ @uses_publisher_confirmations = false
1518
+ end # reset_state!
1519
+
1520
+
1521
+ # @api plugin
1522
+ # @private
1523
+ def handle_open_ok(open_ok)
1524
+ self.status = :opened
1525
+ self.exec_callback_once_yielding_self(:open, open_ok)
1526
+ end
1527
+
1528
+ # @api plugin
1529
+ # @private
1530
+ def handle_close_ok(close_ok)
1531
+ self.status = :closed
1532
+ self.connection.clear_frames_on(self.id)
1533
+ self.exec_callback_once_yielding_self(:close, close_ok)
1534
+
1535
+ self.class.release_channel_id(@id)
1536
+ end
1537
+
1538
+ # @api plugin
1539
+ # @private
1540
+ def handle_close(channel_close)
1541
+ self.status = :closed
1542
+ self.connection.clear_frames_on(self.id)
1543
+
1544
+ self.exec_callback_yielding_self(:error, channel_close)
1545
+ end
1546
+
1547
+
1548
+
1549
+ self.handle(AMQ::Protocol::Channel::OpenOk) do |connection, frame|
1550
+ channel = connection.channels[frame.channel]
1551
+ channel.handle_open_ok(frame.decode_payload)
1552
+ end
1553
+
1554
+ self.handle(AMQ::Protocol::Channel::CloseOk) do |connection, frame|
1555
+ method = frame.decode_payload
1556
+ channels = connection.channels
1557
+
1558
+ channel = channels[frame.channel]
1559
+ channels.delete(channel)
1560
+ channel.handle_close_ok(method)
1561
+ end
1562
+
1563
+ self.handle(AMQ::Protocol::Channel::Close) do |connection, frame|
1564
+ method = frame.decode_payload
1565
+ channels = connection.channels
1566
+ channel = channels[frame.channel]
1567
+ connection.send_frame(AMQ::Protocol::Channel::CloseOk.encode(frame.channel))
1568
+ channel.handle_close(method)
1569
+ end
1570
+
1571
+ self.handle(AMQ::Protocol::Basic::QosOk) do |connection, frame|
1572
+ channel = connection.channels[frame.channel]
1573
+ channel.exec_callback(:qos, frame.decode_payload)
1574
+ end
1575
+
1576
+ self.handle(AMQ::Protocol::Basic::RecoverOk) do |connection, frame|
1577
+ channel = connection.channels[frame.channel]
1578
+ channel.exec_callback(:recover, frame.decode_payload)
1579
+ end
1580
+
1581
+ self.handle(AMQ::Protocol::Channel::FlowOk) do |connection, frame|
1582
+ channel = connection.channels[frame.channel]
1583
+ method = frame.decode_payload
1584
+
1585
+ channel.flow_is_active = method.active
1586
+ channel.exec_callback(:flow, method)
1587
+ end
1588
+
1589
+ self.handle(AMQ::Protocol::Tx::SelectOk) do |connection, frame|
1590
+ channel = connection.channels[frame.channel]
1591
+ channel.exec_callback(:tx_select, frame.decode_payload)
1592
+ end
1593
+
1594
+ self.handle(AMQ::Protocol::Tx::CommitOk) do |connection, frame|
1595
+ channel = connection.channels[frame.channel]
1596
+ channel.exec_callback(:tx_commit, frame.decode_payload)
1597
+ end
1598
+
1599
+ self.handle(AMQ::Protocol::Tx::RollbackOk) do |connection, frame|
1600
+ channel = connection.channels[frame.channel]
1601
+ channel.exec_callback(:tx_rollback, frame.decode_payload)
1602
+ end
1603
+
1604
+ self.handle(AMQ::Protocol::Confirm::SelectOk) do |connection, frame|
1605
+ method = frame.decode_payload
1606
+ channel = connection.channels[frame.channel]
1607
+ channel.handle_select_ok(method)
1608
+ end
1609
+
1610
+ self.handle(AMQ::Protocol::Basic::Ack) do |connection, frame|
1611
+ method = frame.decode_payload
1612
+ channel = connection.channels[frame.channel]
1613
+ channel.handle_basic_ack(method)
1614
+ end
1615
+
1616
+ self.handle(AMQ::Protocol::Basic::Nack) do |connection, frame|
1617
+ method = frame.decode_payload
1618
+ channel = connection.channels[frame.channel]
1619
+ channel.handle_basic_nack(method)
1620
+ end
1621
+
1181
1622
  protected
1182
1623
 
1183
1624
  @private