amqp-client 1.0.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,7 @@
3
3
  require "socket"
4
4
  require "uri"
5
5
  require "openssl"
6
- require_relative "./frames"
6
+ require_relative "./frame_bytes"
7
7
  require_relative "./channel"
8
8
  require_relative "./errors"
9
9
 
@@ -13,47 +13,32 @@ module AMQP
13
13
  class Connection
14
14
  # Establish a connection to an AMQP broker
15
15
  # @param uri [String] URL on the format amqp://username:password@hostname/vhost, use amqps:// for encrypted connection
16
- # @param read_loop_thread [Boolean] Set to false if you manually want to run the {#read_loop}
16
+ # @param read_loop_thread [Boolean] If true run {#read_loop} in a background thread,
17
+ # otherwise the user have to run it explicitly, without {#read_loop} the connection won't function
17
18
  # @option options [Boolean] connection_name (PROGRAM_NAME) Set a name for the connection to be able to identify
18
19
  # the client from the broker
19
20
  # @option options [Boolean] verify_peer (true) Verify broker's TLS certificate, set to false for self-signed certs
21
+ # @option options [Integer] connect_timeout (30) TCP connection timeout
20
22
  # @option options [Integer] heartbeat (0) Heartbeat timeout, defaults to 0 and relies on TCP keepalive instead
21
23
  # @option options [Integer] frame_max (131_072) Maximum frame size,
22
24
  # the smallest of the client's and the broker's values will be used
23
25
  # @option options [Integer] channel_max (2048) Maxium number of channels the client will be allowed to have open.
24
26
  # Maxium allowed is 65_536. The smallest of the client's and the broker's value will be used.
27
+ # @option options [String] keepalive (60:10:3) TCP keepalive setting, 60s idle, 10s interval between probes, 3 probes
25
28
  # @return [Connection]
26
- def self.connect(uri, read_loop_thread: true, **options)
29
+ def initialize(uri = "", read_loop_thread: true, **options)
27
30
  uri = URI.parse(uri)
28
31
  tls = uri.scheme == "amqps"
29
32
  port = port_from_env || uri.port || (tls ? 5671 : 5672)
30
33
  host = uri.host || "localhost"
31
34
  user = uri.user || "guest"
32
35
  password = uri.password || "guest"
33
- vhost = URI.decode_www_form_component(uri.path[1..-1] || "/")
36
+ vhost = URI.decode_www_form_component(uri.path[1..] || "/")
34
37
  options = URI.decode_www_form(uri.query || "").map! { |k, v| [k.to_sym, v] }.to_h.merge(options)
35
38
 
36
- socket = Socket.tcp host, port, connect_timeout: 20, resolv_timeout: 5
37
- enable_tcp_keepalive(socket)
38
- if tls
39
- cert_store = OpenSSL::X509::Store.new
40
- cert_store.set_default_paths
41
- context = OpenSSL::SSL::SSLContext.new
42
- context.cert_store = cert_store
43
- context.verify_mode = OpenSSL::SSL::VERIFY_PEER unless [false, "false", "none"].include? options[:verify_peer]
44
- socket = OpenSSL::SSL::SSLSocket.new(socket, context)
45
- socket.sync_close = true # closing the TLS socket also closes the TCP socket
46
- socket.hostname = host # SNI host
47
- socket.connect
48
- socket.post_connection_check(host) || raise(Error, "TLS certificate hostname doesn't match requested")
49
- end
39
+ socket = open_socket(host, port, tls, options)
50
40
  channel_max, frame_max, heartbeat = establish(socket, user, password, vhost, options)
51
- Connection.new(socket, channel_max, frame_max, heartbeat, read_loop_thread: read_loop_thread)
52
- end
53
41
 
54
- # Requires an already established TCP/TLS socket
55
- # @api private
56
- def initialize(socket, channel_max, frame_max, heartbeat, read_loop_thread: true)
57
42
  @socket = socket
