nats-pure 0.7.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/nats/io/kv.rb ADDED
@@ -0,0 +1,172 @@
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 'errors'
15
+
16
+ module NATS
17
+ class KeyValue
18
+ KV_OP = "KV-Operation"
19
+ KV_DEL = "DEL"
20
+ KV_PURGE = "PURGE"
21
+ MSG_ROLLUP_SUBJECT = "sub"
22
+ MSG_ROLLUP_ALL = "all"
23
+
24
+ def initialize(opts={})
25
+ @name = opts[:name]
26
+ @stream = opts[:stream]
27
+ @pre = opts[:pre]
28
+ @js = opts[:js]
29
+ end
30
+
31
+ # When a key is not found because it was deleted.
32
+ class KeyDeletedError < NATS::Error; end
33
+
34
+ # When there was no bucket present.
35
+ class BucketNotFoundError < NATS::Error; end
36
+
37
+ # When it is an invalid bucket.
38
+ class BadBucketError < NATS::Error; end
39
+
40
+ # get returns the latest value for the key.
41
+ def get(key)
42
+ msg = @js.get_last_msg(@stream, "#{@pre}#{key}")
43
+ entry = Entry.new(bucket: @name, key: key, value: msg.data, revision: msg.seq)
44
+
45
+ if not msg.headers.nil?
46
+ op = msg.headers[KV_OP]
47
+ raise KeyDeletedError.new("nats: key was deleted") if op == KV_DEL or op == KV_PURGE
48
+ end
49
+
50
+ entry
51
+ end
52
+
53
+ # put will place the new value for the key into the store
54
+ # and return the revision number.
55
+ def put(key, value)
56
+ @js.publish("#{@pre}#{key}", value)
57
+ end
58
+
59
+ # delete will place a delete marker and remove all previous revisions.
60
+ def delete(key)
61
+ hdrs = {}
62
+ hdrs[KV_OP] = KV_DEL
63
+ @js.publish("#{@pre}#{key}", header: hdrs)
64
+ end
65
+
66
+ # status retrieves the status and configuration of a bucket.
67
+ def status
68
+ info = @js.stream_info(@stream)
69
+ BucketStatus.new(info, @name)
70
+ end
71
+
72
+ Entry = Struct.new(:bucket, :key, :value, :revision, keyword_init: true) do
73
+ def initialize(opts={})
74
+ rem = opts.keys - members
75
+ opts.delete_if { |k| rem.include?(k) }
76
+ super(opts)
77
+ end
78
+ end
79
+
80
+ class BucketStatus
81
+ attr_reader :bucket
82
+
83
+ def initialize(info, bucket)
84
+ @nfo = info
85
+ @bucket = bucket
86
+ end
87
+
88
+ def values
89
+ @nfo.state.messages
90
+ end
91
+
92
+ def history
93
+ @nfo.config.max_msgs_per_subject
94
+ end
95
+
96
+ def ttl
97
+ @nfo.config.max_age / 1_000_000_000
98
+ end
99
+ end
100
+
101
+ module API
102
+ KeyValueConfig = Struct.new(:bucket, :description, :max_value_size,
103
+ :history, :ttl, :max_bytes, :storage, :replicas,
104
+ keyword_init: true) do
105
+ def initialize(opts={})
106
+ rem = opts.keys - members
107
+ opts.delete_if { |k| rem.include?(k) }
108
+ super(opts)
109
+ end
110
+ end
111
+ end
112
+
113
+ module Manager
114
+ def key_value(bucket)
115
+ stream = "KV_#{bucket}"
116
+ begin
117
+ si = stream_info(stream)
118
+ rescue NATS::JetStream::Error::NotFound
119
+ raise BucketNotFoundError.new("nats: bucket not found")
120
+ end
121
+ if si.config.max_msgs_per_subject < 1
122
+ raise BadBucketError.new("nats: bad bucket")
123
+ end
124
+
125
+ KeyValue.new(
126
+ name: bucket,
127
+ stream: stream,
128
+ pre: "$KV.#{bucket}.",
129
+ js: self,
130
+ )
131
+ end
132
+
133
+ def create_key_value(config)
134
+ config = if not config.is_a?(JetStream::API::StreamConfig)
135
+ KeyValue::API::KeyValueConfig.new(config)
136
+ else
137
+ config
138
+ end
139
+ config.history ||= 1
140
+ config.replicas ||= 1
141
+ if config.ttl
142
+ config.ttl = config.ttl * 1_000_000_000
143
+ end
144
+
145
+ stream = JetStream::API::StreamConfig.new(
146
+ name: "KV_#{config.bucket}",
147
+ subjects: ["$KV.#{config.bucket}.>"],
148
+ max_msgs_per_subject: config.history,
149
+ max_bytes: config.max_bytes,
150
+ max_age: config.ttl,
151
+ max_msg_size: config.max_value_size,
152
+ storage: config.storage,
153
+ num_replicas: config.replicas,
154
+ allow_rollup_hdrs: true,
155
+ deny_delete: true,
156
+ )
157
+ resp = add_stream(stream)
158
+
159
+ KeyValue.new(
160
+ name: config.bucket,
161
+ stream: stream.name,
162
+ pre: "$KV.#{config.bucket}.",
163
+ js: self,
164
+ )
165
+ end
166
+
167
+ def delete_key_value(bucket)
168
+ delete_stream("KV_#{bucket}")
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,56 @@
1
+ # Copyright 2016-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 'js'
15
+
16
+ module NATS
17
+ class Msg
18
+ attr_accessor :subject, :reply, :data, :header
19
+
20
+ # Enhance it with ack related methods from JetStream to ack msgs.
21
+ include JetStream::Msg::AckMethods
22
+
23
+ def initialize(opts={})
24
+ @subject = opts[:subject]
25
+ @reply = opts[:reply]
26
+ @data = opts[:data]
27
+ @header = opts[:header]
28
+ @nc = opts[:nc]
29
+ @sub = opts[:sub]
30
+ @ackd = false
31
+ @meta = nil
32
+ end
33
+
34
+ def respond(data='')
35
+ return unless @nc
36
+ if self.header
37
+ dmsg = self.dup
38
+ dmsg.subject = self.reply
39
+ dmsg.data = data
40
+ @nc.publish_msg(dmsg)
41
+ else
42
+ @nc.publish(self.reply, data)
43
+ end
44
+ end
45
+
46
+ def respond_msg(msg)
47
+ return unless @nc
48
+ @nc.publish_msg(msg)
49
+ end
50
+
51
+ def inspect
52
+ hdr = ", header=#{@header}" if @header
53
+ "#<NATS::Msg(subject: \"#{@subject}\", reply: \"#{@reply}\", data: #{@data.slice(0, 10).inspect}#{hdr})>"
54
+ end
55
+ end
56
+ end
@@ -71,22 +71,22 @@ module NATS
71
71
  @buf = $'
