amqp-client 0.2.2 → 1.0.1

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.
@@ -1,15 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AMQP
4
- Message = Struct.new(:channel, :delivery_tag, :exchange_name, :routing_key, :properties, :body, :redelivered, :consumer_tag) do
5
- def ack
6
- channel.basic_ack(delivery_tag)
7
- end
4
+ class Client
5
+ # A message delivered from the broker
6
+ # @!attribute channel
7
+ # @return [Connection::Channel] The channel the message was deliviered to
8
+ # @!attribute delivery_tag
9
+ # @return [Integer] The delivery tag of the message, used for acknowledge or reject the message
10
+ # @!attribute exchange_name
11
+ # @return [String] Name of the exchange the message was published to
12
+ # @!attribute routing_key
13
+ # @return [String] The routing key the message was published with
14
+ # @!attribute properties
15
+ # @return [Properties]
16
+ # @!attribute body
17
+ # @return [String] The message body
18
+ # @!attribute redelivered
19
+ # @return [Boolean] True if the message have been delivered before
20
+ # @!attribute consumer_tag
21
+ # @return [String] The tag of the consumer the message was deliviered to
22
+ # @return [nil] Nil if the message was polled and not deliviered to a consumer
23
+ Message =
24
+ Struct.new(:channel, :delivery_tag, :exchange_name, :routing_key, :properties, :body, :redelivered, :consumer_tag) do
25
+ # Acknowledge the message
26
+ # @return [nil]
27
+ def ack
28
+ channel.basic_ack(delivery_tag)
29
+ end
8
30
 
9
- def reject(requeue: false)
10
- channel.basic_reject(delivery_tag, requeue)
11
- end
12
- end
31
+ # Reject the message
32
+ # @param requeue [Boolean] If true the message will be put back into the queue again, ready to be redelivered
33
+ # @return [nil]
34
+ def reject(requeue: false)
35
+ channel.basic_reject(delivery_tag, requeue: requeue)
36
+ end
37
+ end
13
38
 
14
- ReturnMessage = Struct.new(:reply_code, :reply_text, :exchange, :routing_key, :properties, :body)
39
+ # A published message returned by the broker due to some error
40
+ # @!attribute reply_code
41
+ # @return [Integer] Error code
42
+ # @!attribute reply_text
43
+ # @return [String] Description on why the message was returned
44
+ # @!attribute exchange
45
+ # @return [String] Name of the exchange the message was published to
46
+ # @!attribute routing_key
47
+ # @return [String] The routing key the message was published with
48
+ # @!attribute properties
49
+ # @return [Properties]
50
+ # @!attribute body
51
+ # @return [String] The message body
52
+ ReturnMessage = Struct.new(:reply_code, :reply_text, :exchange, :routing_key, :properties, :body)
53
+ end
15
54
  end
@@ -3,199 +3,234 @@
3
3
  require_relative "./table"
4
4
 
5
5
  module AMQP