58
43
  @channel_max = channel_max.zero? ? 65_536 : channel_max
59
44
  @frame_max = frame_max
@@ -66,6 +51,13 @@ module AMQP
66
51
  Thread.new { read_loop } if read_loop_thread
67
52
  end
68
53
 
54
+ # Alias for {#initialize}
55
+ # @see #initialize
56
+ # @deprecated
57
+ def self.connect(uri, read_loop_thread: true, **options)
58
+ new(uri, read_loop_thread: read_loop_thread, **options)
59
+ end
60
+
69
61
  # The max frame size negotiated between the client and the broker
70
62
  # @return [Integer]
71
63
  attr_reader :frame_max
@@ -142,9 +134,13 @@ module AMQP
142
134
  warn "AMQP-Client blocked by broker: #{blocked}" if blocked
143
135
  @write_lock.synchronize do
144
136
  warn "AMQP-Client unblocked by broker" if blocked
145
- @socket.write(*bytes)
137
+ if RUBY_ENGINE == "truffleruby"
138
+ bytes.each { |b| @socket.write b }
139
+ else
140
+ @socket.write(*bytes)
141
+ end
146
142
  end
147
- rescue IOError, OpenSSL::OpenSSLError, SystemCallError => e
143
+ rescue *READ_EXCEPTIONS => e
148
144
  raise Error::ConnectionClosed.new(*@closed) if @closed
149
145
 
150
146
  raise Error, "Could not write to socket, #{e.message}"
@@ -161,12 +157,12 @@ module AMQP
161
157
  frame_start = String.new(capacity: 7)
162
158
  frame_buffer = String.new(capacity: frame_max)
163
159
  loop do
164
- socket.read(7, frame_start)
160
+ socket.read(7, frame_start) || raise(IOError)
165
161
  type, channel_id, frame_size = frame_start.unpack("C S> L>")
166
162
  frame_max >= frame_size || raise(Error, "Frame size #{frame_size} larger than negotiated max frame size #{frame_max}")
167
163
 
168
164
  # read the frame content
169
- socket.read(frame_size, frame_buffer)
165
+ socket.read(frame_size, frame_buffer) || raise(IOError)
170
166
 
171
167
  # make sure that the frame end is correct
172
168
  frame_end = socket.readchar.ord
@@ -176,21 +172,26 @@ module AMQP
176
172
  parse_frame(type, channel_id, frame_buffer) || return
177
173
  end
178
174
  nil
179
- rescue IOError, OpenSSL::OpenSSLError, SystemCallError => e
175
+ rescue *READ_EXCEPTIONS => e
180
176
  @closed ||= [400, "read error: #{e.message}"]
181
177
  nil # ignore read errors
182
178
  ensure
183
179
  @closed ||= [400, "unknown"]
184
180
  @replies.close
185
181
  begin
186
- @socket.close
187
- rescue IOError, OpenSSL::OpenSSLError, SystemCallError
182
+ @write_lock.synchronize do
183
+ @socket.close
184
+ end
185
+ rescue *READ_EXCEPTIONS
188
186
  nil
189
187
  end
190
188
  end
191
189
 
192
190
  private
193
191
 
192
+ READ_EXCEPTIONS = [IOError, OpenSSL::OpenSSLError, SystemCallError,
193
+ RUBY_ENGINE == "jruby" ? java.lang.NullPointerException : nil].compact.freeze
194
+
194
195
  def parse_frame(type, channel_id, buf)
195
196
  case type
196
197
  when 1 # method frame
@@ -216,7 +217,7 @@ module AMQP
216
217
  @replies.push [:close_ok]
217
218
  return false
218
219
  when 60 # connection#blocked
219
- reason_len = buf.unpack1("@4 C")
220
+ reason_len = buf.getbyte(4)
220
221
  reason = buf.byteslice(5, reason_len).force_encoding("utf-8")
221
222
  @blocked = reason
222
223
  @write_lock.lock
@@ -256,7 +257,7 @@ module AMQP
256
257
  when 50 # queue
