amqp-client 1.0.0 → 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: 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