72
72
  when ERR
73
73
  @buf = $'
74
- @nc.process_err($1)
74
+ @nc.send(:process_err, $1)
75
75
  when PING
76
76
  @buf = $'
77
- @nc.process_ping
77
+ @nc.send(:process_ping)
78
78
  when PONG
79
79
  @buf = $'
80
- @nc.process_pong
80
+ @nc.send(:process_pong)
81
81
  when INFO
82
82
  @buf = $'
83
83
  # First INFO message is processed synchronously on connect,
84
84
  # and onwards we would be receiving asynchronously INFO commands
85
85
  # signaling possible changes in the topology of the NATS cluster.
86
- @nc.process_info($1)
86
+ @nc.send(:process_info, $1)
87
87
  when UNKNOWN
88
88
  @buf = $'
89
- @nc.process_err("Unknown protocol: #{$1}")
89
+ @nc.send(:process_err, "Unknown protocol: #{$1}")
90
90
  else
91
91
  # If we are here we do not have a complete line yet that we understand.
92
92
  return
@@ -98,10 +98,10 @@ module NATS
98
98
  if @header_needed
99
99
  hbuf = @buf.slice(0, @header_needed)
100
100
  payload = @buf.slice(@header_needed, (@needed-@header_needed))
101
- @nc.process_msg(@sub, @sid, @reply, payload, hbuf)
101
+ @nc.send(:process_msg, @sub, @sid, @reply, payload, hbuf)
102
102
  @buf = @buf.slice((@needed + CR_LF_SIZE), @buf.bytesize)
103
103
  else
104
- @nc.process_msg(@sub, @sid, @reply, @buf.slice(0, @needed), nil)
104
+ @nc.send(:process_msg, @sub, @sid, @reply, @buf.slice(0, @needed), nil)
105
105
  @buf = @buf.slice((@needed + CR_LF_SIZE), @buf.bytesize)
106
106
  end
107
107
 
