nats-pure 2.2.0 → 2.2.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.
- checksums.yaml +4 -4
- data/lib/nats/io/client.rb +11 -7
- data/lib/nats/io/jetstream/api.rb +305 -0
- data/lib/nats/io/jetstream/errors.rb +104 -0
- data/lib/nats/io/jetstream/js/config.rb +26 -0
- data/lib/nats/io/jetstream/js/header.rb +31 -0
- data/lib/nats/io/jetstream/js/status.rb +27 -0
- data/lib/nats/io/jetstream/js/sub.rb +30 -0
- data/lib/nats/io/jetstream/js.rb +93 -0
- data/lib/nats/io/jetstream/manager.rb +284 -0
- data/lib/nats/io/jetstream/msg/ack.rb +57 -0
- data/lib/nats/io/jetstream/msg/ack_methods.rb +107 -0
- data/lib/nats/io/jetstream/msg/metadata.rb +37 -0
- data/lib/nats/io/jetstream/msg.rb +26 -0
- data/lib/nats/io/jetstream/pull_subscription.rb +260 -0
- data/lib/nats/io/jetstream/push_subscription.rb +42 -0
- data/lib/nats/io/jetstream.rb +269 -0
- data/lib/nats/io/kv/api.rb +39 -0
- data/lib/nats/io/kv/bucket_status.rb +38 -0
- data/lib/nats/io/kv/errors.rb +60 -0
- data/lib/nats/io/kv/manager.rb +89 -0
- data/lib/nats/io/kv.rb +5 -157
- data/lib/nats/io/msg.rb +1 -1
- data/lib/nats/io/version.rb +1 -1
- metadata +21 -3
- data/lib/nats/io/js.rb +0 -1434
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 21e90ec654ece66516fdfac7d16036695ea1afae5f76143e087c8f11564b2135
|
4
|
+
data.tar.gz: 3c7644d2bb03f0a9b8fbc982e88a0ea1119d49ed79b849611209755e8b641437
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06da3807dd934cd955a4dad34a44927b8885e99b5fe43a641ca7e95ddb8231132f837012d4052d3abac84c025bcc05941c8a2277ed224433f8fab16d7cd4c18e
|
7
|
+
data.tar.gz: 12608f0a54fb270de3bda898e4ce2831c166b60b525717de450827e1840e15a5b2b9dd4cf80676490350effc48eb79a31656c46b4eed0af6cd21b264fb03deda
|
data/lib/nats/io/client.rb
CHANGED
@@ -17,7 +17,7 @@ require_relative 'version'
|
|
17
17
|
require_relative 'errors'
|
18
18
|
require_relative 'msg'
|
19
19
|
require_relative 'subscription'
|
20
|
-
require_relative '
|
20
|
+
require_relative 'jetstream'
|
21
21
|
|
22
22
|
require 'nats/nuid'
|
23
23
|
require 'thread'
|
@@ -854,14 +854,18 @@ module NATS
|
|
854
854
|
hdr = {}
|
855
855
|
lines = header.lines
|
856
856
|
|
857
|
-
# Check if
|
858
|
-
if lines.count
|
857
|
+
# Check if the first line has an inline status and description.
|
858
|
+
if lines.count > 0
|
859
859
|
status_hdr = lines.first.rstrip
|
860
|
-
|
860
|
+
status = status_hdr.slice(NATS_HDR_LINE_SIZE-1, STATUS_MSG_LEN)
|
861
861
|
|
862
|
-
if
|
863
|
-
|
864
|
-
|
862
|
+
if status and !status.empty?
|
863
|
+
hdr[STATUS_HDR] = status
|
864
|
+
|
865
|
+
if NATS_HDR_LINE_SIZE+2 < status_hdr.bytesize
|
866
|
+
desc = status_hdr.slice(NATS_HDR_LINE_SIZE+STATUS_MSG_LEN, status_hdr.bytesize)
|
867
|
+
hdr[DESC_HDR] = desc unless desc.empty?
|
868
|
+
end
|
865
869
|
end
|
866
870
|
end
|
867
871
|
begin
|
@@ -0,0 +1,305 @@
|
|
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
|
+
keyword_init: true) do
|
123
|
+
def initialize(opts={})
|
124
|
+
# Filter unrecognized fields just in case.
|
125
|
+
rem = opts.keys - members
|
126
|
+
opts.delete_if { |k| rem.include?(k) }
|
127
|
+
super(opts)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# StreamConfig represents the configuration of a stream from JetStream.
|
132
|
+
#
|
133
|
+
# @!attribute type
|
134
|
+
# @return [String]
|
135
|
+
# @!attribute config
|
136
|
+
# @return [Hash]
|
137
|
+
# @!attribute created
|
138
|
+
# @return [String]
|
139
|
+
# @!attribute state
|
140
|
+
# @return [StreamState]
|
141
|
+
# @!attribute did_create
|
142
|
+
# @return [Boolean]
|
143
|
+
# @!attribute name
|
144
|
+
# @return [String]
|
145
|
+
# @!attribute subjects
|
146
|
+
# @return [Array]
|
147
|
+
# @!attribute retention
|
148
|
+
# @return [String]
|
149
|
+
# @!attribute max_consumers
|
150
|
+
# @return [Integer]
|
151
|
+
# @!attribute max_msgs
|
152
|
+
# @return [Integer]
|
153
|
+
# @!attribute max_bytes
|
154
|
+
# @return [Integer]
|
155
|
+
# @!attribute max_age
|
156
|
+
# @return [Integer]
|
157
|
+
# @!attribute max_msgs_per_subject
|
158
|
+
# @return [Integer]
|
159
|
+
# @!attribute max_msg_size
|
160
|
+
# @return [Integer]
|
161
|
+
# @!attribute discard
|
162
|
+
# @return [String]
|
163
|
+
# @!attribute storage
|
164
|
+
# @return [String]
|
165
|
+
# @!attribute num_replicas
|
166
|
+
# @return [Integer]
|
167
|
+
# @!attribute duplicate_window
|
168
|
+
# @return [Integer]
|
169
|
+
StreamConfig = Struct.new(
|
170
|
+
:name,
|
171
|
+
:description,
|
172
|
+
:subjects,
|
173
|
+
:retention,
|
174
|
+
:max_consumers,
|
175
|
+
:max_msgs,
|
176
|
+
:max_bytes,
|
177
|
+
:discard,
|
178
|
+
:max_age,
|
179
|
+
:max_msgs_per_subject,
|
180
|
+
:max_msg_size,
|
181
|
+
:storage,
|
182
|
+
:num_replicas,
|
183
|
+
:no_ack,
|
184
|
+
:duplicate_window,
|
185
|
+
:placement,
|
186
|
+
:mirror,
|
187
|
+
:sources,
|
188
|
+
:sealed,
|
189
|
+
:deny_delete,
|
190
|
+
:deny_purge,
|
191
|
+
:allow_rollup_hdrs,
|
192
|
+
:republish,
|
193
|
+
:allow_direct,
|
194
|
+
:mirror_direct,
|
195
|
+
keyword_init: true) do
|
196
|
+
def initialize(opts={})
|
197
|
+
# Filter unrecognized fields just in case.
|
198
|
+
rem = opts.keys - members
|
199
|
+
opts.delete_if { |k| rem.include?(k) }
|
200
|
+
super(opts)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# StreamInfo is the info about a stream from JetStream.
|
205
|
+
#
|
206
|
+
# @!attribute type
|
207
|
+
# @return [String]
|
208
|
+
# @!attribute config
|
209
|
+
# @return [Hash]
|
210
|
+
# @!attribute created
|
211
|
+
# @return [String]
|
212
|
+
# @!attribute state
|
213
|
+
# @return [Hash]
|
214
|
+
# @!attribute domain
|
215
|
+
# @return [String]
|
216
|
+
StreamInfo = Struct.new(:type, :config, :created, :state, :domain,
|
217
|
+
keyword_init: true) do
|
218
|
+
def initialize(opts={})
|
219
|
+
opts[:config] = StreamConfig.new(opts[:config])
|
220
|
+
opts[:state] = StreamState.new(opts[:state])
|
221
|
+
opts[:created] = ::Time.parse(opts[:created])
|
222
|
+
|
223
|
+
# Filter fields and freeze.
|
224
|
+
rem = opts.keys - members
|
225
|
+
opts.delete_if { |k| rem.include?(k) }
|
226
|
+
super(opts)
|
227
|
+
freeze
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
# StreamState is the state of a stream.
|
232
|
+
#
|
233
|
+
# @!attribute messages
|
234
|
+
# @return [Integer]
|
235
|
+
# @!attribute bytes
|
236
|
+
# @return [Integer]
|
237
|
+
# @!attribute first_seq
|
238
|
+
# @return [Integer]
|
239
|
+
# @!attribute last_seq
|
240
|
+
# @return [Integer]
|
241
|
+
# @!attribute consumer_count
|
242
|
+
# @return [Integer]
|
243
|
+
StreamState = Struct.new(:messages, :bytes, :first_seq, :first_ts,
|
244
|
+
:last_seq, :last_ts, :consumer_count,
|
245
|
+
keyword_init: true) do
|
246
|
+
def initialize(opts={})
|
247
|
+
rem = opts.keys - members
|
248
|
+
opts.delete_if { |k| rem.include?(k) }
|
249
|
+
super(opts)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# StreamCreateResponse is the response from the JetStream $JS.API.STREAM.CREATE API.
|
254
|
+
#
|
255
|
+
# @!attribute type
|
256
|
+
# @return [String]
|
257
|
+
# @!attribute config
|
258
|
+
# @return [StreamConfig]
|
259
|
+
# @!attribute created
|
260
|
+
# @return [String]
|
261
|
+
# @!attribute state
|
262
|
+
# @return [StreamState]
|
263
|
+
# @!attribute did_create
|
264
|
+
# @return [Boolean]
|
265
|
+
StreamCreateResponse = Struct.new(:type, :config, :created, :state, :did_create,
|
266
|
+
keyword_init: true) do
|
267
|
+
def initialize(opts={})
|
268
|
+
rem = opts.keys - members
|
269
|
+
opts.delete_if { |k| rem.include?(k) }
|
270
|
+
opts[:config] = StreamConfig.new(opts[:config])
|
271
|
+
opts[:state] = StreamState.new(opts[:state])
|
272
|
+
super(opts)
|
273
|
+
freeze
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
RawStreamMsg = Struct.new(:subject, :seq, :data, :headers, keyword_init: true) do
|
278
|
+
def initialize(opts)
|
279
|
+
opts[:data] = Base64.decode64(opts[:data]) if opts[:data]
|
280
|
+
if opts[:hdrs]
|
281
|
+
header = Base64.decode64(opts[:hdrs])
|
282
|
+
hdr = {}
|
283
|
+
lines = header.lines
|
284
|
+
lines.slice(1, header.size).each do |line|
|
285
|
+
line.rstrip!
|
286
|
+
next if line.empty?
|
287
|
+
key, value = line.strip.split(/\s*:\s*/, 2)
|
288
|
+
hdr[key] = value
|
289
|
+
end
|
290
|
+
opts[:headers] = hdr
|
291
|
+
end
|
292
|
+
|
293
|
+
# Filter out members not present.
|
294
|
+
rem = opts.keys - members
|
295
|
+
opts.delete_if { |k| rem.include?(k) }
|
296
|
+
super(opts)
|
297
|
+
end
|
298
|
+
|
299
|
+
def sequence
|
300
|
+
self.seq
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
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
|