amqp-client 1.0.0 → 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: 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,201 +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
- delivery_mode.is_a?(Integer) || raise(ArgumentError, "delivery_mode must be an int")
42
- delivery_mode.between?(0, 2) || raise(ArgumentError, "delivery_mode must be be between 0 and 2")
43
-
44
- flags |= (1 << 12)
45
- arr << delivery_mode
46
- fmt << "C"
47
- end
48
-
49
- if priority
50
- priority.is_a?(Integer) || raise(ArgumentError, "priority must be an int")
51
- flags |= (1 << 11)
52
- arr << priority
53
- fmt << "C"
54
- end
55
-
56
- if correlation_id
57
- priority.is_a?(String) || raise(ArgumentError, "correlation_id must be a string")
58
-
59
- flags |= (1 << 10)
60
- arr << correlation_id.bytesize << correlation_id
61
- fmt << "Ca*"
62
- end
63
-
64
- if reply_to
65
- reply_to.is_a?(String) || raise(ArgumentError, "reply_to must be a string")
66
-
67
- flags |= (1 << 9)
68
- arr << reply_to.bytesize << reply_to
69
- fmt << "Ca*"
70
- end
71
-
72
- if expiration
73
- self.expiration = expiration.to_s if expiration.is_a?(Integer)
74
- expiration.is_a?(String) || raise(ArgumentError, "expiration must be a string or integer")
75
-
76
- flags |= (1 << 8)
77
- arr << expiration.bytesize << expiration
78
- fmt << "Ca*"
79
- end
80
-
81
- if message_id
82
- message_id.is_a?(String) || raise(ArgumentError, "message_id must be a string")
83
-
84
- flags |= (1 << 7)
85
- arr << message_id.bytesize << message_id
86
- fmt << "Ca*"
87
- end
88
-
89
- if timestamp
90
- timestamp.is_a?(Integer) || timestamp.is_a?(Time) || raise(ArgumentError, "timestamp must be an Integer or a Time")
91
-
92
- flags |= (1 << 6)
93
- arr << timestamp.to_i
94
- fmt << "Q>"
95
- end
96
-
97
- if type
98
- type.is_a?(String) || raise(ArgumentError, "type must be a string")
99
-
100
- flags |= (1 << 5)
101
- arr << type.bytesize << type
102
- fmt << "Ca*"
103
- end
104
-
105
- if user_id
106
- user_id.is_a?(String) || raise(ArgumentError, "user_id must be a string")
107
-
108
- flags |= (1 << 4)
109
- arr << user_id.bytesize << user_id
110
- fmt << "Ca*"
111
- end
112
-
113
- if app_id
114
- app_id.is_a?(String) || raise(ArgumentError, "app_id must be a string")
115
-
116
- flags |= (1 << 3)
117
- arr << app_id.bytesize << app_id
118
- fmt << "Ca*"
119
- end
120
-
121
- arr[0] = flags
122
- arr.pack(fmt)
123
- end
124
-
125
- def self.decode(bytes)
126
- h = new
127
- flags = bytes.unpack1("S>")
128
- pos = 2
129
- if (flags & 0x8000).positive?
130
- len = bytes[pos].ord
131
- pos += 1
132
- h[:content_type] = bytes.byteslice(pos, len).force_encoding("utf-8")
133
- pos += len
134
- end
135
- if (flags & 0x4000).positive?
136
- len = bytes[pos].ord
137
- pos += 1
138
- h[:content_encoding] = bytes.byteslice(pos, len).force_encoding("utf-8")
139
- pos += len
140
- end
141
- if (flags & 0x2000).positive?
142
- len = bytes.byteslice(pos, 4).unpack1("L>")
143
- pos += 4
144
- h[:headers] = Table.decode(bytes.byteslice(pos, len))
145
- pos += len
146
- end
147
- if (flags & 0x1000).positive?
148
- h[:delivery_mode] = bytes[pos].ord
149
- pos += 1
150
- end
151
- if (flags & 0x0800).positive?
152
- h[:priority] = bytes[pos].ord
153
- pos += 1
154
- end
155
- if (flags & 0x0400).positive?
156
- len = bytes[pos].ord
157
- pos += 1
158
- h[:correlation_id] = bytes.byteslice(pos, len).force_encoding("utf-8")
159
- pos += len
160
- end
161
- if (flags & 0x0200).positive?
162
- len = bytes[pos].ord
163
- pos += 1
164
- h[:reply_to] = bytes.byteslice(pos, len).force_encoding("utf-8")
165
- pos += len
166
- end
167
- if (flags & 0x0100).positive?
168
- len = bytes[pos].ord
169
- pos += 1
170
- h[:expiration] = bytes.byteslice(pos, len).force_encoding("utf-8")
171
- pos += len
172
- end
173
- if (flags & 0x0080).positive?
174
- len = bytes[pos].ord
175
- pos += 1
176
- h[:message_id] = bytes.byteslice(pos, len).force_encoding("utf-8")
177
- pos += len
178
- end
179
- if (flags & 0x0040).positive?
180
- h[:timestamp] = Time.at(bytes.byteslice(pos, 8).unpack1("Q>"))
181
- pos += 8
182
- end
183
- if (flags & 0x0020).positive?
184
- len = bytes[pos].ord
185
- pos += 1
186
- h[:type] = bytes.byteslice(pos, len).force_encoding("utf-8")
187
- pos += len
188
- end
189
- if (flags & 0x0010).positive?
190
- len = bytes[pos].ord
191
- pos += 1
192
- h[:user_id] = bytes.byteslice(pos, len).force_encoding("utf-8")
193
- pos += len
194
- end
195
- if (flags & 0x0008).positive?
196
- len = bytes[pos].ord
197
- pos += 1
198
- h[:app_id] = bytes.byteslice(pos, len).force_encoding("utf-8")
199
- end
200
- h
201
234
  end
202
235
  end
203
236
  end