nats-pure 0.7.2 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +201 -0
  3. data/README.md +251 -0
  4. data/lib/nats/client.rb +16 -0
  5. data/lib/nats/io/client.rb +1559 -1277
  6. data/lib/nats/io/errors.rb +74 -0
  7. data/lib/nats/io/jetstream/api.rb +309 -0
  8. data/lib/nats/io/jetstream/errors.rb +104 -0
  9. data/lib/nats/io/jetstream/js/config.rb +26 -0
  10. data/lib/nats/io/jetstream/js/header.rb +31 -0
  11. data/lib/nats/io/jetstream/js/status.rb +27 -0
  12. data/lib/nats/io/jetstream/js/sub.rb +30 -0
  13. data/lib/nats/io/jetstream/js.rb +93 -0
  14. data/lib/nats/io/jetstream/manager.rb +303 -0
  15. data/lib/nats/io/jetstream/msg/ack.rb +57 -0
  16. data/lib/nats/io/jetstream/msg/ack_methods.rb +111 -0
  17. data/lib/nats/io/jetstream/msg/metadata.rb +37 -0
  18. data/lib/nats/io/jetstream/msg.rb +26 -0
  19. data/lib/nats/io/jetstream/pull_subscription.rb +260 -0
  20. data/lib/nats/io/jetstream/push_subscription.rb +42 -0
  21. data/lib/nats/io/jetstream.rb +344 -0
  22. data/lib/nats/io/kv/api.rb +39 -0
  23. data/lib/nats/io/kv/bucket_status.rb +38 -0
  24. data/lib/nats/io/kv/errors.rb +60 -0
  25. data/lib/nats/io/kv/manager.rb +89 -0
  26. data/lib/nats/io/kv.rb +178 -0
  27. data/lib/nats/io/msg.rb +58 -0
  28. data/lib/nats/io/parser.rb +7 -7
  29. data/lib/nats/io/rails.rb +29 -0
  30. data/lib/nats/io/subscription.rb +157 -0
  31. data/lib/nats/io/version.rb +8 -4
  32. data/lib/nats/io/websocket.rb +75 -0
  33. data/lib/nats/nuid.rb +3 -1
  34. data/lib/nats.rb +39 -0
  35. data/sig/nats/io/client.rbs +304 -0
  36. data/sig/nats/io/errors.rbs +54 -0
  37. data/sig/nats/io/jetstream/api.rbs +35 -0
  38. data/sig/nats/io/jetstream/errors.rbs +54 -0
  39. data/sig/nats/io/jetstream/js/config.rbs +11 -0
  40. data/sig/nats/io/jetstream/js/header.rbs +17 -0
  41. data/sig/nats/io/jetstream/js/status.rbs +13 -0
  42. data/sig/nats/io/jetstream/js/sub.rbs +14 -0
  43. data/sig/nats/io/jetstream/js.rbs +27 -0
  44. data/sig/nats/io/jetstream/manager.rbs +33 -0
  45. data/sig/nats/io/jetstream/msg/ack.rbs +35 -0
  46. data/sig/nats/io/jetstream/msg/ack_methods.rbs +25 -0
  47. data/sig/nats/io/jetstream/msg/metadata.rbs +15 -0
  48. data/sig/nats/io/jetstream/msg.rbs +6 -0
  49. data/sig/nats/io/jetstream/pull_subscription.rbs +14 -0
  50. data/sig/nats/io/jetstream/push_subscription.rbs +7 -0
  51. data/sig/nats/io/jetstream.rbs +15 -0
  52. data/sig/nats/io/kv/api.rbs +8 -0
  53. data/sig/nats/io/kv/bucket_status.rbs +17 -0
  54. data/sig/nats/io/kv/errors.rbs +30 -0
  55. data/sig/nats/io/kv/manager.rbs +11 -0
  56. data/sig/nats/io/kv.rbs +39 -0
  57. data/sig/nats/io/msg.rbs +14 -0
  58. data/sig/nats/io/parser.rbs +32 -0
  59. data/sig/nats/io/subscription.rbs +33 -0
  60. data/sig/nats/io/version.rbs +9 -0
  61. data/sig/nats/nuid.rbs +32 -0
  62. metadata +74 -4