257
258
  case method_id
258
259
  when 11 # declare-ok
259
- queue_name_len = buf.unpack1("@4 C")
260
+ queue_name_len = buf.getbyte(4)
260
261
  queue_name = buf.byteslice(5, queue_name_len).force_encoding("utf-8")
261
262
  message_count, consumer_count = buf.byteslice(5 + queue_name_len, 8).unpack("L> L>")
262
263
  @channels[channel_id].reply [:queue_declare_ok, queue_name, message_count, consumer_count]
@@ -276,17 +277,17 @@ module AMQP
276
277
  when 11 # qos-ok
277
278
  @channels[channel_id].reply [:basic_qos_ok]
278
279
  when 21 # consume-ok
279
- tag_len = buf.unpack1("@4 C")
280
+ tag_len = buf.getbyte(4)
280
281
  tag = buf.byteslice(5, tag_len).force_encoding("utf-8")
281
282
  @channels[channel_id].reply [:basic_consume_ok, tag]
282
283
  when 30 # cancel
283
- tag_len = buf.unpack1("@4 C")
284
+ tag_len = buf.getbyte(4)
284
285
  tag = buf.byteslice(5, tag_len).force_encoding("utf-8")
285
- no_wait = buf[5 + tag_len].ord == 1
286
+ no_wait = buf.getbyte(5 + tag_len) == 1
286
287
  @channels[channel_id].close_consumer(tag)
287
288
  write_bytes FrameBytes.basic_cancel_ok(@id, tag) unless no_wait
288
289
  when 31 # cancel-ok
289
- tag_len = buf.unpack1("@4 C")
290
+ tag_len = buf.getbyte(4)
290
291
  tag = buf.byteslice(5, tag_len).force_encoding("utf-8")
291
292
  @channels[channel_id].reply [:basic_cancel_ok, tag]
292
293
  when 50 # return
@@ -294,23 +295,23 @@ module AMQP
294
295
  pos = 7
295
296
  reply_text = buf.byteslice(pos, reply_text_len).force_encoding("utf-8")
296
297
  pos += reply_text_len
297
- exchange_len = buf[pos].ord
298
+ exchange_len = buf.getbyte(pos)
298
299
  pos += 1
299
300
  exchange = buf.byteslice(pos, exchange_len).force_encoding("utf-8")
300
301
  pos += exchange_len
301
- routing_key_len = buf[pos].ord
302
+ routing_key_len = buf.getbyte(pos)
302
303
  pos += 1
303
304
  routing_key = buf.byteslice(pos, routing_key_len).force_encoding("utf-8")
304
305
  @channels[channel_id].message_returned(reply_code, reply_text, exchange, routing_key)
305
306
  when 60 # deliver
306
- ctag_len = buf[4].ord
307
+ ctag_len = buf.getbyte(4)
307
308
  consumer_tag = buf.byteslice(5, ctag_len).force_encoding("utf-8")
308
309
  pos = 5 + ctag_len
309
310
  delivery_tag, redelivered, exchange_len = buf.byteslice(pos, 10).unpack("Q> C C")
310
311
  pos += 8 + 1 + 1
311
312
  exchange = buf.byteslice(pos, exchange_len).force_encoding("utf-8")
312
313
  pos += exchange_len
313
- rk_len = buf[pos].ord
314
+ rk_len = buf.getbyte(pos)
314
315
  pos += 1
315
316
  routing_key = buf.byteslice(pos, rk_len).force_encoding("utf-8")
316
317
  @channels[channel_id].message_delivered(consumer_tag, delivery_tag, redelivered == 1, exchange, routing_key)
@@ -319,11 +320,11 @@ module AMQP
319
320
  pos = 14
320
321
  exchange = buf.byteslice(pos, exchange_len).force_encoding("utf-8")
321
322
  pos += exchange_len
322
- routing_key_len = buf[pos].ord
323
+ routing_key_len = buf.getbyte(pos)
323
324
  pos += 1
