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.
@@ -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
- socket = Socket.connect(self, settings[:host], settings[:port])
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
- @connections = []
131
- super
132
- if settings[:on_tcp_connection_failure]
133
- on_tcp_connection_failure(&settings.delete(:on_tcp_connection_failure))
134
- end
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
- # Returns next frame from buffer whenever possible
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
- attr_reader :connections
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
- @connections.each { |c| c.handle_connection_interruption }
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
- @connections = Array.new
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
- alias send_raw send_data
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
- # For EventMachine adapter, this is a no-op.
169
- # @api public
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
- @connections.each { |c| c.handle_connection_interruption }
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
- self.close_connection
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
- # Called when previously established TCP connection fails.
293
- # @api public
294
- def tcp_connection_lost
295
- @on_tcp_connection_loss.call(self, @settings) if @on_tcp_connection_loss
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
- # Called when initial TCP connection fails.
299
- # @api public
300
- def tcp_connection_failed
301
- @on_tcp_connection_failure.call(@settings) if @on_tcp_connection_failure
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
- protected
332
+ self.handle(Protocol::Connection::Close) do |connection, frame|
333
+ connection.handle_close(frame.decode_payload)
334
+ end
306
335
 
307
- def handshake(mechanism = "PLAIN", response = nil, locale = "en_GB")
308
- username = @settings[:user] || @settings[:username]
309
- password = @settings[:pass] || @settings[:password]
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
- @authenticating = true
316
- self.send_preamble
317
- end
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 = Deferrable.new
326
- @disconnection_deferrable = Deferrable.new
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
 
@@ -33,23 +33,32 @@ module AMQ
33
33
 
34
34
 
35
35
  def exec_callback(name, *args, &block)
36
- callbacks = Array(self.callbacks[name])
37
- callbacks.map { |c| c.call(*args, &block) } if callbacks.any?
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
- callbacks = Array(self.callbacks.delete(name))
42
- callbacks.map { |c| c.call(*args, &block) } if callbacks.any?
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
- callbacks = Array(self.callbacks[name])
47
- callbacks.map { |c| c.call(self, *args, &block) } if callbacks.any?
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
- callbacks = Array(self.callbacks.delete(name))
52
- callbacks.map { |c| c.call(self, *args, &block) } if callbacks.any?
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