amq-client 0.7.0.alpha25 → 0.7.0.alpha26
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/.travis.yml +0 -1
- data/examples/coolio_adapter/basic_consume.rb +19 -15
- data/examples/coolio_adapter/channel_close.rb +4 -4
- data/examples/eventmachine_adapter/authentication/plain_password_with_default_role_credentials.rb +1 -1
- data/examples/eventmachine_adapter/basic_consume.rb +19 -17
- data/examples/eventmachine_adapter/basic_publish.rb +5 -5
- data/examples/eventmachine_adapter/channel_close.rb +4 -4
- data/examples/eventmachine_adapter/exchange_declare.rb +8 -8
- data/examples/eventmachine_adapter/kitchen_sink1.rb +10 -10
- data/lib/amq/client/adapter.rb +225 -38
- data/lib/amq/client/adapters/coolio.rb +72 -54
- data/lib/amq/client/adapters/event_machine.rb +67 -60
- data/lib/amq/client/callbacks.rb +18 -9
- data/lib/amq/client/channel.rb +44 -45
- data/lib/amq/client/entity.rb +4 -4
- data/lib/amq/client/exchange.rb +13 -21
- data/lib/amq/client/queue.rb +31 -31
- data/lib/amq/client/settings.rb +12 -1
- data/lib/amq/client/version.rb +1 -1
- data/spec/integration/coolio/connection_close_spec.rb +5 -5
- data/spec/integration/coolio/connection_start_spec.rb +9 -6
- data/spec/integration/eventmachine/channel_close_spec.rb +4 -4
- data/spec/integration/eventmachine/connection_close_spec.rb +5 -5
- data/spec/unit/client/entity_spec.rb +3 -8
- metadata +5 -6
- data/lib/amq/client/connection.rb +0 -246
@@ -13,6 +13,19 @@ module AMQ
|
|
13
13
|
# cool.io style.
|
14
14
|
#
|
15
15
|
class CoolioClient
|
16
|
+
|
17
|
+
#
|
18
|
+
# Behaviors
|
19
|
+
#
|
20
|
+
|
21
|
+
include AMQ::Client::Adapter
|
22
|
+
|
23
|
+
|
24
|
+
#
|
25
|
+
# API
|
26
|
+
#
|
27
|
+
|
28
|
+
|
16
29
|
#
|
17
30
|
# Cool.io socket delegates most of its operations to the parent adapter.
|
18
31
|
# Thus, 99.9% of the time you don't need to deal with this class.
|
@@ -73,17 +86,7 @@ module AMQ
|
|
73
86
|
end
|
74
87
|
end
|
75
88
|
|
76
|
-
#
|
77
|
-
# Behaviors
|
78
|
-
#
|
79
89
|
|
80
|
-
include AMQ::Client::Adapter
|
81
|
-
include AMQ::Client::Callbacks
|
82
|
-
|
83
|
-
|
84
|
-
#
|
85
|
-
# API
|
86
|
-
#
|
87
90
|
|
88
91
|
# Cool.io socket for multiplexing et al.
|
89
92
|
#
|
@@ -93,11 +96,6 @@ module AMQ
|
|
93
96
|
# Hash with available callbacks
|
94
97
|
attr_accessor :callbacks
|
95
98
|
|
96
|
-
# AMQP connections
|
97
|
-
#
|
98
|
-
# @see AMQ::Client::Connection
|
99
|
-
attr_accessor :connections
|
100
|
-
|
101
99
|
# Creates a socket and attaches it to cool.io default loop.
|
102
100
|
#
|
103
101
|
# Called from CoolioClient.connect
|
@@ -106,9 +104,24 @@ module AMQ
|
|
106
104
|
# @param [Hash] connection settings
|
107
105
|
# @api private
|
108
106
|
def establish_connection(settings)
|
109
|
-
|
107
|
+
@settings = Settings.configure(settings)
|
108
|
+
|
109
|
+
socket = Socket.connect(self, @settings[:host], @settings[:port])
|
110
110
|
socket.attach(Cool.io::Loop.default)
|
111
111
|
self.socket = socket
|
112
|
+
|
113
|
+
|
114
|
+
@on_tcp_connection_failure = @settings[:on_tcp_connection_failure] || Proc.new { |settings|
|
115
|
+
raise self.class.tcp_connection_failure_exception_class.new(settings)
|
116
|
+
}
|
117
|
+
@on_possible_authentication_failure = @settings[:on_possible_authentication_failure] || Proc.new { |settings|
|
118
|
+
raise self.class.authentication_failure_exception_class.new(settings)
|
119
|
+
}
|
120
|
+
|
121
|
+
@locale = @settings.fetch(:locale, "en_GB")
|
122
|
+
@client_properties = Settings.client_properties.merge(@settings.fetch(:client_properties, Hash.new))
|
123
|
+
|
124
|
+
socket
|
112
125
|
end
|
113
126
|
|
114
127
|
# Registers on_open callback
|
@@ -127,11 +140,13 @@ module AMQ
|
|
127
140
|
# Be careful with default values for #ruby hashes: h = Hash.new(Array.new); h[:key] ||= 1
|
128
141
|
# won't assign anything to :key. MK.
|
129
142
|
@callbacks = {}
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
143
|
+
|
144
|
+
self.logger = self.class.logger
|
145
|
+
|
146
|
+
@frames = Array.new
|
147
|
+
@channels = Hash.new
|
148
|
+
|
149
|
+
@mechanism = "PLAIN"
|
135
150
|
end
|
136
151
|
|
137
152
|
# Sets a callback for successful connection (after we receive open-ok)
|
@@ -177,16 +192,6 @@ module AMQ
|
|
177
192
|
end
|
178
193
|
|
179
194
|
|
180
|
-
# Called by Socket if it could not connect.
|
181
|
-
#
|
182
|
-
# @api private
|
183
|
-
def tcp_connection_failed
|
184
|
-
if has_callback?(:tcp_connection_failure)
|
185
|
-
exec_callback_yielding_self(:tcp_connection_failure)
|
186
|
-
else
|
187
|
-
raise self.class.tcp_connection_failure_exception_class.new(settings)
|
188
|
-
end
|
189
|
-
end # tcp_connection_failed
|
190
195
|
|
191
196
|
# Called when socket is connected but before handshake is done
|
192
197
|
#
|
@@ -201,6 +206,35 @@ module AMQ
|
|
201
206
|
def socket_disconnected
|
202
207
|
end
|
203
208
|
|
209
|
+
alias close disconnect
|
210
|
+
|
211
|
+
|
212
|
+
self.handle(Protocol::Connection::Start) do |connection, frame|
|
213
|
+
connection.start_ok(frame.decode_payload)
|
214
|
+
end
|
215
|
+
|
216
|
+
self.handle(Protocol::Connection::Tune) do |connection, frame|
|
217
|
+
connection.handle_tune(frame.decode_payload)
|
218
|
+
|
219
|
+
connection.open(connection.vhost)
|
220
|
+
end
|
221
|
+
|
222
|
+
self.handle(Protocol::Connection::OpenOk) do |connection, frame|
|
223
|
+
connection.handle_open_ok(frame.decode_payload)
|
224
|
+
end
|
225
|
+
|
226
|
+
self.handle(Protocol::Connection::Close) do |connection, frame|
|
227
|
+
connection.handle_close(frame.decode_payload)
|
228
|
+
end
|
229
|
+
|
230
|
+
self.handle(Protocol::Connection::CloseOk) do |connection, frame|
|
231
|
+
connection.handle_close_ok(frame.decode_payload)
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
|
236
|
+
|
237
|
+
|
204
238
|
# Sends raw data through the socket
|
205
239
|
#
|
206
240
|
# @param [String] binary data
|
@@ -209,6 +243,7 @@ module AMQ
|
|
209
243
|
socket.send_raw data
|
210
244
|
end
|
211
245
|
|
246
|
+
|
212
247
|
# The story about the buffering is kinda similar to EventMachine,
|
213
248
|
# you keep receiving more than one frame in a single packet.
|
214
249
|
#
|
@@ -240,32 +275,15 @@ module AMQ
|
|
240
275
|
|
241
276
|
# @api private
|
242
277
|
def post_init
|
243
|
-
reset
|
244
|
-
handshake
|
278
|
+
self.reset
|
279
|
+
self.handshake
|
245
280
|
end
|
246
281
|
|
247
282
|
# @api private
|
248
283
|
def reset
|
249
284
|
@chunk_buffer = ""
|
285
|
+
@frames = Array.new
|
250
286
|
end
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
# @api private
|
255
|
-
def get_next_frame
|
256
|
-
return nil unless @chunk_buffer.size > 7 # otherwise, cannot read the length
|
257
|
-
# octet + short
|
258
|
-
offset = 1 + 2
|
259
|
-
# length
|
260
|
-
payload_length = @chunk_buffer[offset, 4].unpack('N')[0]
|
261
|
-
# 4 bytes for long payload length, 1 byte final octet
|
262
|
-
frame_length = offset + 4 + payload_length + 1
|
263
|
-
if frame_length <= @chunk_buffer.size
|
264
|
-
@chunk_buffer.slice!(0, frame_length)
|
265
|
-
else
|
266
|
-
nil
|
267
|
-
end
|
268
|
-
end
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
287
|
+
end # CoolioClient
|
288
|
+
end # Client
|
289
|
+
end # AMQ
|
@@ -7,10 +7,6 @@ require "amq/client/framing/string/frame"
|
|
7
7
|
module AMQ
|
8
8
|
module Client
|
9
9
|
class EventMachineClient < EM::Connection
|
10
|
-
# @private
|
11
|
-
class Deferrable
|
12
|
-
include EventMachine::Deferrable
|
13
|
-
end
|
14
10
|
|
15
11
|
#
|
16
12
|
# Behaviors
|
@@ -23,10 +19,7 @@ module AMQ
|
|
23
19
|
# API
|
24
20
|
#
|
25
21
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
def self.connect(settings = nil, &block)
|
22
|
+
def self.connect(settings = {}, &block)
|
30
23
|
@settings = Settings.configure(settings)
|
31
24
|
|
32
25
|
instance = EventMachine.connect(@settings[:host], @settings[:port], self, @settings)
|
@@ -50,7 +43,8 @@ module AMQ
|
|
50
43
|
|
51
44
|
if !@reconnecting
|
52
45
|
@reconnecting = true
|
53
|
-
|
46
|
+
|
47
|
+
self.handle_connection_interruption
|
54
48
|
self.reset
|
55
49
|
end
|
56
50
|
|
@@ -58,6 +52,9 @@ module AMQ
|
|
58
52
|
end
|
59
53
|
|
60
54
|
|
55
|
+
|
56
|
+
|
57
|
+
|
61
58
|
# Defines a callback that will be executed when AMQP connection is considered open:
|
62
59
|
# client and broker has agreed on max channel identifier and maximum allowed frame
|
63
60
|
# size and authentication succeeds. You can define more than one callback.
|
@@ -116,10 +113,18 @@ module AMQ
|
|
116
113
|
end
|
117
114
|
|
118
115
|
|
116
|
+
|
117
|
+
|
119
118
|
def initialize(*args)
|
120
119
|
super(*args)
|
120
|
+
|
121
|
+
self.logger = self.class.logger
|
122
|
+
|
123
|
+
@frames = Array.new
|
124
|
+
@channels = Hash.new
|
125
|
+
|
121
126
|
opening!
|
122
|
-
|
127
|
+
|
123
128
|
# track TCP connection state, used to detect initial TCP connection failures.
|
124
129
|
@tcp_connection_established = false
|
125
130
|
@tcp_connection_failed = false
|
@@ -127,7 +132,7 @@ module AMQ
|
|
127
132
|
|
128
133
|
# EventMachine::Connection's and Adapter's constructors arity
|
129
134
|
# make it easier to use *args. MK.
|
130
|
-
@settings = args.first
|
135
|
+
@settings = Settings.configure(args.first)
|
131
136
|
@on_tcp_connection_failure = @settings[:on_tcp_connection_failure] || Proc.new { |settings|
|
132
137
|
raise self.class.tcp_connection_failure_exception_class.new(settings)
|
133
138
|
}
|
@@ -135,9 +140,11 @@ module AMQ
|
|
135
140
|
raise self.class.authentication_failure_exception_class.new(settings)
|
136
141
|
}
|
137
142
|
|
143
|
+
@mechanism = "PLAIN"
|
144
|
+
@locale = @settings.fetch(:locale, "en_GB")
|
145
|
+
@client_properties = Settings.client_properties.merge(@settings.fetch(:client_properties, Hash.new))
|
138
146
|
|
139
147
|
self.reset
|
140
|
-
|
141
148
|
self.set_pending_connect_timeout((@settings[:timeout] || 3).to_f) unless defined?(JRUBY_VERSION)
|
142
149
|
|
143
150
|
if self.heartbeat_interval > 0
|
@@ -147,7 +154,17 @@ module AMQ
|
|
147
154
|
end # initialize(*args)
|
148
155
|
|
149
156
|
|
150
|
-
|
157
|
+
|
158
|
+
# For EventMachine adapter, this is a no-op.
|
159
|
+
# @api public
|
160
|
+
def establish_connection(settings)
|
161
|
+
# Unfortunately there doesn't seem to be any sane way
|
162
|
+
# how to get EventMachine connect to the instance level.
|
163
|
+
end
|
164
|
+
|
165
|
+
alias close disconnect
|
166
|
+
|
167
|
+
|
151
168
|
|
152
169
|
# Whether we are in authentication state (after TCP connection was estabilished
|
153
170
|
# but before broker authenticated us).
|
@@ -165,12 +182,8 @@ module AMQ
|
|
165
182
|
@tcp_connection_established
|
166
183
|
end # tcp_connection_established?
|
167
184
|
|
168
|
-
|
169
|
-
|
170
|
-
def establish_connection(settings)
|
171
|
-
# Unfortunately there doesn't seem to be any sane way
|
172
|
-
# how to get EventMachine connect to the instance level.
|
173
|
-
end
|
185
|
+
|
186
|
+
|
174
187
|
|
175
188
|
|
176
189
|
|
@@ -178,6 +191,13 @@ module AMQ
|
|
178
191
|
# Implementation
|
179
192
|
#
|
180
193
|
|
194
|
+
# Backwards compatibility with 0.7.0.a25. MK.
|
195
|
+
Deferrable = EventMachine::DefaultDeferrable
|
196
|
+
|
197
|
+
|
198
|
+
alias send_raw send_data
|
199
|
+
|
200
|
+
|
181
201
|
# EventMachine reactor callback. Is run when TCP connection is estabilished
|
182
202
|
# but before resumption of the network loop. Note that this includes cases
|
183
203
|
# when TCP connection has failed.
|
@@ -196,6 +216,8 @@ module AMQ
|
|
196
216
|
raise error
|
197
217
|
end # post_init
|
198
218
|
|
219
|
+
|
220
|
+
|
199
221
|
# Called by EventMachine reactor once TCP connection is successfully estabilished.
|
200
222
|
# @private
|
201
223
|
def connection_completed
|
@@ -236,7 +258,7 @@ module AMQ
|
|
236
258
|
closing!
|
237
259
|
@tcp_connection_established = false
|
238
260
|
|
239
|
-
|
261
|
+
self.handle_connection_interruption
|
240
262
|
@disconnection_deferrable.succeed
|
241
263
|
|
242
264
|
closed!
|
@@ -283,38 +305,43 @@ module AMQ
|
|
283
305
|
def disconnection_successful
|
284
306
|
@disconnection_deferrable.succeed
|
285
307
|
|
286
|
-
|
308
|
+
# true for "after writing buffered data"
|
309
|
+
self.close_connection(true)
|
287
310
|
self.reset
|
288
311
|
closed!
|
289
312
|
end # disconnection_successful
|
290
313
|
|
291
314
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
315
|
+
|
316
|
+
|
317
|
+
|
318
|
+
self.handle(Protocol::Connection::Start) do |connection, frame|
|
319
|
+
connection.start_ok(frame.decode_payload)
|
296
320
|
end
|
297
321
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
322
|
+
self.handle(Protocol::Connection::Tune) do |connection, frame|
|
323
|
+
connection.handle_tune(frame.decode_payload)
|
324
|
+
|
325
|
+
connection.open(connection.vhost)
|
302
326
|
end
|
303
327
|
|
328
|
+
self.handle(Protocol::Connection::OpenOk) do |connection, frame|
|
329
|
+
connection.handle_open_ok(frame.decode_payload)
|
330
|
+
end
|
304
331
|
|
305
|
-
|
332
|
+
self.handle(Protocol::Connection::Close) do |connection, frame|
|
333
|
+
connection.handle_close(frame.decode_payload)
|
334
|
+
end
|
306
335
|
|
307
|
-
|
308
|
-
|
309
|
-
|
336
|
+
self.handle(Protocol::Connection::CloseOk) do |connection, frame|
|
337
|
+
connection.handle_close_ok(frame.decode_payload)
|
338
|
+
end
|
310
339
|
|
311
|
-
# self.logger.info "[authentication] Credentials are #{username}/#{'*' * password.bytesize}"
|
312
340
|
|
313
|
-
self.connection = AMQ::Client::Connection.new(self, mechanism, self.encode_credentials(username, password), locale)
|
314
341
|
|
315
|
-
|
316
|
-
|
317
|
-
|
342
|
+
|
343
|
+
protected
|
344
|
+
|
318
345
|
|
319
346
|
def reset
|
320
347
|
@size = 0
|
@@ -322,8 +349,8 @@ module AMQ
|
|
322
349
|
@frames = Array.new
|
323
350
|
|
324
351
|
@chunk_buffer = ""
|
325
|
-
@connection_deferrable =
|
326
|
-
@disconnection_deferrable =
|
352
|
+
@connection_deferrable = EventMachine::DefaultDeferrable.new
|
353
|
+
@disconnection_deferrable = EventMachine::DefaultDeferrable.new
|
327
354
|
|
328
355
|
# used to track down whether authentication succeeded. AMQP 0.9.1 dictates
|
329
356
|
# that on authentication failure broker must close TCP connection without sending
|
@@ -332,26 +359,6 @@ module AMQ
|
|
332
359
|
@authenticating = false
|
333
360
|
end
|
334
361
|
|
335
|
-
# @see http://tools.ietf.org/rfc/rfc2595.txt RFC 2595
|
336
|
-
def encode_credentials(username, password)
|
337
|
-
"\0#{username}\0#{password}"
|
338
|
-
end # encode_credentials(username, password)
|
339
|
-
|
340
|
-
def get_next_frame
|
341
|
-
return unless @chunk_buffer.size > 7 # otherwise, cannot read the length
|
342
|
-
# octet + short
|
343
|
-
offset = 3 # 1 + 2
|
344
|
-
# length
|
345
|
-
payload_length = @chunk_buffer[offset, 4].unpack('N')[0]
|
346
|
-
# 5: 4 bytes for long payload length, 1 byte final octet
|
347
|
-
frame_length = offset + 5 + payload_length
|
348
|
-
if frame_length <= @chunk_buffer.size
|
349
|
-
@chunk_buffer.slice!(0, frame_length)
|
350
|
-
else
|
351
|
-
nil
|
352
|
-
end
|
353
|
-
end # get_next_frame
|
354
|
-
|
355
362
|
def upgrade_to_tls_if_necessary
|
356
363
|
tls_options = @settings[:ssl]
|
357
364
|
|
data/lib/amq/client/callbacks.rb
CHANGED
@@ -33,23 +33,32 @@ module AMQ
|
|
33
33
|
|
34
34
|
|
35
35
|
def exec_callback(name, *args, &block)
|
36
|
-
|
37
|
-
|
36
|
+
list = Array(self.callbacks[name])
|
37
|
+
if list.any?
|
38
|
+
list.each { |c| c.call(*args, &block) }
|
39
|
+
end
|
38
40
|
end
|
39
41
|
|
40
42
|
def exec_callback_once(name, *args, &block)
|
41
|
-
|
42
|
-
|
43
|
+
list = (self.callbacks.delete(name) || Array.new)
|
44
|
+
if list.any?
|
45
|
+
list.each { |c| c.call(*args, &block) }
|
46
|
+
end
|
43
47
|
end
|
44
48
|
|
45
49
|
def exec_callback_yielding_self(name, *args, &block)
|
46
|
-
|
47
|
-
|
50
|
+
list = Array(self.callbacks[name])
|
51
|
+
if list.any?
|
52
|
+
list.each { |c| c.call(self, *args, &block) }
|
53
|
+
end
|
48
54
|
end
|
49
55
|
|
50
56
|
def exec_callback_once_yielding_self(name, *args, &block)
|
51
|
-
|
52
|
-
|
57
|
+
list = (self.callbacks.delete(name) || Array.new)
|
58
|
+
|
59
|
+
if list.any?
|
60
|
+
list.each { |c| c.call(self, *args, &block) }
|
61
|
+
end
|
53
62
|
end
|
54
63
|
|
55
64
|
def has_callback?(name)
|
@@ -57,4 +66,4 @@ module AMQ
|
|
57
66
|
end # has_callback?
|
58
67
|
end # Callbacks
|
59
68
|
end # Client
|
60
|
-
end # AMQ
|
69
|
+
end # AMQ
|