324
325
  routing_key = buf.byteslice(pos, routing_key_len).force_encoding("utf-8")
325
- pos += routing_key_len
326
- _message_count = buf.byteslice(pos, 4).unpack1("L>")
326
+ # pos += routing_key_len
327
+ # message_count = buf.byteslice(pos, 4).unpack1("L>")
327
328
  @channels[channel_id].message_delivered(nil, delivery_tag, redelivered == 1, exchange, routing_key)
328
329
  when 72 # get-empty
329
330
  @channels[channel_id].basic_get_empty
@@ -357,7 +358,7 @@ module AMQP
357
358
  end
358
359
  when 2 # header
359
360
  body_size = buf.unpack1("@4 Q>")
360
- properties = Properties.decode(buf.byteslice(12, buf.bytesize - 12))
361
+ properties = Properties.decode(buf, 12)
361
362
  @channels[channel_id].header_delivered body_size, properties
362
363
  when 3 # body
363
364
  @channels[channel_id].body_delivered buf
@@ -377,21 +378,47 @@ module AMQP
377
378
  args
378
379
  end
379
380
 
381
+ # Connect to the host/port, optionally establish a TLS connection
382
+ # @return [Socket]
383
+ # @return [OpenSSL::SSL::SSLSocket]
384
+ def open_socket(host, port, tls, options)
385
+ connect_timeout = options.fetch(:connect_timeout, 30).to_i
386
+ socket = Socket.tcp host, port, connect_timeout: connect_timeout
387
+ keepalive = options.fetch(:keepalive, "").split(":", 3).map!(&:to_i)
388
+ enable_tcp_keepalive(socket, *keepalive)
389
+ if tls
390
+ cert_store = OpenSSL::X509::Store.new
391
+ cert_store.set_default_paths
392
+ context = OpenSSL::SSL::SSLContext.new
393
+ context.cert_store = cert_store
394
+ verify_peer = [false, "false", "none"].include? options[:verify_peer]
395
+ context.verify_mode = OpenSSL::SSL::VERIFY_PEER unless verify_peer
396
+ socket = OpenSSL::SSL::SSLSocket.new(socket, context)
397
+ socket.sync_close = true # closing the TLS socket also closes the TCP socket
398
+ socket.hostname = host # SNI host
399
+ socket.connect
400
+ socket.post_connection_check(host) || raise(Error, "TLS certificate hostname doesn't match requested")
401
+ end
402
+ socket
403
+ rescue SystemCallError, OpenSSL::OpenSSLError => e
404
+ raise Error, "Could not open a socket: #{e.message}"
405
+ end
406
+
380
407
  # Negotiate a connection
381
408
  # @return [Array<Integer, Integer, Integer>] channel_max, frame_max, heartbeat
382
- def self.establish(socket, user, password, vhost, options)
409
+ def establish(socket, user, password, vhost, options)
383
410
  channel_max, frame_max, heartbeat = nil
384
411
  socket.write "AMQP\x00\x00\x09\x01"
385
412
  buf = String.new(capacity: 4096)
386
413
  loop do
387
414
  begin
388
415
  socket.readpartial(4096, buf)
389
- rescue IOError, OpenSSL::OpenSSLError, SystemCallError => e
416
+ rescue *READ_EXCEPTIONS => e
390
417
  raise Error, "Could not establish AMQP connection: #{e.message}"
391
418
  end
392
419
 
393
420
  type, channel_id, frame_size = buf.unpack("C S> L>")
394
- frame_end = buf[frame_size + 7].ord
421
+ frame_end = buf.getbyte(frame_size + 7)
395
422
  raise UnexpectedFrameEndError, frame_end if frame_end != 206
396
423
 
397
424
  case type
@@ -428,32 +455,42 @@ module AMQP
428
455
  else raise Error, "Unexpected frame type: #{type}"
429
456
  end
430
457
  end
431
- rescue StandardError => e
458
+ rescue Exception => e
432
459
  begin