6
- # Encode/decode AMQP Properties
7
- Properties = Struct.new(:content_type, :content_encoding, :headers, :delivery_mode, :priority, :correlation_id,
8
- :reply_to, :expiration, :message_id, :timestamp, :type, :user_id, :app_id,
9
- keyword_init: true) do
10
- def encode
11
- flags = 0
12
- arr = [flags]
13
- fmt = String.new("S>")
14
-
15
- if content_type
16
- content_type.is_a?(String) || raise(ArgumentError, "content_type must be a string")
17
-
18
- flags |= (1 << 15)
19
- arr << content_type.bytesize << content_type
20
- fmt << "Ca*"
6
+ class Client
7
+ # Encode/decode AMQP Properties
8
+ # @!attribute content_type
9
+ # @return [String] Content type of the message body
10
+ # @!attribute content_encoding
11
+ # @return [String] Content encoding of the body
12
+ # @!attribute headers
13
+ # @return [Hash<String, Object>] Custom headers
14
+ # @!attribute delivery_mode
15
+ # @return [Integer] 2 for persisted message, transient messages for all other values
16
+ # @!attribute priority
17
+ # @return [Integer] A priority of the message (between 0 and 255)
18
+ # @!attribute correlation_id
19
+ # @return [Integer] A correlation id, most often used used for RPC communication
20
+ # @!attribute reply_to
21
+ # @return [String] Queue to reply RPC responses to
22
+ # @!attribute expiration
23
+ # @return [Integer, String] Number of seconds the message will stay in the queue
24
+ # @!attribute message_id
25
+ # @return [String]
26
+ # @!attribute timestamp
27
+ # @return [Date] User-definable, but often used for the time the message was originally generated
28
+ # @!attribute type
29
+ # @return [String] User-definable, but can can indicate what kind of message this is
30
+ # @!attribute user_id
31
+ # @return [String] User-definable, but can be used to verify that this is the user that published the message
32
+ # @!attribute app_id
33
+ # @return [String] User-definable, but often indicates which app that generated the message
34
+ Properties = Struct.new(:content_type, :content_encoding, :headers, :delivery_mode, :priority, :correlation_id,
35
+ :reply_to, :expiration, :message_id, :timestamp, :type, :user_id, :app_id,
36
+ keyword_init: true) do
37
+ # Encode properties into a byte array
38
+ # @return [String] byte array
39
+ def encode
40
+ flags = 0
41
+ arr = [flags]
42
+ fmt = StringIO.new(String.new("S>", capacity: 35))
43
+ fmt.pos = 2
44
+
45
+ if content_type
46
+ content_type.is_a?(String) || raise(ArgumentError, "content_type must be a string")
47
+
48
+ flags |= (1 << 15)
49
+ arr << content_type.bytesize << content_type
50
+ fmt << "Ca*"
51
+ end
52
+
53
+ if content_encoding
54
+ content_encoding.is_a?(String) || raise(ArgumentError, "content_encoding must be a string")
55
+
56
+ flags |= (1 << 14)
57
+ arr << content_encoding.bytesize << content_encoding
58
+ fmt << "Ca*"
59
+ end
60
+
61
+ if headers
62
+ headers.is_a?(Hash) || raise(ArgumentError, "headers must be a hash")
63
+
64
+ flags |= (1 << 13)
65
+ tbl = Table.encode(headers)
66
+ arr << tbl.bytesize << tbl
67
+ fmt << "L>a*"
68
+ end
69
+
70
+ if delivery_mode
71
+ delivery_mode.is_a?(Integer) || raise(ArgumentError, "delivery_mode must be an int")
72
+ delivery_mode.between?(0, 2) || raise(ArgumentError, "delivery_mode must be be between 0 and 2")
73
+
74
+ flags |= (1 << 12)
75
+ arr << delivery_mode
76
+ fmt << "C"
77
+ end
78
+
79
+ if priority
80
+ priority.is_a?(Integer) || raise(ArgumentError, "priority must be an int")
81
+ flags |= (1 << 11)
82
+ arr << priority
83
+ fmt << "C"
84
+ end
85
+
86
+ if correlation_id
87
+ priority.is_a?(String) || raise(ArgumentError, "correlation_id must be a string")
88
+
89
+ flags |= (1 << 10)
90
+ arr << correlation_id.bytesize << correlation_id
91
+ fmt << "Ca*"
92
+ end
93
+
94
+ if reply_to
95
+ reply_to.is_a?(String) || raise(ArgumentError, "reply_to must be a string")
96
+
97
+ flags |= (1 << 9)
98
+ arr << reply_to.bytesize << reply_to
99
+ fmt << "Ca*"
100
+ end
101
+
102
+ if expiration
103
+ self.expiration = expiration.to_s if expiration.is_a?(Integer)
104
+ expiration.is_a?(String) || raise(ArgumentError, "expiration must be a string or integer")
105
+
106
+ flags |= (1 << 8)
107
+ arr << expiration.bytesize << expiration
108
+ fmt << "Ca*"
109
+ end
110
+
111
+ if message_id
112
+ message_id.is_a?(String) || raise(ArgumentError, "message_id must be a string")
113
+
114
+ flags |= (1 << 7)
115
+ arr << message_id.bytesize << message_id
116
+ fmt << "Ca*"
117
+ end
118
+
119
+ if timestamp
120
+ timestamp.is_a?(Integer) || timestamp.is_a?(Time) || raise(ArgumentError, "timestamp must be an Integer or a Time")
121
+
122
+ flags |= (1 << 6)
123
+ arr << timestamp.to_i
124
+ fmt << "Q>"
125
+ end
126
+
127
+ if type
128
+ type.is_a?(String) || raise(ArgumentError, "type must be a string")
129
+
130
+ flags |= (1 << 5)
131
+ arr << type.bytesize << type
132
+ fmt << "Ca*"
133
+ end
134
+
135
+ if user_id
136
+ user_id.is_a?(String) || raise(ArgumentError, "user_id must be a string")
137
+
138
+ flags |= (1 << 4)
139
+ arr << user_id.bytesize << user_id
140
+ fmt << "Ca*"
141
+ end
142
+
143
+ if app_id
144
+ app_id.is_a?(String) || raise(ArgumentError, "app_id must be a string")
145
+
146
+ flags |= (1 << 3)
147
+ arr << app_id.bytesize << app_id
148
+ fmt << "Ca*"
149
+ end
150
+
151
+ arr[0] = flags
152
+ arr.pack(fmt.string)
153
+ end
154
+
155
+ # Decode a byte array
156
+ # @return [Properties]
157
+ def self.decode(bytes)
158
+ h = new
159
+ flags = bytes.unpack1("S>")
160
+ pos = 2
161
+ if (flags & 0x8000).positive?
162
+ len = bytes[pos].ord
163
+ pos += 1
164
+ h[:content_type] = bytes.byteslice(pos, len).force_encoding("utf-8")
165
+ pos += len
166
+ end
167
+ if (flags & 0x4000).positive?
168
+ len = bytes[pos].ord
169
+ pos += 1
170
+ h[:content_encoding] = bytes.byteslice(pos, len).force_encoding("utf-8")
171
+ pos += len
172
+ end
173
+ if (flags & 0x2000).positive?
174
+ len = bytes.byteslice(pos, 4).unpack1("L>")
175
+ pos += 4
176
+ h[:headers] = Table.decode(bytes.byteslice(pos, len))
177
+ pos += len
178
+ end
179
+ if (flags & 0x1000).positive?
180
+ h[:delivery_mode] = bytes[pos].ord
181
+ pos += 1
182
+ end
183
+ if (flags & 0x0800).positive?
184
+ h[:priority] = bytes[pos].ord
185
+ pos += 1
186
+ end
187
+ if (flags & 0x0400).positive?
188
+ len = bytes[pos].ord
189
+ pos += 1
190
+ h[:correlation_id] = bytes.byteslice(pos, len).force_encoding("utf-8")
191
+ pos += len
192
+ end
193
+ if (flags & 0x0200).positive?
194
+ len = bytes[pos].ord
195
+ pos += 1
196
+ h[:reply_to] = bytes.byteslice(pos, len).force_encoding("utf-8")
197
+ pos += len
198
+ end
199
+ if (flags & 0x0100).positive?
200
+ len = bytes[pos].ord
201
+ pos += 1
202
+ h[:expiration] = bytes.byteslice(pos, len).force_encoding("utf-8")
203
+ pos += len
204
+ end
205
+ if (flags & 0x0080).positive?
206
+ len = bytes[pos].ord
207
+ pos += 1
208
+ h[:message_id] = bytes.byteslice(pos, len).force_encoding("utf-8")
209
+ pos += len
210
+ end
211
+ if (flags & 0x0040).positive?
212
+ h[:timestamp] = Time.at(bytes.byteslice(pos, 8).unpack1("Q>"))
213
+ pos += 8
214
+ end
215
+ if (flags & 0x0020).positive?
216
+ len = bytes[pos].ord
217
+ pos += 1
218
+ h[:type] = bytes.byteslice(pos, len).force_encoding("utf-8")
219
+ pos += len
220
+ end
221
+ if (flags & 0x0010).positive?
222
+ len = bytes[pos].ord
223
+ pos += 1
224
+ h[:user_id] = bytes.byteslice(pos, len).force_encoding("utf-8")
225
+ pos += len
226
+ end
227
+ if (flags & 0x0008).positive?
228
+ len = bytes[pos].ord
229
+ pos += 1
230
+ h[:app_id] = bytes.byteslice(pos, len).force_encoding("utf-8")
231
+ end
232
+ h
21
233
  end
