nats-pure 2.2.0 → 2.3.0

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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +201 -0
  3. data/README.md +251 -0
  4. data/lib/nats/io/client.rb +226 -151
  5. data/lib/nats/io/errors.rb +6 -0
  6. data/lib/nats/io/jetstream/api.rb +305 -0
  7. data/lib/nats/io/jetstream/errors.rb +104 -0
  8. data/lib/nats/io/jetstream/js/config.rb +26 -0
  9. data/lib/nats/io/jetstream/js/header.rb +31 -0
  10. data/lib/nats/io/jetstream/js/status.rb +27 -0
  11. data/lib/nats/io/jetstream/js/sub.rb +30 -0
  12. data/lib/nats/io/jetstream/js.rb +93 -0
  13. data/lib/nats/io/jetstream/manager.rb +284 -0
  14. data/lib/nats/io/jetstream/msg/ack.rb +57 -0
  15. data/lib/nats/io/jetstream/msg/ack_methods.rb +111 -0
  16. data/lib/nats/io/jetstream/msg/metadata.rb +37 -0
  17. data/lib/nats/io/jetstream/msg.rb +26 -0
  18. data/lib/nats/io/jetstream/pull_subscription.rb +260 -0
  19. data/lib/nats/io/jetstream/push_subscription.rb +42 -0
  20. data/lib/nats/io/jetstream.rb +269 -0
  21. data/lib/nats/io/kv/api.rb +39 -0
  22. data/lib/nats/io/kv/bucket_status.rb +38 -0
  23. data/lib/nats/io/kv/errors.rb +60 -0
  24. data/lib/nats/io/kv/manager.rb +89 -0
  25. data/lib/nats/io/kv.rb +5 -157
  26. data/lib/nats/io/msg.rb +4 -2
  27. data/lib/nats/io/rails.rb +29 -0
  28. data/lib/nats/io/subscription.rb +70 -5
  29. data/lib/nats/io/version.rb +1 -1
  30. data/lib/nats/io/websocket.rb +75 -0
  31. data/sig/nats/io/client.rbs +304 -0
  32. data/sig/nats/io/errors.rbs +54 -0
  33. data/sig/nats/io/jetstream/api.rbs +35 -0
  34. data/sig/nats/io/jetstream/errors.rbs +54 -0
  35. data/sig/nats/io/jetstream/js/config.rbs +11 -0
  36. data/sig/nats/io/jetstream/js/header.rbs +17 -0
  37. data/sig/nats/io/jetstream/js/status.rbs +13 -0
  38. data/sig/nats/io/jetstream/js/sub.rbs +14 -0
  39. data/sig/nats/io/jetstream/js.rbs +27 -0
  40. data/sig/nats/io/jetstream/manager.rbs +33 -0
  41. data/sig/nats/io/jetstream/msg/ack.rbs +35 -0
  42. data/sig/nats/io/jetstream/msg/ack_methods.rbs +25 -0
  43. data/sig/nats/io/jetstream/msg/metadata.rbs +15 -0
  44. data/sig/nats/io/jetstream/msg.rbs +6 -0
  45. data/sig/nats/io/jetstream/pull_subscription.rbs +14 -0
  46. data/sig/nats/io/jetstream/push_subscription.rbs +7 -0
  47. data/sig/nats/io/jetstream.rbs +15 -0
  48. data/sig/nats/io/kv/api.rbs +8 -0
  49. data/sig/nats/io/kv/bucket_status.rbs +17 -0
  50. data/sig/nats/io/kv/errors.rbs +30 -0
  51. data/sig/nats/io/kv/manager.rbs +11 -0
  52. data/sig/nats/io/kv.rbs +39 -0
  53. data/sig/nats/io/msg.rbs +14 -0
  54. data/sig/nats/io/parser.rbs +32 -0
  55. data/sig/nats/io/subscription.rbs +33 -0
  56. data/sig/nats/io/version.rbs +9 -0
  57. data/sig/nats/nuid.rbs +32 -0
  58. metadata +68 -5
  59. data/lib/nats/io/js.rb +0 -1434