433
460
  socket.close
434
- rescue IOError, OpenSSL::OpenSSLError, SystemCallError
461
+ rescue *READ_EXCEPTIONS
435
462
  nil
436
463
  end
437
464
  raise e
438
465
  end
439
466
 
440
- def self.enable_tcp_keepalive(socket)
467
+ # Enable TCP keepalive, which is prefered to heartbeats
468
+ # @return [void]
469
+ def enable_tcp_keepalive(socket, idle = 60, interval = 10, count = 3)
441
470
  socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
442
- socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE, 60)
443
- socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL, 10)
444
- socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT, 3)
471
+ if Socket.const_defined?(:TCP_KEEPIDLE) # linux/bsd
472
+ socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPIDLE, idle)
473
+ elsif RUBY_PLATFORM.include? "darwin" # os x
474
+ # https://www.quickhack.net/nom/blog/2018-01-19-enable-tcp-keepalive-of-macos-and-linux-in-ruby.html
475
+ socket.setsockopt(Socket::IPPROTO_TCP, 0x10, idle)
476
+ else # windows
477
+ return
478
+ end
479
+ socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPINTVL, interval)
480
+ socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPCNT, count)
445
481
  rescue StandardError => e
446
482
  warn "AMQP-Client could not enable TCP keepalive on socket. #{e.inspect}"
447
483
  end
448
484
 
449
- def self.port_from_env
485
+ # Fetch the AMQP port number from ENV
486
+ # @return [Integer] A port number
487
+ # @return [nil] When the environment variable AMQP_PORT isn't set
488
+ def port_from_env
450
489
  return unless (port = ENV["AMQP_PORT"])
451
490
 
452
491
  port.to_i
453
492
  end
454
493
 
455
- private_class_method :establish, :enable_tcp_keepalive, :port_from_env
456
-
457
494
  CLIENT_PROPERTIES = {
458
495
  capabilities: {
459
496
  authentication_failure_close: true,
@@ -10,9 +10,7 @@ module AMQP
10
10
  # Having a class for each frame type is more expensive in terms of CPU and memory
11
11
  # @api private
12
12
  module FrameBytes
13
- module_function
14
-
15
- def connection_start_ok(response, properties)
13
+ def self.connection_start_ok(response, properties)
16
14
  prop_tbl = Table.encode(properties)
17
15
  [
18
16
  1, # type: method
@@ -28,7 +26,7 @@ module AMQP
28
26
  ].pack("C S> L> S> S> L>a* Ca* L>a* Ca* C")
29
27
  end
30
28
 
31
- def connection_tune_ok(channel_max, frame_max, heartbeat)
29
+ def self.connection_tune_ok(channel_max, frame_max, heartbeat)
32
30
  [
33
31
  1, # type: method
34
32
  0, # channel id
@@ -42,7 +40,7 @@ module AMQP
42
40
  ].pack("CS>L>S>S>S>L>S>C")
43
41
  end
44
42
 
45
- def connection_open(vhost)
43
+ def self.connection_open(vhost)
46
44
  [
47
45
  1, # type: method
48
46
  0, # channel id
@@ -56,7 +54,7 @@ module AMQP
56
54
  ].pack("C S> L> S> S> Ca* CCC")
57
55
  end
58
56
 
59
- def connection_close(code, reason)
57
+ def self.connection_close(code, reason)
60
58
  frame_size = 2 + 2 + 2 + 1 + reason.bytesize + 2 + 2
61
59
  [
62
60
  1, # type: method
@@ -72,7 +70,7 @@ module AMQP
72
70
  ].pack("C S> L> S> S> S> Ca* S> S> C")
73
71
  end
74
72
 
75
- def connection_close_ok
73
+ def self.connection_close_ok
76
74
  [
77
75
  1, # type: method
78
76
  0, # channel id
@@ -83,7 +81,7 @@ module AMQP
83
81
  ].pack("C S> L> S> S> C")
84
82
  end
85
83
 
86
- def channel_open(id)
84
+ def self.channel_open(id)
87
85
  [
88
86
  1, # type: method
89
87
  id, # channel id
@@ -95,7 +93,7 @@ module AMQP
95
93
  ].pack("C S> L> S> S> C C")
96
94
  end
97
95
 
98
- def channel_close(id, reason, code)
96
+ def self.channel_close(id, reason, code)
99
97
  frame_size = 2 + 2 + 2 + 1 + reason.bytesize + 2 + 2
100
98
  [
101
99
  1, # type: method
@@ -111,7 +109,7 @@ module AMQP
111
109
  ].pack("C S> L> S> S> S> Ca* S> S> C")
112
110
  end
113
111
 
114
- def channel_close_ok(id)
112
+ def self.channel_close_ok(id)
115
113
  [
116
114
  1, # type: method
117
115
  id, # channel id
@@ -122,7 +120,7 @@ module AMQP
122
120
  ].pack("C S> L> S> S> C")
123
121
  end
124
122
 
125
- def exchange_declare(id, name, type, passive, durable, auto_delete, internal, arguments)
123
+ def self.exchange_declare(id, name, type, passive, durable, auto_delete, internal, arguments)
126
124
  no_wait = false
127
125
  bits = 0
128
126
  bits |= (1 << 0) if passive
@@ -147,7 +145,7 @@ module AMQP
147
145
  ].pack("C S> L> S> S> S> Ca* Ca* C L>a* C")
148
146
  end
149
147
 
150
- def exchange_delete(id, name, if_unused, no_wait)
148
+ def self.exchange_delete(id, name, if_unused, no_wait)
151
149
  bits = 0
152
150
  bits |= (1 << 0) if if_unused
153
151
  bits |= (1 << 1) if no_wait
@@ -165,7 +163,7 @@ module AMQP
165
163
  ].pack("C S> L> S> S> S> Ca* C C")