22
-
23
- if content_encoding
24
- content_encoding.is_a?(String) || raise(ArgumentError, "content_encoding must be a string")
25
-
26
- flags |= (1 << 14)
27
- arr << content_encoding.bytesize << content_encoding
28
- fmt << "Ca*"
29
- end
30
-
31
- if headers
32
- headers.is_a?(Hash) || raise(ArgumentError, "headers must be a hash")
33
-
34
- flags |= (1 << 13)
35
- tbl = Table.encode(headers)
36
- arr << tbl.bytesize << tbl
37
- fmt << "L>a*"
38
- end
39
-
40
- if delivery_mode
41
- headers.is_a?(Integer) || raise(ArgumentError, "delivery_mode must be an int")
42
-
43
- flags |= (1 << 12)
44
- arr << delivery_mode
45
- fmt << "C"
46
- end
47
-
48
- if priority
49
- priority.is_a?(Integer) || raise(ArgumentError, "priority must be an int")
50
- flags |= (1 << 11)
51
- arr << priority
52
- fmt << "C"
53
- end
54
-
55
- if correlation_id
56
- priority.is_a?(String) || raise(ArgumentError, "correlation_id must be a string")
57
-
58
- flags |= (1 << 10)
59
- arr << correlation_id.bytesize << correlation_id
60
- fmt << "Ca*"
61
- end
62
-
63
- if reply_to
64
- reply_to.is_a?(String) || raise(ArgumentError, "reply_to must be a string")
65
-
66
- flags |= (1 << 9)
67
- arr << reply_to.bytesize << reply_to
68
- fmt << "Ca*"
69
- end
70
-
71
- if expiration
72
- expiration.is_a?(String) || raise(ArgumentError, "expiration must be a string")
73
-
74
- flags |= (1 << 8)
75
- arr << expiration.bytesize << expiration
76
- fmt << "Ca*"
77
- end
78
-
79
- if message_id
80
- message_id.is_a?(String) || raise(ArgumentError, "message_id must be a string")
81
-
82
- flags |= (1 << 7)
83
- arr << message_id.bytesize << message_id
84
- fmt << "Ca*"
85
- end
86
-
87
- if timestamp
88
- timestamp.is_a?(Time) || raise(ArgumentError, "timestamp must be a time")
89
-
90
- flags |= (1 << 6)
91
- arr << timestamp.to_i
92
- fmt << "Q>"
93
- end
94
-
95
- if type
96
- type.is_a?(String) || raise(ArgumentError, "type must be a string")
97
-
98
- flags |= (1 << 5)
99
- arr << type.bytesize << type
100
- fmt << "Ca*"
101
- end
102
-
103
- if user_id
104
- user_id.is_a?(String) || raise(ArgumentError, "user_id must be a string")
105
-
106
- flags |= (1 << 4)
107
- arr << user_id.bytesize << user_id
108
- fmt << "Ca*"
109
- end
110
-
111
- if app_id
112
- app_id.is_a?(String) || raise(ArgumentError, "app_id must be a string")
113
-
114
- flags |= (1 << 3)
115
- arr << app_id.bytesize << app_id
116
- fmt << "Ca*"
117
- end
118
-
119
- arr[0] = flags
120
- arr.pack(fmt)
121
- end
122
-
123
- def self.decode(bytes)
124
- h = new
125
- flags = bytes.unpack1("S>")
126
- pos = 2
127
- if (flags & 0x8000).positive?
128
- len = bytes[pos].ord
129
- pos += 1
130
- h[:content_type] = bytes.byteslice(pos, len).force_encoding("utf-8")
131
- pos += len
132
- end
133
- if (flags & 0x4000).positive?
134
- len = bytes[pos].ord
135
- pos += 1
136
- h[:content_encoding] = bytes.byteslice(pos, len).force_encoding("utf-8")
137
- pos += len
138
- end
139
- if (flags & 0x2000).positive?
140
- len = bytes.byteslice(pos, 4).unpack1("L>")
141
- pos += 4
142
- h[:headers] = Table.decode(bytes.byteslice(pos, len))
143
- pos += len
144
- end
145
- if (flags & 0x1000).positive?
146
- h[:delivery_mode] = bytes[pos].ord
147
- pos += 1
148
- end
149
- if (flags & 0x0800).positive?
150
- h[:priority] = bytes[pos].ord
151
- pos += 1
152
- end
153
- if (flags & 0x0400).positive?
154
- len = bytes[pos].ord
155
- pos += 1
156
- h[:correlation_id] = bytes.byteslice(pos, len).force_encoding("utf-8")
157
- pos += len
158
- end
159
- if (flags & 0x0200).positive?
160
- len = bytes[pos].ord
161
- pos += 1
162
- h[:reply_to] = bytes.byteslice(pos, len).force_encoding("utf-8")
163
- pos += len
164
- end
165
- if (flags & 0x0100).positive?
166
- len = bytes[pos].ord
167
- pos += 1
168
- h[:expiration] = bytes.byteslice(pos, len).force_encoding("utf-8")
169
- pos += len
170
- end
171
- if (flags & 0x0080).positive?
172
- len = bytes[pos].ord
173
- pos += 1
174
- h[:message_id] = bytes.byteslice(pos, len).force_encoding("utf-8")
175
- pos += len
176
- end
177
- if (flags & 0x0040).positive?
178
- h[:timestamp] = Time.at(bytes.byteslice(pos, 8).unpack1("Q>"))
179
- pos += 8
180
- end
181
- if (flags & 0x0020).positive?
182
- len = bytes[pos].ord
183
- pos += 1
184
- h[:type] = bytes.byteslice(pos, len).force_encoding("utf-8")
185
- pos += len
186
- end
187
- if (flags & 0x0010).positive?
188
- len = bytes[pos].ord
189
- pos += 1
190
- h[:user_id] = bytes.byteslice(pos, len).force_encoding("utf-8")
191
- pos += len
192
- end
193
- if (flags & 0x0008).positive?
194
- len = bytes[pos].ord
195
- pos += 1
196
- h[:app_id] = bytes.byteslice(pos, len).force_encoding("utf-8")
197
- end
198
- h
199
234
  end
200
235
  end
201
236
  end