@@ -0,0 +1,74 @@
1
+ # Copyright 2021 The NATS Authors
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module NATS
16
+ module IO
17
+ class Error < StandardError; end
18
+
19
+ # When the NATS server sends us an 'ERR' message.
20
+ class ServerError < Error; end
21
+
22
+ # When we detect error on the client side.
23
+ class ClientError < Error; end
24
+
25
+ # When we cannot connect to the server (either initially or after a reconnect).
26
+ class ConnectError < Error; end
27
+
28
+ # When we cannot connect to the server because authorization failed.
29
+ class AuthError < ConnectError; end
30
+
31
+ # When we cannot connect serverince there are no servers available.
32
+ class NoServersError < ConnectError; end
33
+
34
+ # When there are no subscribers available to respond.
35
+ class NoRespondersError < ConnectError; end
36
+
37
+ # When the connection exhausts max number of pending pings replies.
38
+ class StaleConnectionError < Error; end
39
+
40
+ # When we do not get a result within a specified time.
41
+ class Timeout < Error; end
42
+
43
+ # When there is an i/o timeout with the socket.
44
+ class SocketTimeoutError < Timeout; end
45
+
46
+ # When we use an invalid subject.
47
+ class BadSubject < Error; end
48
+
49
+ # When an invalid subscription is used, like one already unsubscribed
50
+ # or when the NATS connection is already closed.
51
+ class BadSubscription < Error; end
52
+
53
+ # When a subscription hits the pending messages limit.
54
+ class SlowConsumer < Error; end
55
+
56
+ # When an action cannot be done because client is draining.
57
+ class ConnectionDrainingError < Error; end
58
+
59
+ # When drain takes too long to complete.
60
+ class DrainTimeoutError < Error; end
61
+
62
+ # When a fork is detected, but the client is not configured to re-connect automatically.
63
+ class ForkDetectedError < Error; end
64
+
65
+ # When tried to send command after connection has been closed.
66
+ class ConnectionClosedError < Error; end
67
+ end
68
+
69
+ # Timeout is raised when the client gives up waiting for a response from a service.
70
+ Timeout = ::NATS::IO::Timeout
71
+
72
+ # Error is any error thrown by the client library.
73
+ Error = ::NATS::IO::Error
74
+ end
@@ -0,0 +1,309 @@
1
+ # Copyright 2021 The NATS Authors
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ require_relative 'errors'
16
+ require 'base64'
17
+ require 'time'
18
+
19
+ module NATS
20
+ class JetStream
21
+ # JetStream::API are the types used to interact with the JetStream API.
22
+ module API
23
+ # When the server responds with an error from the JetStream API.
24
+ Error = ::NATS::JetStream::Error::APIError
25
+
26
+ # SequenceInfo is a pair of consumer and stream sequence and last activity.
27
+ # @!attribute consumer_seq
28
+ # @return [Integer] The consumer sequence.
29
+ # @!attribute stream_seq
30
+ # @return [Integer] The stream sequence.
31
+ SequenceInfo = Struct.new(:consumer_seq, :stream_seq, :last_active,
32
+ keyword_init: true) do
33
+ def initialize(opts={})
34
+ # Filter unrecognized fields and freeze.
35
+ rem = opts.keys - members
36
+ opts.delete_if { |k| rem.include?(k) }
37
+ super(opts)
38
+ freeze
39
+ end
40
+ end
41
+
42
+ # ConsumerInfo is the current status of a JetStream consumer.
43
+ #
44
+ # @!attribute stream_name
45
+ # @return [String] name of the stream to which the consumer belongs.
46
+ # @!attribute name
47
+ # @return [String] name of the consumer.
48
+ # @!attribute created
49
+ # @return [String] time when the consumer was created.
50
+ # @!attribute config
51
+ # @return [ConsumerConfig] consumer configuration.
52
+ # @!attribute delivered
53
+ # @return [SequenceInfo]
54
+ # @!attribute ack_floor
55
+ # @return [SequenceInfo]
56
+ # @!attribute num_ack_pending
57
+ # @return [Integer]
58
+ # @!attribute num_redelivered
59
+ # @return [Integer]
60
+ # @!attribute num_waiting
61
+ # @return [Integer]
62
+ # @!attribute num_pending
63
+ # @return [Integer]
64
+ # @!attribute cluster
65
+ # @return [Hash]
66
+ ConsumerInfo = Struct.new(:type, :stream_name, :name, :created,
67
+ :config, :delivered, :ack_floor,
68
+ :num_ack_pending, :num_redelivered, :num_waiting,
69
+ :num_pending, :cluster, :push_bound,
70
+ keyword_init: true) do
71
+ def initialize(opts={})
72
+ opts[:created] = Time.parse(opts[:created])
73
+ opts[:ack_floor] = SequenceInfo.new(opts[:ack_floor])
74
+ opts[:delivered] = SequenceInfo.new(opts[:delivered])
75
+ opts[:config][:ack_wait] = opts[:config][:ack_wait] / ::NATS::NANOSECONDS
76
+ opts[:config] = ConsumerConfig.new(opts[:config])
77
+ opts.delete(:cluster)
78
+ # Filter unrecognized fields just in case.
79
+ rem = opts.keys - members
80
+ opts.delete_if { |k| rem.include?(k) }
81
+ super(opts)
82
+ freeze
83
+ end
84
+ end
85
+
86
+ # ConsumerConfig is the consumer configuration.
87
+ #
88
+ # @!attribute durable_name
89
+ # @return [String]
90
+ # @!attribute deliver_policy
91
+ # @return [String]
92
+ # @!attribute ack_policy
93
+ # @return [String]
94
+ # @!attribute ack_wait
95
+ # @return [Integer]
96
+ # @!attribute max_deliver
97
+ # @return [Integer]
98
+ # @!attribute replay_policy
99
+ # @return [String]
100
+ # @!attribute max_waiting
101
+ # @return [Integer]
102
+ # @!attribute max_ack_pending
103
+ # @return [Integer]
104
+ ConsumerConfig = Struct.new(:name, :durable_name, :description,
105
+ :deliver_policy, :opt_start_seq, :opt_start_time,
106
+ :ack_policy, :ack_wait, :max_deliver, :backoff,
107
+ :filter_subject, :replay_policy, :rate_limit_bps,
108
+ :sample_freq, :max_waiting, :max_ack_pending,
109
+ :flow_control, :idle_heartbeat, :headers_only,
110
+
111
+ # Pull based options
112
+ :max_batch, :max_expires,
113
+ # Push based consumers
114
+ :deliver_subject, :deliver_group,
115
+ # Ephemeral inactivity threshold
116
+ :inactive_threshold,
117
+ # Generally inherited by parent stream and other markers,
118
+ # now can be configured directly.
119
+ :num_replicas,
120
+ # Force memory storage
121
+ :mem_storage,
122
+
123
+ # NATS v2.10 features
124
+ :metadata, :filter_subjects, :max_bytes,
125
+ keyword_init: true) do
126
+ def initialize(opts={})
127
+ # Filter unrecognized fields just in case.
128
+ rem = opts.keys - members
129
+ opts.delete_if { |k| rem.include?(k) }
130
+ super(opts)
131
+ end
132
+ end
133
+
134
+ # StreamConfig represents the configuration of a stream from JetStream.
135
+ #
136
+ # @!attribute type
137
+ # @return [String]
138
+ # @!attribute config
139
+ # @return [Hash]
140
+ # @!attribute created
141
+ # @return [String]
142
+ # @!attribute state
143
+ # @return [StreamState]
144
+ # @!attribute did_create
145
+ # @return [Boolean]
146
+ # @!attribute name
147
+ # @return [String]
148
+ # @!attribute subjects
149
+ # @return [Array]
150
+ # @!attribute retention
151
+ # @return [String]
152
+ # @!attribute max_consumers
153
+ # @return [Integer]
154
+ # @!attribute max_msgs
155
+ # @return [Integer]
156
+ # @!attribute max_bytes
157
+ # @return [Integer]
158
+ # @!attribute max_age
159
+ # @return [Integer]
160
+ # @!attribute max_msgs_per_subject
161
+ # @return [Integer]
162
+ # @!attribute max_msg_size
163
+ # @return [Integer]
164
+ # @!attribute discard
165
+ # @return [String]
166
+ # @!attribute storage
167
+ # @return [String]
168
+ # @!attribute num_replicas
169
+ # @return [Integer]
170
+ # @!attribute duplicate_window
171
+ # @return [Integer]
172
+ StreamConfig = Struct.new(
173
+ :name,
174
+ :description,
175
+ :subjects,
176
+ :retention,
177
+ :max_consumers,
178
+ :max_msgs,
179
+ :max_bytes,
180
+ :discard,
181
+ :max_age,
182
+ :max_msgs_per_subject,
183
+ :max_msg_size,
184
+ :storage,
185
+ :num_replicas,
186
+ :no_ack,
187
+ :duplicate_window,
188
+ :placement,
189
+ :mirror,
190
+ :sources,
191
+ :sealed,
192
+ :deny_delete,
193
+ :deny_purge,
194
+ :allow_rollup_hdrs,
195
+ :republish,
196
+ :allow_direct,
197
+ :mirror_direct,
198
+ :metadata,
199
+ keyword_init: true) do
200
+ def initialize(opts={})
201
+ # Filter unrecognized fields just in case.
202
+ rem = opts.keys - members
203
+ opts.delete_if { |k| rem.include?(k) }
204
+ super(opts)
205
+ end
206
+ end
207
+
208
+ # StreamInfo is the info about a stream from JetStream.
209
+ #
210
+ # @!attribute type
211
+ # @return [String]
212
+ # @!attribute config
213
+ # @return [Hash]
214
+ # @!attribute created
215
+ # @return [String]
216
+ # @!attribute state
217
+ # @return [Hash]
218
+ # @!attribute domain
219
+ # @return [String]
220
+ StreamInfo = Struct.new(:type, :config, :created, :state, :domain,
221
+ keyword_init: true) do
222
+ def initialize(opts={})
223
+ opts[:config] = StreamConfig.new(opts[:config])
224
+ opts[:state] = StreamState.new(opts[:state])
225
+ opts[:created] = ::Time.parse(opts[:created])
226
+
227
+ # Filter fields and freeze.
228
+ rem = opts.keys - members
229
+ opts.delete_if { |k| rem.include?(k) }
230
+ super(opts)
231
+ freeze
232
+ end
233
+ end
234
+
235
+ # StreamState is the state of a stream.
236
+ #
237
+ # @!attribute messages
238
+ # @return [Integer]
239
+ # @!attribute bytes
240
+ # @return [Integer]
241
+ # @!attribute first_seq
242
+ # @return [Integer]
243
+ # @!attribute last_seq
244
+ # @return [Integer]
245
+ # @!attribute consumer_count
246
+ # @return [Integer]
247
+ StreamState = Struct.new(:messages, :bytes, :first_seq, :first_ts,
248
+ :last_seq, :last_ts, :consumer_count,
249
+ keyword_init: true) do
250
+ def initialize(opts={})
251
+ rem = opts.keys - members
252
+ opts.delete_if { |k| rem.include?(k) }
253
+ super(opts)
254
+ end
255
+ end
256
+
257
+ # StreamCreateResponse is the response from the JetStream $JS.API.STREAM.CREATE API.
258
+ #
259
+ # @!attribute type
260
+ # @return [String]
261
+ # @!attribute config
262
+ # @return [StreamConfig]
263
+ # @!attribute created
264
+ # @return [String]
265
+ # @!attribute state
266
+ # @return [StreamState]
267
+ # @!attribute did_create
268
+ # @return [Boolean]
269
+ StreamCreateResponse = Struct.new(:type, :config, :created, :state, :did_create,
270
+ keyword_init: true) do
271
+ def initialize(opts={})
272
+ rem = opts.keys - members
273
+ opts.delete_if { |k| rem.include?(k) }
274
+ opts[:config] = StreamConfig.new(opts[:config])
275
+ opts[:state] = StreamState.new(opts[:state])
276
+ super(opts)
277
+ freeze
278
+ end
279
+ end
280
+
281
+ RawStreamMsg = Struct.new(:subject, :seq, :data, :headers, keyword_init: true) do
282
+ def initialize(opts)
283
+ opts[:data] = Base64.decode64(opts[:data]) if opts[:data]
284
+ if opts[:hdrs]
285
+ header = Base64.decode64(opts[:hdrs])
286
+ hdr = {}
287
+ lines = header.lines
288
+ lines.slice(1, header.size).each do |line|
289
+ line.rstrip!
290
+ next if line.empty?
291
+ key, value = line.strip.split(/\s*:\s*/, 2)
292
+ hdr[key] = value
293
+ end
294
+ opts[:headers] = hdr
295
+ end
296
+
297
+ # Filter out members not present.
298
+ rem = opts.keys - members
299
+ opts.delete_if { |k| rem.include?(k) }
300
+ super(opts)
301
+ end
302
+
303
+ def sequence
304
+ self.seq
305
+ end
306
+ end
307
+ end
308
+ end
309
+ end
@@ -0,0 +1,104 @@
1
+ # Copyright 2021 The NATS Authors
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module NATS
16
+ class JetStream
17
+ # Error is any error that may arise when interacting with JetStream.
18
+ class Error < NATS::IO::Error
19
+
20
+ # When there is a NATS::IO::NoResponders error after making a publish request.
21
+ class NoStreamResponse < Error; end
22
+
23
+ # When an invalid durable or consumer name was attempted to be used.
24
+ class InvalidDurableName < Error; end
25
+
26
+ # When an ack not longer valid.
27
+ class InvalidJSAck < Error; end
28
+
29
+ # When an ack has already been acked.
30
+ class MsgAlreadyAckd < Error; end
31
+
32
+ # When the delivered message does not behave as a message delivered by JetStream,
33
+ # for example when the ack reply has unrecognizable fields.
34
+ class NotJSMessage < Error; end
35
+
36
+ # When the stream name is invalid.
37
+ class InvalidStreamName < Error; end
38
+
39
+ # When the consumer name is invalid.
40
+ class InvalidConsumerName < Error; end
41
+
42
+ # When the server responds with an error from the JetStream API.
43
+ class APIError < Error
44
+ attr_reader :code, :err_code, :description, :stream, :seq
45
+
46
+ def initialize(params={})
47
+ @code = params[:code]
48
+ @err_code = params[:err_code]
49
+ @description = params[:description]
50
+ @stream = params[:stream]
51
+ @seq = params[:seq]
52
+ end
53
+
54
+ def to_s
55
+ "#{@description} (status_code=#{@code}, err_code=#{@err_code})"
56
+ end
57
+ end
58
+
59
+ # When JetStream is not currently available, this could be due to JetStream
60
+ # not being enabled or temporarily unavailable due to a leader election when
61
+ # running in cluster mode.
62
+ # This condition is represented with a message that has 503 status code header.
63
+ class ServiceUnavailable < APIError
64
+ def initialize(params={})
65
+ super(params)
66
+ @code ||= 503
67
+ end
68
+ end
69
+
70
+ # When there is a hard failure in the JetStream.
71
+ # This condition is represented with a message that has 500 status code header.
72
+ class ServerError < APIError
73
+ def initialize(params={})
74
+ super(params)
75
+ @code ||= 500
76
+ end
77
+ end
78
+
79
+ # When a JetStream object was not found.
80
+ # This condition is represented with a message that has 404 status code header.
81
+ class NotFound < APIError
82
+ def initialize(params={})
83
+ super(params)
84
+ @code ||= 404
85
+ end
86
+ end
87
+
88
+ # When the stream is not found.
89
+ class StreamNotFound < NotFound; end
90
+
91
+ # When the consumer or durable is not found by name.
92
+ class ConsumerNotFound < NotFound; end
93
+
94
+ # When the JetStream client makes an invalid request.
95
+ # This condition is represented with a message that has 400 status code header.
96
+ class BadRequest < APIError
97
+ def initialize(params={})
98
+ super(params)
99
+ @code ||= 400
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright 2021 The NATS Authors
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module NATS
16
+ class JetStream
17
+ module JS
18
+ module Config
19
+ # AckPolicy
20
+ AckExplicit = ("explicit".freeze)
21
+ AckAll = ("all".freeze)
22
+ AckNone = ("none".freeze)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright 2021 The NATS Authors
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module NATS
16
+ class JetStream
17
+ module JS
18
+ module Header
19
+ Status = ("Status".freeze)
20
+ Desc = ("Description".freeze)
21
+ MsgID = ("Nats-Msg-Id".freeze)
22
+ ExpectedStream = ("Nats-Expected-Stream".freeze)
23
+ ExpectedLastSeq = ("Nats-Expected-Last-Sequence".freeze)
24
+ ExpectedLastSubjSeq = ("Nats-Expected-Last-Subject-Sequence".freeze)
25
+ ExpectedLastMsgID = ("Nats-Expected-Last-Msg-Id".freeze)
26
+ LastConsumerSeq = ("Nats-Last-Consumer".freeze)
27
+ LastStreamSeq = ("Nats-Last-Stream".freeze)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright 2021 The NATS Authors
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module NATS
16
+ class JetStream
17
+ module JS
18
+ module Status
19
+ CtrlMsg = ("100".freeze)
20
+ NoMsgs = ("404".freeze)
21
+ NotFound = ("404".freeze)
22
+ RequestTimeout = ("408".freeze)
23
+ ServiceUnavailable = ("503".freeze)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ # Copyright 2021 The NATS Authors
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ module NATS
16
+ class JetStream
17
+ module JS
18
+ class Sub
19
+ attr_reader :js, :stream, :consumer, :nms
20
+
21
+ def initialize(opts={})
22
+ @js = opts[:js]
23
+ @stream = opts[:stream]
24
+ @consumer = opts[:consumer]
25
+ @nms = opts[:nms]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,93 @@
1
+ # Copyright 2021 The NATS Authors
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ #
14
+
15
+ require_relative 'js/config'
16
+ require_relative 'js/header'
17
+ require_relative 'js/status'
18
+ require_relative 'js/sub'
19
+
20
+ module NATS
21
+ class JetStream
22
+ # Misc internal functions to support JS API.
23
+ # @private
24
+ module JS
25
+ DefaultAPIPrefix = ("$JS.API".freeze)
26
+
27
+ class << self
28
+ def next_req_to_json(next_req)
29
+ req = {}
30
+ req[:batch] = next_req[:batch]
31
+ req[:expires] = next_req[:expires].to_i if next_req[:expires]
32
+ req[:no_wait] = next_req[:no_wait] if next_req[:no_wait]
33
+ req.to_json
34
+ end
35
+
36
+ def is_status_msg(msg)
37
+ return (!msg.nil? and (!msg.header.nil? and msg.header[Header::Status]))
38
+ end
39
+
40
+ # check_503_error raises exception when a NATS::Msg has a 503 status header.
41
+ # @param msg [NATS::Msg] The message with status headers.
42
+ # @raise [NATS::JetStream::Error::ServiceUnavailable]
43
+ def check_503_error(msg)
44
+ return if msg.nil? or msg.header.nil?
45
+ if msg.header[Header::Status] == Status::ServiceUnavailable
46
+ raise ::NATS::JetStream::Error::ServiceUnavailable
47
+ end
48
+ end
49
+
50
+ # from_msg takes a plain NATS::Msg and checks its headers to confirm
51
+ # if it was an error:
52
+ #
53
+ # msg.header={"Status"=>"503"})
54
+ # msg.header={"Status"=>"408", "Description"=>"Request Timeout"})
55
+ #
56
+ # @param msg [NATS::Msg] The message with status headers.
57
+ # @return [NATS::JetStream::API::Error]
58
+ def from_msg(msg)
59
+ check_503_error(msg)
60
+ code = msg.header[JS::Header::Status]
61
+ desc = msg.header[JS::Header::Desc]
62
+ return ::NATS::JetStream::API::Error.new({code: code, description: desc})
63
+ end
64
+
65
+ # from_error takes an API response that errored and maps the error
66
+ # into a JetStream error type based on the status and error code.
67
+ def from_error(err)
68
+ return unless err
69
+ case err[:code]
70
+ when 503
71
+ ::NATS::JetStream::Error::ServiceUnavailable.new(err)
72
+ when 500
73
+ ::NATS::JetStream::Error::ServerError.new(err)
74
+ when 404
75
+ case err[:err_code]
76
+ when 10059
77
+ ::NATS::JetStream::Error::StreamNotFound.new(err)
78
+ when 10014
79
+ ::NATS::JetStream::Error::ConsumerNotFound.new(err)
80
+ else
81
+ ::NATS::JetStream::Error::NotFound.new(err)
82
+ end
83
+ when 400
84
+ ::NATS::JetStream::Error::BadRequest.new(err)
85
+ else
86
+ ::NATS::JetStream::API::Error.new(err)
87
+ end
88
+ end
89
+ end
90
+ end
91
+ private_constant :JS
92
+ end
93
+ end