166
164
  end
167
165
 
168
- def exchange_bind(id, destination, source, binding_key, no_wait, arguments)
166
+ def self.exchange_bind(id, destination, source, binding_key, no_wait, arguments)
169
167
  tbl = Table.encode(arguments)
170
168
  frame_size = 2 + 2 + 2 + 1 + destination.bytesize + 1 + source.bytesize + 1 +
171
169
  binding_key.bytesize + 1 + 4 + tbl.bytesize
@@ -185,7 +183,7 @@ module AMQP
185
183
  ].pack("C S> L> S> S> S> Ca* Ca* Ca* C L>a* C")
186
184
  end
187
185
 
188
- def exchange_unbind(id, destination, source, binding_key, no_wait, arguments)
186
+ def self.exchange_unbind(id, destination, source, binding_key, no_wait, arguments)
189
187
  tbl = Table.encode(arguments)
190
188
  frame_size = 2 + 2 + 2 + 1 + destination.bytesize + 1 + source.bytesize + 1 +
191
189
  binding_key.bytesize + 1 + 4 + tbl.bytesize
@@ -205,7 +203,7 @@ module AMQP
205
203
  ].pack("C S> L> S> S> S> Ca* Ca* Ca* C L>a* C")
206
204
  end
207
205
 
208
- def queue_declare(id, name, passive, durable, exclusive, auto_delete, arguments)
206
+ def self.queue_declare(id, name, passive, durable, exclusive, auto_delete, arguments)
209
207
  no_wait = false
210
208
  bits = 0
211
209
  bits |= (1 << 0) if passive
@@ -229,7 +227,7 @@ module AMQP
229
227
  ].pack("C S> L> S> S> S> Ca* C L>a* C")
230
228
  end
231
229
 
232
- def queue_delete(id, name, if_unused, if_empty, no_wait)
230
+ def self.queue_delete(id, name, if_unused, if_empty, no_wait)
233
231
  bits = 0
234
232
  bits |= (1 << 0) if if_unused