@@ -0,0 +1,260 @@
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
+
17
+ module NATS
18
+ class JetStream
19
+ # PullSubscription is included into NATS::Subscription so that it
20
+ # can be used to fetch messages from a pull based consumer from
21
+ # JetStream.
22
+ #
23
+ # @example Create a pull subscription using JetStream context.
24
+ #
25
+ # require 'nats/client'
26
+ #
27
+ # nc = NATS.connect
28
+ # js = nc.jetstream
29
+ # psub = js.pull_subscribe("foo", "bar")
30
+ #
31
+ # loop do
32
+ # msgs = psub.fetch(5)
33
+ # msgs.each do |msg|
34
+ # msg.ack
35
+ # end
36
+ # end
37
+ #
38
+ # @!visibility public
39
+ module PullSubscription
40
+ # next_msg is not available for pull based subscriptions.
41
+ # @raise [NATS::JetStream::Error]
42
+ def next_msg(params={})
43
+ raise ::NATS::JetStream::Error.new("nats: pull subscription cannot use next_msg")
44
+ end
45
+
46
+ # fetch makes a request to be delivered more messages from a pull consumer.
47
+ #
48
+ # @param batch [Fixnum] Number of messages to pull from the stream.
49
+ # @param params [Hash] Options to customize the fetch request.
50
+ # @option params [Float] :timeout Duration of the fetch request before it expires.
51
+ # @return [Array<NATS::Msg>]
52
+ def fetch(batch=1, params={})
53
+ if batch < 1
54
+ raise ::NATS::JetStream::Error.new("nats: invalid batch size")
55
+ end
56
+
57
+ t = MonotonicTime.now
58
+ timeout = params[:timeout] ||= 5
59
+ expires = (timeout * 1_000_000_000) - 100_000
60
+ next_req = {
61
+ batch: batch
62
+ }
63
+
64
+ msgs = []
65
+ case
66
+ when batch < 1
67
+ raise ::NATS::JetStream::Error.new("nats: invalid batch size")
68
+ when batch == 1
69
+ ####################################################
70
+ # Fetch (1) #
71
+ ####################################################
72
+
73
+ # Check if there is any pending message in the queue that is
74
+ # ready to be consumed.
75
+ synchronize do
76
+ unless @pending_queue.empty?
77
+ msg = @pending_queue.pop
78
+ @pending_size -= msg.data.size
79
+ # Check for a no msgs response status.
80
+ if JS.is_status_msg(msg)
81
+ case msg.header["Status"]
82
+ when JS::Status::NoMsgs
83
+ msg = nil
84
+ when JS::Status::RequestTimeout
85
+ # Skip
86
+ else
87
+ raise JS.from_msg(msg)
88
+ end
89
+ else
90
+ msgs << msg
91
+ end
92
+ end
93
+ end
94
+
95
+ # Make lingering request with expiration.
96
+ next_req[:expires] = expires
97
+ if msgs.empty?
98
+ # Make publish request and wait for response.
99
+ @nc.publish(@jsi.nms, JS.next_req_to_json(next_req), @subject)
100
+
101
+ # Wait for result of fetch or timeout.
102
+ synchronize { wait_for_msgs_cond.wait(timeout) }
103
+
104
+ unless @pending_queue.empty?
105
+ msg = @pending_queue.pop
106
+ @pending_size -= msg.data.size
107
+
108
+ msgs << msg
109
+ end
110
+
111
+ duration = MonotonicTime.since(t)
112
+ if duration > timeout
113
+ raise ::NATS::Timeout.new("nats: fetch timeout")
114
+ end
115
+
116
+ # Should have received at least a message at this point,
117
+ # if that is not the case then error already.
118
+ if JS.is_status_msg(msgs.first)
119
+ msg = msgs.first
120
+ case msg.header[JS::Header::Status]
121
+ when JS::Status::RequestTimeout
122
+ raise NATS::Timeout.new("nats: fetch request timeout")
123
+ else
124
+ raise JS.from_msg(msgs.first)
125
+ end
126
+ end
127
+ end
128
+ when batch > 1
129
+ ####################################################
130
+ # Fetch (n) #
131
+ ####################################################
132
+
133
+ # Check if there already enough in the pending buffer.
134
+ synchronize do
135
+ if batch <= @pending_queue.size
136
+ batch.times do
137
+ msg = @pending_queue.pop
138
+ @pending_size -= msg.data.size
139
+
140
+ # Check for a no msgs response status.
141
+ if JS.is_status_msg(msg)
142
+ case msg.header[JS::Header::Status]
143
+ when JS::Status::NoMsgs, JS::Status::RequestTimeout
144
+ # Skip these
145
+ next
146
+ else
147
+ raise JS.from_msg(msg)
148
+ end
149
+ else
150
+ msgs << msg
151
+ end
152
+ end
153
+
154
+ return msgs
155
+ end
156
+ end
157
+
158
+ # Make publish request and wait any response.
159
+ next_req[:no_wait] = true
160
+ @nc.publish(@jsi.nms, JS.next_req_to_json(next_req), @subject)
161
+
162
+ # Not receiving even one is a timeout.
163
+ start_time = MonotonicTime.now
164
+ msg = nil
165
+
166
+ synchronize do
167
+ wait_for_msgs_cond.wait(timeout)
168
+
169
+ unless @pending_queue.empty?
170
+ msg = @pending_queue.pop
171
+ @pending_size -= msg.data.size
172
+ end
173
+ end
174
+
175
+ # Check if the first message was a response saying that
176
+ # there are no messages.
177
+ if !msg.nil? && JS.is_status_msg(msg)
178
+ case msg.header[JS::Header::Status]
179
+ when JS::Status::NoMsgs
180
+ # Make another request that does wait.
181
+ next_req[:expires] = expires
182
+ next_req.delete(:no_wait)
183
+
184
+ @nc.publish(@jsi.nms, JS.next_req_to_json(next_req), @subject)
185
+ when JS::Status::RequestTimeout
186
+ raise NATS::Timeout.new("nats: fetch request timeout")
187
+ else
188
+ raise JS.from_msg(msg)
189
+ end
190
+ else
191
+ msgs << msg unless msg.nil?
192
+ end
193
+
194
+ # Check if have not received yet a single message.
195
+ duration = MonotonicTime.since(start_time)
196
+ if msgs.empty? and duration > timeout
197
+ raise NATS::Timeout.new("nats: fetch timeout")
198
+ end
199
+
200
+ needed = batch - msgs.count
201
+ while needed > 0 and MonotonicTime.since(start_time) < timeout
202
+ duration = MonotonicTime.since(start_time)
203
+
204
+ # Wait for the rest of the messages.
205
+ synchronize do
206
+
207
+ # Wait until there is a message delivered.
208
+ if @pending_queue.empty?
209
+ deadline = timeout - duration
210
+ wait_for_msgs_cond.wait(deadline) if deadline > 0
211
+
212
+ duration = MonotonicTime.since(start_time)
213
+ if msgs.empty? && @pending_queue.empty? and duration > timeout
214
+ raise NATS::Timeout.new("nats: fetch timeout")
215
+ end
216
+ else
217
+ msg = @pending_queue.pop
218
+ @pending_size -= msg.data.size
219
+
220
+ if JS.is_status_msg(msg)
221
+ case msg.header[JS::Header::Status]
222
+ when JS::Status::NoMsgs, JS::Status::RequestTimeout
223
+ duration = MonotonicTime.since(start_time)
224
+
225
+ if duration > timeout
226
+ # Only received a subset of the messages.
227
+ if !msgs.empty?
228
+ return msgs
229
+ else
230
+ raise NATS::Timeout.new("nats: fetch timeout")
231
+ end
232
+ end
233
+ else
234
+ raise JS.from_msg(msg)
235
+ end
236
+
237
+ else
238
+ # Add to the set of messages that will be returned.
239
+ msgs << msg
240
+ needed -= 1
241
+ end
242
+ end
243
+ end # :end: synchronize
244
+ end
245
+ end
246
+
247
+ msgs
248
+ end
249
+
250
+ # consumer_info retrieves the current status of the pull subscription consumer.
251
+ # @param params [Hash] Options to customize API request.
252
+ # @option params [Float] :timeout Time to wait for response.
253
+ # @return [JetStream::API::ConsumerInfo] The latest ConsumerInfo of the consumer.
254
+ def consumer_info(params={})
255
+ @jsi.js.consumer_info(@jsi.stream, @jsi.consumer, params)
256
+ end
257
+ end
258
+ private_constant :PullSubscription
259
+ end
260
+ end
@@ -0,0 +1,42 @@
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
+ # PushSubscription is included into NATS::Subscription so that it
18
+ #
19
+ # @example Create a push subscription using JetStream context.
20
+ #
21
+ # require 'nats/client'
22
+ #
23
+ # nc = NATS.connect
24
+ # js = nc.jetstream
25
+ # sub = js.subscribe("foo", "bar")
26
+ # msg = sub.next_msg
27
+ # msg.ack
28
+ # sub.unsubscribe
29
+ #
30
+ # @!visibility public
31
+ module PushSubscription
32
+ # consumer_info retrieves the current status of the pull subscription consumer.
33
+ # @param params [Hash] Options to customize API request.
34
+ # @option params [Float] :timeout Time to wait for response.
35
+ # @return [JetStream::API::ConsumerInfo] The latest ConsumerInfo of the consumer.
36
+ def consumer_info(params={})
37
+ @jsi.js.consumer_info(@jsi.stream, @jsi.consumer, params)
38
+ end
39
+ end
40
+ private_constant :PushSubscription
41
+ end
42
+ end
@@ -0,0 +1,269 @@
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
+ require_relative 'msg'
15
+ require_relative 'client'
16
+ require_relative 'errors'
17
+ require_relative 'kv'
18
+ require_relative 'jetstream/api'
19
+ require_relative 'jetstream/errors'
20
+ require_relative 'jetstream/js'
21
+ require_relative 'jetstream/manager'
22
+ require_relative 'jetstream/msg'
23
+ require_relative 'jetstream/pull_subscription'
24
+ require_relative 'jetstream/push_subscription'
25
+
26
+ module NATS
27
+ # JetStream returns a context with a similar API as the NATS::Client
28
+ # but with enhanced functions to persist and consume messages from
29
+ # the NATS JetStream engine.
30
+ #
31
+ # @example
32
+ # nc = NATS.connect("demo.nats.io")
33
+ # js = nc.jetstream()
34
+ #
35
+ class JetStream
36
+ # Create a new JetStream context for a NATS connection.
37
+ #
38
+ # @param conn [NATS::Client]
39
+ # @param params [Hash] Options to customize JetStream context.
40
+ # @option params [String] :prefix JetStream API prefix to use for the requests.
41
+ # @option params [String] :domain JetStream Domain to use for the requests.
42
+ # @option params [Float] :timeout Default timeout to use for JS requests.
43
+ def initialize(conn, params={})
44
+ @nc = conn
45
+ @prefix = if params[:prefix]
46
+ params[:prefix]
47
+ elsif params[:domain]
48
+ "$JS.#{params[:domain]}.API"
49
+ else
50
+ JS::DefaultAPIPrefix
51
+ end
52
+ @opts = params
53
+ @opts[:timeout] ||= 5 # seconds
54
+ params[:prefix] = @prefix
55
+
56
+ # Include JetStream::Manager
57
+ extend Manager
58
+ extend KeyValue::Manager
59
+ end
60
+
61
+ # PubAck is the API response from a successfully published message.
62
+ #
63
+ # @!attribute [stream] stream
64
+ # @return [String] Name of the stream that processed the published message.
65
+ # @!attribute [seq] seq
66
+ # @return [Fixnum] Sequence of the message in the stream.
67
+ # @!attribute [duplicate] duplicate
68
+ # @return [Boolean] Indicates whether the published message is a duplicate.
69
+ # @!attribute [domain] domain
70
+ # @return [String] JetStream Domain that processed the ack response.
71
+ PubAck = Struct.new(:stream, :seq, :duplicate, :domain, keyword_init: true)
72
+
73
+ # publish produces a message for JetStream.
74
+ #
75
+ # @param subject [String] The subject from a stream where the message will be sent.
76
+ # @param payload [String] The payload of the message.
77
+ # @param params [Hash] Options to customize the publish message request.
78
+ # @option params [Float] :timeout Time to wait for an PubAck response or an error.
79
+ # @option params [Hash] :header NATS Headers to use for the message.
80
+ # @option params [String] :stream Expected Stream to which the message is being published.
81
+ # @raise [NATS::Timeout] When it takes too long to receive an ack response.
82
+ # @return [PubAck] The pub ack response.
83
+ def publish(subject, payload="", **params)
84
+ params[:timeout] ||= @opts[:timeout]
85
+ if params[:stream]
86
+ params[:header] ||= {}
87
+ params[:header][JS::Header::ExpectedStream] = params[:stream]
88
+ end
89
+
90
+ # Send message with headers.
91
+ msg = NATS::Msg.new(subject: subject,
92
+ data: payload,
93
+ header: params[:header])
94
+
95
+ begin
96
+ resp = @nc.request_msg(msg, **params)
97
+ result = JSON.parse(resp.data, symbolize_names: true)
98
+ rescue ::NATS::IO::NoRespondersError
99
+ raise JetStream::Error::NoStreamResponse.new("nats: no response from stream")
100
+ end
101
+ raise JS.from_error(result[:error]) if result[:error]
102
+
103
+ PubAck.new(result)
104
+ end
105
+
106
+ # subscribe binds or creates a push subscription to a JetStream pull consumer.
107
+ #
108
+ # @param subject [String] Subject from which the messages will be fetched.
109
+ # @param params [Hash] Options to customize the PushSubscription.
110
+ # @option params [String] :stream Name of the Stream to which the consumer belongs.
111
+ # @option params [String] :consumer Name of the Consumer to which the PushSubscription will be bound.
112
+ # @option params [String] :durable Consumer durable name from where the messages will be fetched.
113
+ # @option params [Hash] :config Configuration for the consumer.
114
+ # @return [NATS::JetStream::PushSubscription]
115
+ def subscribe(subject, params={}, &cb)
116
+ params[:consumer] ||= params[:durable]
117
+ stream = params[:stream].nil? ? find_stream_name_by_subject(subject) : params[:stream]
118
+
119
+ queue = params[:queue]
120
+ durable = params[:durable]
121
+ flow_control = params[:flow_control]
122
+ manual_ack = params[:manual_ack]
123
+ idle_heartbeat = params[:idle_heartbeat]
124
+ flow_control = params[:flow_control]
125
+ config = params[:config]
126
+
127
+ if queue
128
+ if durable and durable != queue
129
+ raise NATS::JetStream::Error.new("nats: cannot create queue subscription '#{queue}' to consumer '#{durable}'")
130
+ else
131
+ durable = queue
132
+ end
133
+ end
134
+
135
+ cinfo = nil
136
+ consumer_found = false
137
+ should_create = false
138
+
139
+ if not durable
140
+ should_create = true
141
+ else
142
+ begin
143
+ cinfo = consumer_info(stream, durable)
144
+ config = cinfo.config
145
+ consumer_found = true
146
+ consumer = durable
147
+ rescue NATS::JetStream::Error::NotFound
148
+ should_create = true
149
+ consumer_found = false
150
+ end
151
+ end
152
+
153
+ if consumer_found
154
+ if not config.deliver_group
155
+ if queue
156
+ raise NATS::JetStream::Error.new("nats: cannot create a queue subscription for a consumer without a deliver group")
157
+ elsif cinfo.push_bound
158
+ raise NATS::JetStream::Error.new("nats: consumer is already bound to a subscription")
159
+ end
160
+ else
161
+ if not queue
162
+ raise NATS::JetStream::Error.new("nats: cannot create a subscription for a consumer with a deliver group #{config.deliver_group}")
163
+ elsif queue != config.deliver_group
164
+ raise NATS::JetStream::Error.new("nats: cannot create a queue subscription #{queue} for a consumer with a deliver group #{config.deliver_group}")
165
+ end
166
+ end
167
+ elsif should_create
168
+ # Auto-create consumer if none found.
169
+ if config.nil?
170
+ # Defaults
171
+ config = JetStream::API::ConsumerConfig.new({ack_policy: "explicit"})
172
+ elsif config.is_a?(Hash)
173
+ config = JetStream::API::ConsumerConfig.new(config)
174
+ elsif !config.is_a?(JetStream::API::ConsumerConfig)
175
+ raise NATS::JetStream::Error.new("nats: invalid ConsumerConfig")
176
+ end
177
+
178
+ config.durable_name = durable if not config.durable_name
179
+ config.deliver_group = queue if not config.deliver_group
180
+
181
+ # Create inbox for push consumer.
182
+ deliver = @nc.new_inbox
183
+ config.deliver_subject = deliver
184
+
185
+ # Auto created consumers use the filter subject.
186
+ config.filter_subject = subject
187
+
188
+ # Heartbeats / FlowControl
189
+ config.flow_control = flow_control
190
+ if idle_heartbeat or config.idle_heartbeat
191
+ idle_heartbeat = config.idle_heartbeat if config.idle_heartbeat
192
+ idle_heartbeat = idle_heartbeat * ::NATS::NANOSECONDS
193
+ config.idle_heartbeat = idle_heartbeat
194
+ end
195
+
196
+ # Auto create the consumer.
197
+ cinfo = add_consumer(stream, config)
198
+ consumer = cinfo.name
199
+ end
200
+
201
+ # Enable auto acking for async callbacks unless disabled.
202
+ if cb and not manual_ack
203
+ ocb = cb
204
+ new_cb = proc do |msg|
205
+ ocb.call(msg)
206
+ msg.ack rescue JetStream::Error::MsgAlreadyAckd
207
+ end
208
+ cb = new_cb
209
+ end
210
+ sub = @nc.subscribe(config.deliver_subject, queue: config.deliver_group, &cb)
211
+ sub.extend(PushSubscription)
212
+ sub.jsi = JS::Sub.new(
213
+ js: self,
214
+ stream: stream,
215
+ consumer: consumer,
216
+ )
217
+ sub
218
+ end
219
+
220
+ # pull_subscribe binds or creates a subscription to a JetStream pull consumer.
221
+ #
222
+ # @param subject [String] Subject from which the messages will be fetched.
223
+ # @param durable [String] Consumer durable name from where the messages will be fetched.
224
+ # @param params [Hash] Options to customize the PullSubscription.
225
+ # @option params [String] :stream Name of the Stream to which the consumer belongs.
226
+ # @option params [String] :consumer Name of the Consumer to which the PullSubscription will be bound.
227
+ # @option params [Hash] :config Configuration for the consumer.
228
+ # @return [NATS::JetStream::PullSubscription]
229
+ def pull_subscribe(subject, durable, params={})
230
+ if durable.empty? && !params[:consumer]
231
+ raise JetStream::Error::InvalidDurableName.new("nats: invalid durable name")
232
+ end
233
+ params[:consumer] ||= durable
234
+ stream = params[:stream].nil? ? find_stream_name_by_subject(subject) : params[:stream]
235
+
236
+ begin
237
+ consumer_info(stream, params[:consumer])
238
+ rescue NATS::JetStream::Error::NotFound => e
239
+ # If attempting to bind, then this is a hard error.
240
+ raise e if params[:stream]
241
+
242
+ config = if not params[:config]
243
+ JetStream::API::ConsumerConfig.new
244
+ elsif params[:config].is_a?(JetStream::API::ConsumerConfig)
245
+ params[:config]
246
+ else
247
+ JetStream::API::ConsumerConfig.new(params[:config])
248
+ end
249
+ config[:durable_name] = durable
250
+ config[:ack_policy] ||= JS::Config::AckExplicit
251
+ add_consumer(stream, config)
252
+ end
253
+
254
+ deliver = @nc.new_inbox
255
+ sub = @nc.subscribe(deliver)
256
+ sub.extend(PullSubscription)
257
+
258
+ consumer = params[:consumer]
259
+ subject = "#{@prefix}.CONSUMER.MSG.NEXT.#{stream}.#{consumer}"
260
+ sub.jsi = JS::Sub.new(
261
+ js: self,
262
+ stream: stream,
263
+ consumer: params[:consumer],
264
+ nms: subject
265
+ )
266
+ sub
267
+ end
268
+ end
269
+ end
@@ -0,0 +1,39 @@
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 KeyValue
17
+ module API
18
+ KeyValueConfig = Struct.new(
19
+ :bucket,
20
+ :description,
21
+ :max_value_size,
22
+ :history,
23
+ :ttl,
24
+ :max_bytes,
25
+ :storage,
26
+ :replicas,
27
+ :placement,
28
+ :republish,
29
+ :direct,
30
+ keyword_init: true) do
31
+ def initialize(opts={})
32
+ rem = opts.keys - members
33
+ opts.delete_if { |k| rem.include?(k) }
34
+ super(opts)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,38 @@
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 KeyValue
17
+ class BucketStatus
18
+ attr_reader :bucket
19
+
20
+ def initialize(info, bucket)
21
+ @nfo = info
22
+ @bucket = bucket
23
+ end
24
+
25
+ def values
26
+ @nfo.state.messages
27
+ end
28
+
29
+ def history
30
+ @nfo.config.max_msgs_per_subject
31
+ end
32
+
33
+ def ttl
34
+ @nfo.config.max_age / ::NATS::NANOSECONDS
35
+ end
36
+ end
37
+ end
38
+ end