amqp-client 0.2.0 → 0.3.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/lib/amqp-client.rb +3 -0
- data/lib/amqp/client.rb +2 -2
- data/lib/amqp/client/channel.rb +34 -22
- data/lib/amqp/client/connection.rb +11 -7
- data/lib/amqp/client/properties.rb +2 -1
- data/lib/amqp/client/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 30006ba97b26d7e73cf9503841e2248744db3d9e86d1a32fe4c9abecd9ee69f7
|
4
|
+
data.tar.gz: a59d667d971da49c2657e57efe385853adbef958fd191a01f0d1f4dbaaa1b8a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ddb8f409abf9e773a6551ff53629b702e8324ea7ff794f6b14f09ef9dd7cb27a752e853bb312a8d9da88b826a7714e84006d5bb01b5efeef7bbaed56f14323a
|
7
|
+
data.tar.gz: 642e332c0a031d27d7f364b66e0ae5beefef4bad402336f24052eef2679e306eec219369d7b8b2c1d8324eabafd0c40d45aa8feb474c3cd11ddc4578203f5bea
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.3.0] - 2021-08-20
|
4
|
+
|
5
|
+
- Channel#wait_for_confirms is a smarter way of waiting for publish confirms
|
6
|
+
- Default connection_name to $PROGRAM_NAME
|
7
|
+
|
8
|
+
## [0.2.3] - 2021-08-19
|
9
|
+
|
10
|
+
- Improved TLS/AMQPS support
|
11
|
+
|
12
|
+
## [0.2.2] - 2021-08-19
|
13
|
+
|
14
|
+
- TLS port issue fixed
|
15
|
+
|
16
|
+
## [0.2.1] - 2021-08-19
|
17
|
+
|
18
|
+
- More arguments to be passed to AMQP::Client::Queue
|
19
|
+
- Can require with 'amqp-client'
|
3
20
|
|
4
21
|
## [0.2.0] - 2021-08-19
|
5
22
|
|
data/lib/amqp-client.rb
ADDED
data/lib/amqp/client.rb
CHANGED
@@ -123,8 +123,8 @@ module AMQP
|
|
123
123
|
self
|
124
124
|
end
|
125
125
|
|
126
|
-
def subscribe(prefetch: 1, arguments: {}, &blk)
|
127
|
-
@client.subscribe(@name, prefetch: prefetch, arguments: arguments, &blk)
|
126
|
+
def subscribe(no_ack: false, prefetch: 1, worker_threads: 1, arguments: {}, &blk)
|
127
|
+
@client.subscribe(@name, no_ack: no_ack, prefetch: prefetch, worker_threads: worker_threads, arguments: arguments, &blk)
|
128
128
|
self
|
129
129
|
end
|
130
130
|
|
data/lib/amqp/client/channel.rb
CHANGED
@@ -6,15 +6,16 @@ module AMQP
|
|
6
6
|
# AMQP Channel
|
7
7
|
class Channel
|
8
8
|
def initialize(connection, id)
|
9
|
-
@replies = ::Queue.new
|
10
9
|
@connection = connection
|
11
10
|
@id = id
|
11
|
+
@replies = ::Queue.new
|
12
12
|
@consumers = {}
|
13
|
-
@confirm = nil
|
14
|
-
@last_confirmed = 0
|
15
13
|
@closed = nil
|
16
|
-
@on_return = nil
|
17
14
|
@open = false
|
15
|
+
@on_return = nil
|
16
|
+
@confirm = nil
|
17
|
+
@unconfirmed = ::Queue.new
|
18
|
+
@unconfirmed_empty = ::Queue.new
|
18
19
|
end
|
19
20
|
|
20
21
|
attr_reader :id, :consumers
|
@@ -124,15 +125,17 @@ module AMQP
|
|
124
125
|
def basic_publish(body, exchange, routing_key, **properties)
|
125
126
|
frame_max = @connection.frame_max - 8
|
126
127
|
id = @id
|
128
|
+
mandatory = properties.delete(:mandatory) || false
|
127
129
|
|
128
130
|
if 0 < body.bytesize && body.bytesize <= frame_max
|
129
|
-
write_bytes FrameBytes.basic_publish(id, exchange, routing_key,
|
131
|
+
write_bytes FrameBytes.basic_publish(id, exchange, routing_key, mandatory),
|
130
132
|
FrameBytes.header(id, body.bytesize, properties),
|
131
133
|
FrameBytes.body(id, body)
|
132
|
-
|
134
|
+
@unconfirmed.push @confirm += 1 if @confirm
|
135
|
+
return
|
133
136
|
end
|
134
137
|
|
135
|
-
write_bytes FrameBytes.basic_publish(id, exchange, routing_key,
|
138
|
+
write_bytes FrameBytes.basic_publish(id, exchange, routing_key, mandatory),
|
136
139
|
FrameBytes.header(id, body.bytesize, properties)
|
137
140
|
pos = 0
|
138
141
|
while pos < body.bytesize # split body into multiple frame_max frames
|
@@ -141,13 +144,14 @@ module AMQP
|
|
141
144
|
write_bytes FrameBytes.body(id, body_part)
|
142
145
|
pos += len
|
143
146
|
end
|
144
|
-
@confirm += 1 if @confirm
|
147
|
+
@unconfirmed.push @confirm += 1 if @confirm
|
148
|
+
nil
|
145
149
|
end
|
146
150
|
|
147
151
|
def basic_publish_confirm(body, exchange, routing_key, **properties)
|
148
152
|
confirm_select(no_wait: true)
|
149
|
-
|
150
|
-
|
153
|
+
basic_publish(body, exchange, routing_key, **properties)
|
154
|
+
wait_for_confirms
|
151
155
|
end
|
152
156
|
|
153
157
|
# Consume from a queue
|
@@ -211,20 +215,32 @@ module AMQP
|
|
211
215
|
|
212
216
|
write_bytes FrameBytes.confirm_select(@id, no_wait)
|
213
217
|
expect :confirm_select_ok unless no_wait
|
214
|
-
@confirms = ::Queue.new
|
215
218
|
@confirm = 0
|
216
219
|
end
|
217
220
|
|
218
|
-
|
219
|
-
|
220
|
-
return true if @
|
221
|
+
# Block until all publishes messages are confirmed
|
222
|
+
def wait_for_confirms
|
223
|
+
return true if @unconfirmed.empty?
|
224
|
+
|
225
|
+
@unconfirmed_empty.pop
|
226
|
+
end
|
221
227
|
|
228
|
+
def confirm(args)
|
229
|
+
ack_or_nack, delivery_tag, multiple = *args
|
222
230
|
loop do
|
223
|
-
|
224
|
-
|
225
|
-
|
231
|
+
tag = @unconfirmed.pop(true)
|
232
|
+
break if tag == delivery_tag
|
233
|
+
next if multiple && tag < delivery_tag
|
234
|
+
|
235
|
+
@unconfirmed << tag # requeue
|
236
|
+
rescue ThreadError
|
237
|
+
break
|
238
|
+
end
|
239
|
+
return unless @unconfirmed.empty?
|
240
|
+
|
241
|
+
@unconfirmed_empty.num_waiting.times do
|
242
|
+
@unconfirmed_empty << ack_or_nack == :ack
|
226
243
|
end
|
227
|
-
false
|
228
244
|
end
|
229
245
|
|
230
246
|
def tx_select
|
@@ -246,10 +262,6 @@ module AMQP
|
|
246
262
|
@replies.push(args)
|
247
263
|
end
|
248
264
|
|
249
|
-
def confirm(args)
|
250
|
-
@confirms.push(args)
|
251
|
-
end
|
252
|
-
|
253
265
|
def message_returned(reply_code, reply_text, exchange, routing_key)
|
254
266
|
Thread.new do
|
255
267
|
body_size, properties = expect(:header)
|
@@ -15,7 +15,7 @@ module AMQP
|
|
15
15
|
|
16
16
|
uri = URI.parse(uri)
|
17
17
|
tls = uri.scheme == "amqps"
|
18
|
-
port = port_from_env || uri.port || (
|
18
|
+
port = port_from_env || uri.port || (tls ? 5671 : 5672)
|
19
19
|
host = uri.host || "localhost"
|
20
20
|
user = uri.user || "guest"
|
21
21
|
password = uri.password || "guest"
|
@@ -25,10 +25,15 @@ module AMQP
|
|
25
25
|
socket = Socket.tcp host, port, connect_timeout: 20, resolv_timeout: 5
|
26
26
|
enable_tcp_keepalive(socket)
|
27
27
|
if tls
|
28
|
+
cert_store = OpenSSL::X509::Store.new
|
29
|
+
cert_store.set_default_paths
|
28
30
|
context = OpenSSL::SSL::SSLContext.new
|
31
|
+
context.cert_store = cert_store
|
29
32
|
context.verify_mode = OpenSSL::SSL::VERIFY_PEER unless [false, "false", "none"].include? options[:verify_peer]
|
30
33
|
socket = OpenSSL::SSL::SSLSocket.new(socket, context)
|
31
34
|
socket.sync_close = true # closing the TLS socket also closes the TCP socket
|
35
|
+
socket.hostname = host # SNI host
|
36
|
+
socket.connect
|
32
37
|
end
|
33
38
|
channel_max, frame_max, heartbeat = establish(socket, user, password, vhost, **options)
|
34
39
|
Connection.new(socket, channel_max, frame_max, heartbeat, read_loop_thread: read_loop_thread)
|
@@ -159,7 +164,8 @@ module AMQP
|
|
159
164
|
channel = @channels.delete(channel_id)
|
160
165
|
channel.closed!(reply_code, reply_text, classid, methodid)
|
161
166
|
when 41 # channel#close-ok
|
162
|
-
@channels
|
167
|
+
channel = @channels.delete(channel_id)
|
168
|
+
channel.reply [:channel_close_ok]
|
163
169
|
else raise AMQP::Client::UnsupportedMethodFrame, class_id, method_id
|
164
170
|
end
|
165
171
|
when 40 # exchange
|
@@ -258,10 +264,7 @@ module AMQP
|
|
258
264
|
@channels[channel_id].reply [:basic_get_empty]
|
259
265
|
when 80 # ack
|
260
266
|
delivery_tag, multiple = buf.unpack("@11 Q> C")
|
261
|
-
@channels[channel_id].confirm [:ack, delivery_tag, multiple]
|
262
|
-
when 90 # reject
|
263
|
-
delivery_tag, requeue = buf.unpack("@11 Q> C")
|
264
|
-
@channels[channel_id].confirm [:reject, delivery_tag, requeue == 1]
|
267
|
+
@channels[channel_id].confirm [:ack, delivery_tag, multiple == 1]
|
265
268
|
when 111 # recover-ok
|
266
269
|
@channels[channel_id].reply [:basic_recover_ok]
|
267
270
|
when 120 # nack
|
@@ -329,7 +332,8 @@ module AMQP
|
|
329
332
|
|
330
333
|
case method_id
|
331
334
|
when 10 # connection#start
|
332
|
-
|
335
|
+
conn_name = options[:connection_name] || $PROGRAM_NAME
|
336
|
+
properties = CLIENT_PROPERTIES.merge({ connection_name: conn_name })
|
333
337
|
socket.write FrameBytes.connection_start_ok "\u0000#{user}\u0000#{password}", properties
|
334
338
|
when 30 # connection#tune
|
335
339
|
channel_max, frame_max, heartbeat = buf.unpack("@11 S> L> S>")
|
@@ -69,7 +69,8 @@ module AMQP
|
|
69
69
|
end
|
70
70
|
|
71
71
|
if expiration
|
72
|
-
expiration
|
72
|
+
expiration = expiration.to_s if expiration.is_a?(Integer)
|
73
|
+
expiration.is_a?(String) || raise(ArgumentError, "expiration must be a string or integer")
|
73
74
|
|
74
75
|
flags |= (1 << 8)
|
75
76
|
arr << expiration.bytesize << expiration
|
data/lib/amqp/client/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amqp-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carl Hörberg
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-08-
|
11
|
+
date: 2021-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Work in progress
|
14
14
|
email:
|
@@ -29,6 +29,7 @@ files:
|
|
29
29
|
- amqp-client.gemspec
|
30
30
|
- bin/console
|
31
31
|
- bin/setup
|
32
|
+
- lib/amqp-client.rb
|
32
33
|
- lib/amqp/client.rb
|
33
34
|
- lib/amqp/client/channel.rb
|
34
35
|
- lib/amqp/client/connection.rb
|