235
233
  bits |= (1 << 1) if if_empty
@@ -248,7 +246,7 @@ module AMQP
248
246
  ].pack("C S> L> S> S> S> Ca* C C")
249
247
  end
250
248
 
251
- def queue_bind(id, queue, exchange, binding_key, no_wait, arguments)
249
+ def self.queue_bind(id, queue, exchange, binding_key, no_wait, arguments)
252
250
  tbl = Table.encode(arguments)
253
251
  frame_size = 2 + 2 + 2 + 1 + queue.bytesize + 1 + exchange.bytesize + 1 +
254
252
  binding_key.bytesize + 1 + 4 + tbl.bytesize
@@ -268,7 +266,7 @@ module AMQP
268
266
  ].pack("C S> L> S> S> S> Ca* Ca* Ca* C L>a* C")
269
267
  end
270
268
 
271
- def queue_unbind(id, queue, exchange, binding_key, arguments)
269
+ def self.queue_unbind(id, queue, exchange, binding_key, arguments)
272
270
  tbl = Table.encode(arguments)
273
271
  frame_size = 2 + 2 + 2 + 1 + queue.bytesize + 1 + exchange.bytesize + 1 +
274
272
  binding_key.bytesize + 4 + tbl.bytesize
@@ -287,7 +285,7 @@ module AMQP
287
285
  ].pack("C S> L> S> S> S> Ca* Ca* Ca* L>a* C")
288
286
  end
289
287
 
290
- def queue_purge(id, queue, no_wait)
288
+ def self.queue_purge(id, queue, no_wait)
291
289
  frame_size = 2 + 2 + 2 + 1 + queue.bytesize + 1
292
290
  [
293
291
  1, # type: method
@@ -302,7 +300,7 @@ module AMQP
302
300
  ].pack("C S> L> S> S> S> Ca* C C")
303
301
  end
304
302
 
305
- def basic_get(id, queue, no_ack)
303
+ def self.basic_get(id, queue, no_ack)
306
304
  frame_size = 2 + 2 + 2 + 1 + queue.bytesize + 1
307
305
  [
308
306
  1, # type: method
@@ -317,7 +315,7 @@ module AMQP
317
315
  ].pack("C S> L> S> S> S> Ca* C C")
318
316
  end
319
317
 
320
- def basic_publish(id, exchange, routing_key, mandatory)
318
+ def self.basic_publish(id, exchange, routing_key, mandatory)
321
319
  frame_size = 2 + 2 + 2 + 1 + exchange.bytesize + 1 + routing_key.bytesize + 1
322
320
  [
323
321
  1, # type: method
@@ -333,8 +331,8 @@ module AMQP
333
331
  ].pack("C S> L> S> S> S> Ca* Ca* C C")
334
332
  end
335
333
 
336
- def header(id, body_size, properties)
337
- props = Properties.new(**properties).encode
334
+ def self.header(id, body_size, properties)
335
+ props = Properties.encode(properties)
338
336
  frame_size = 2 + 2 + 8 + props.bytesize
339
337
  [
340
338
  2, # type: header
@@ -348,7 +346,7 @@ module AMQP
348
346
  ].pack("C S> L> S> S> Q> a* C")
349
347
  end
350
348
 
351
- def body(id, body_part)
349
+ def self.body(id, body_part)
352
350
  [
353
351
  3, # type: body
354
352
  id, # channel id
@@ -358,7 +356,7 @@ module AMQP
358
356
  ].pack("C S> L> a* C")
359
357
  end
360
358
 
361
- def basic_consume(id, queue, tag, no_ack, exclusive, arguments)
359
+ def self.basic_consume(id, queue, tag, no_ack, exclusive, arguments)
362
360
  no_local = false
363
361
  no_wait = false
364
362
  bits = 0
@@ -383,7 +381,7 @@ module AMQP
383
381
  ].pack("C S> L> S> S> S> Ca* Ca* C L>a* C")
384
382
  end
385
383
 
