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