amqp-client 0.2.2 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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