386
- def basic_cancel(id, consumer_tag, no_wait: false)
384
+ def self.basic_cancel(id, consumer_tag, no_wait: false)
387
385
  frame_size = 2 + 2 + 1 + consumer_tag.bytesize + 1
388
386
  [
389
387
  1, # type: method
@@ -397,7 +395,7 @@ module AMQP
397
395
  ].pack("C S> L> S> S> Ca* C C")
398
396
  end
399
397
 
400
- def basic_cancel_ok(id, consumer_tag)
398
+ def self.basic_cancel_ok(id, consumer_tag)
401
399
  frame_size = 2 + 2 + 1 + consumer_tag.bytesize + 1
402
400
  [
403
401
  1, # type: method
@@ -410,7 +408,7 @@ module AMQP
410
408
  ].pack("C S> L> S> S> Ca* C")
411
409
  end
412
410
 
413
- def basic_ack(id, delivery_tag, multiple)
411
+ def self.basic_ack(id, delivery_tag, multiple)
414
412
  frame_size = 2 + 2 + 8 + 1
415
413
  [
416
414
  1, # type: method
@@ -424,7 +422,7 @@ module AMQP
424
422
  ].pack("C S> L> S> S> Q> C C")
425
423
  end
426
424
 
427
- def basic_nack(id, delivery_tag, multiple, requeue)
425
+ def self.basic_nack(id, delivery_tag, multiple, requeue)
428
426
  bits = 0
429
427
  bits |= (1 << 0) if multiple
430
428
  bits |= (1 << 1) if requeue
@@ -441,7 +439,7 @@ module AMQP
441
439
  ].pack("C S> L> S> S> Q> C C")
442
440
  end
443
441
 
444
- def basic_reject(id, delivery_tag, requeue)
442
+ def self.basic_reject(id, delivery_tag, requeue)
445
443
  frame_size = 2 + 2 + 8 + 1
446
444
  [
447
445
  1, # type: method
@@ -455,7 +453,7 @@ module AMQP
455
453
  ].pack("C S> L> S> S> Q> C C")
456
454
  end
457
455
 
458
- def basic_qos(id, prefetch_size, prefetch_count, global)
456
+ def self.basic_qos(id, prefetch_size, prefetch_count, global)
459
457
  frame_size = 2 + 2 + 4 + 2 + 1
460
458
  [
461
459
  1, # type: method
@@ -470,7 +468,7 @@ module AMQP
470
468
  ].pack("C S> L> S> S> L> S> C C")
471
469
  end
472
470
 
473
- def basic_recover(id, requeue)
471
+ def self.basic_recover(id, requeue)
474
472
  frame_size = 2 + 2 + 1
475
473
  [
476
474
  1, # type: method
@@ -483,7 +481,7 @@ module AMQP
483
481
  ].pack("C S> L> S> S> C C")
484
482
  end
485
483
 
486
- def confirm_select(id, no_wait)
484
+ def self.confirm_select(id, no_wait)
487
485
  [
488
486
  1, # type: method
489
487
  id, # channel id
@@ -495,7 +493,7 @@ module AMQP
495
493
  ].pack("C S> L> S> S> C C")
496
494
  end
497
495
 
498
- def tx_select(id)
496
+ def self.tx_select(id)
499
497
  frame_size = 2 + 2
500
498
  [
501
499
  1, # type: method
@@ -507,7 +505,7 @@ module AMQP
507
505
  ].pack("C S> L> S> S> C")
508
506
  end
509
507
 
510
- def tx_commit(id)
508
+ def self.tx_commit(id)
511
509
  frame_size = 2 + 2
512
510
  [
513
511
  1, # type: method
@@ -519,7 +517,7 @@ module AMQP
519
517
  ].pack("C S> L> S> S> C")
520
518
  end
521
519
 
522
- def tx_rollback(id)
520
+ def self.tx_rollback(id)
523
521
  frame_size = 2 + 2
524
522
  [
525
523
  1, # type: method