@@ -0,0 +1,92 @@
1
+ # Copyright 2016-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
+
17
+ # A Subscription represents interest in a given subject.
18
+ #
19
+ # @example Create NATS subscription with callback.
20
+ # require 'nats/client'
21
+ #
22
+ # nc = NATS.connect("demo.nats.io")
23
+ # sub = nc.subscribe("foo") do |msg|
24
+ # puts "Received [#{msg.subject}]: #{}"
25
+ # end
26
+ #
27
+ class Subscription
28
+ include MonitorMixin
29
+
30
+ attr_accessor :subject, :queue, :future, :callback, :response, :received, :max, :pending, :sid
31
+ attr_accessor :pending_queue, :pending_size, :wait_for_msgs_t, :wait_for_msgs_cond, :is_slow_consumer
32
+ attr_accessor :pending_msgs_limit, :pending_bytes_limit
33
+ attr_accessor :nc
34
+ attr_accessor :jsi
35
+ attr_accessor :closed
36
+
37
+ def initialize
38
+ super # required to initialize monitor
39
+ @subject = ''
40
+ @queue = nil
41
+ @future = nil
42
+ @callback = nil
43
+ @response = nil
44
+ @received = 0
45
+ @max = nil
46
+ @pending = nil
47
+ @sid = nil
48
+ @nc = nil
49
+ @closed = nil
50
+
51
+ # State from async subscriber messages delivery
52
+ @pending_queue = nil
53
+ @pending_size = 0
54
+ @pending_msgs_limit = nil
55
+ @pending_bytes_limit = nil
56
+ @wait_for_msgs_t = nil
57
+ @is_slow_consumer = false
58
+
59
+ # Sync subscriber
60
+ @wait_for_msgs_cond = nil
61
+ end
62
+
63
+ # Auto unsubscribes the server by sending UNSUB command and throws away
64
+ # subscription in case already present and has received enough messages.
65
+ def unsubscribe(opt_max=nil)
66
+ @nc.send(:unsubscribe, self, opt_max)
67
+ end
68
+
69
+ # next_msg blocks and waiting for the next message to be received.
70
+ def next_msg(opts={})
71
+ timeout = opts[:timeout] ||= 0.5
72
+ synchronize do
73
+ return @pending_queue.pop if not @pending_queue.empty?
74
+
75
+ # Wait for a bit until getting a signal.
76
+ MonotonicTime::with_nats_timeout(timeout) do
77
+ wait_for_msgs_cond.wait(timeout)
78
+ end
79
+
80
+ if not @pending_queue.empty?
81
+ return @pending_queue.pop
82
+ else
83
+ raise NATS::Timeout
84
+ end
85
+ end
86
+ end
87
+
88
+ def inspect
89
+ "#<NATS::Subscription(subject: \"#{@subject}\", queue: \"#{@queue}\", sid: #{@sid})>"
90
+ end
91
+ end
92
+ end
@@ -1,4 +1,4 @@
1
- # Copyright 2016-2021 The NATS Authors
1
+ # Copyright 2016-2022 The NATS Authors
2
2
  # Licensed under the Apache License, Version 2.0 (the "License");
3
3
  # you may not use this file except in compliance with the License.
4
4
  # You may obtain a copy of the License at
@@ -14,9 +14,13 @@
14
14
 
15
15
  module NATS
16
16
  module IO
17
- # NOTE: These are all announced to the server on CONNECT
18
- VERSION = "0.7.2"
19
- LANG = "#{RUBY_ENGINE}#{RUBY_VERSION}".freeze
17
+ # VERSION is the version of the client announced on CONNECT to the server.
18
+ VERSION = "2.0.0".freeze
19
+
20
+ # LANG is the lang runtime of the client announced on CONNECT to the server.
21
+ LANG = "#{RUBY_ENGINE}#{RUBY_VERSION}".freeze
22
+
23
+ # PROTOCOL is the supported version of the protocol in the client.
20
24
  PROTOCOL = 1
21
25
  end
22
26
  end
data/lib/nats.rb ADDED
@@ -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
+ require 'nats/io/client'
16
+ require 'nats/nuid'
17
+
18
+ # A thread safe Ruby client for the NATS messaging system (https://nats.io).
19
+ #
20
+ # @example Service example
21
+ # nc = NATS.connect("demo.nats.io")
22
+ # nc.subscribe("foo") do |msg|
23
+ # msg.respond("Hello World")
24
+ # end
25
+ #
26
+ # resp = nc.request("foo")
27
+ # puts "Received: #{msg.data}"
28
+ #
29
+ #
30
+ # @example Stream example
31
+ # nc = NATS.connect("demo.nats.io")
32
+ # sub = nc.subscribe("foo")
33
+ #
34
+ # nc.publish("foo")
35
+ # msg = sub.next_msg
36
+ # puts "Received: #{msg.data}"
37
+ #
38
+ module NATS
39
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nats-pure
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Waldemar Quevedo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-25 00:00:00.000000000 Z
11
+ date: 2022-01-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: NATS is an open-source, high-performance, lightweight cloud messaging
14
14
  system.
@@ -18,8 +18,15 @@ executables: []
18
18
  extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
+ - lib/nats.rb
22
+ - lib/nats/client.rb
21
23
  - lib/nats/io/client.rb
24
+ - lib/nats/io/errors.rb
25
+ - lib/nats/io/js.rb
26
+ - lib/nats/io/kv.rb
27
+ - lib/nats/io/msg.rb
22
28
  - lib/nats/io/parser.rb
29
+ - lib/nats/io/subscription.rb
23
30
  - lib/nats/io/version.rb
24
31
  - lib/nats/nuid.rb
25
32
  homepage: https://nats.io