ruby_nest_nats 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12ced8e11e87c01a5106285c4b01e7cb75f338adbb952b95d2362d928c76133c
4
- data.tar.gz: '049dd24c5e1015e8b3e90be3f77f352bd934c7837c71881e8f4235a47498e2ec'
3
+ metadata.gz: c27d22ced425f310876883bb15afd2aaa52b24235bb095551b7981bedca4b210
4
+ data.tar.gz: 2537c259848226de1481ce0579b2036200b7d0e45a2a6b098fddd988bae16b4d
5
5
  SHA512:
6
- metadata.gz: 3340f499fe967b290f3b2b21e2f34b69a55ed8b8a003c9e0af897df556890fcb884bdf99f25f67e5195a614c4fde21f311d395d7376bab07b1f51fe88bd37b56
7
- data.tar.gz: 23eabe3e8b26ba41f9e4ca38f55e8ae48c7362a4658d16d92a9b6284843d55ce34a912c3eae8ad8d312a14457b5ea230cc85422bbde3539c66b3788f1c52ba6d
6
+ metadata.gz: b8b7397a66a1f2984d54ae60bc3f299b384695f450a066cb00a64386fcfaf86be7dcad7e1c9e6f9fac4ede7994f41a2f1fa1cbd267563d5551dc2b53ac3512b0
7
+ data.tar.gz: a998c0f7015d4e6a1700ac23db6516cdd29572b92a1aaa18fe784b144862f5a229123820467a4d1e2e9baa5d5e30a618fbbe3bd526ac5e67b6640e08ca6b7e73
data/README.md CHANGED
@@ -6,11 +6,13 @@ The `ruby_nest_nats` gem allows you to listen for (and reply to) NATS messages a
6
6
 
7
7
  - [x] docs
8
8
  - [ ] tests
9
- - [ ] "controller"-style classes for reply organization
9
+ - [x] "controller"-style classes for reply organization
10
+ - [x] runtime subscription additions
10
11
  - [x] multiple queues
11
12
  - [ ] `on_error` handler so you can send a response (what's standard?)
12
13
  - [ ] config options for URL/host/port/etc.
13
14
  - [ ] config for restart behavior (default is to restart listening on any `StandardError`)
15
+ - [ ] consider using child processes instead of threads
14
16
 
15
17
  ## Installation
16
18
 
@@ -36,6 +38,10 @@ Alternatively, install it globally:
36
38
  gem install ruby_nest_nats
37
39
  ```
38
40
 
41
+ ### NATS server
42
+
43
+ **IMPORTANT:** This gem also requires a NATS server to be installed and running before use. See [the NATS documentation](https://docs.nats.io/nats-server/installation) for more details.
44
+
39
45
  ## Usage
40
46
 
41
47
  ### Logging
@@ -45,6 +51,7 @@ gem install ruby_nest_nats
45
51
  Attach a logger to have `ruby_nest_nats` write out logs for messages received, responses sent, errors raised, lifecycle events, etc.
46
52
 
47
53
  ```rb
54
+ require 'ruby_nest_nats'
48
55
  require 'logger'
49
56
 
50
57
  nats_logger = Logger.new(STDOUT)
@@ -68,6 +75,8 @@ The following will be logged at the specified log levels
68
75
  - `WARN`: Error handled gracefully (listening restarted due to some exception, etc.), as well as everything under `ERROR`
69
76
  - `ERROR`: Some exception was raised in-thread (error in handler, error in subscription, etc.)
70
77
 
78
+ <a id="default-queue-section"></a>
79
+
71
80
  ### Setting a default queue
72
81
 
73
82
  Set a default queue for subscriptions.
@@ -82,6 +91,8 @@ Leave the `::default_queue` blank (or assign `nil`) to use no default queue.
82
91
  RubyNestNats::Client.default_queue = nil
83
92
  ```
84
93
 
94
+ <a id="reply-to-section"></a>
95
+
85
96
  ### Registering message handlers
86
97
 
87
98
  Register a message handler with the `RubyNestNats::Client::reply_to` method. Pass a subject string as the first argument (either a static subject string or a pattern to match more than one subject). Specify a queue (or don't) with the `queue:` option. If you don't provide the `queue:` option, it will be set to the value of `default_queue`, or to `nil` (no queue) if a default queue hasn't been set.
@@ -116,10 +127,20 @@ Start listening for messages with the `RubyNestNats::Client::start!` method. Thi
116
127
  RubyNestNats::Client.start!
117
128
  ```
118
129
 
119
- ### Full example
130
+ ### Basic full working example (in vanilla Ruby)
131
+
132
+ The following should be enough to start a `ruby_nest_nats` setup in your Ruby application, using what we've learned so far.
133
+
134
+ > **NOTE:** For a more organized structure and implementation in a larger app (like a Rails project), see the ["controller" section below](#controller-section).
120
135
 
121
136
  ```rb
122
- RubyNestNats::Client.logger = Rails.logger
137
+ require 'ruby_nest_nats'
138
+ require 'logger'
139
+
140
+ nats_logger = Logger.new(STDOUT)
141
+ nats_logger.level = Logger::DEBUG
142
+
143
+ RubyNestNats::Client.logger = nats_logger
123
144
  RubyNestNats::Client.default_queue = "foobar"
124
145
 
125
146
  RubyNestNats::Client.reply_to("some.subject") { |data| "Got it! #{data.inspect}" }
@@ -129,6 +150,86 @@ RubyNestNats::Client.reply_to("subject.in.queue", queue: "barbaz") { { msg: "My
129
150
  RubyNestNats::Client.start!
130
151
  ```
131
152
 
153
+ > **NOTE:** You _can_ invoke `::reply_to` to create additional message subscriptions after `RubyNestNats::Client.start!`, but be aware that this forces the client to restart. You may see (benign, already-handled) errors in the logs generated when this restart happens. It will force the client to restart and re-subscribe after _each additional `::reply_to` invoked after `::start!`._ So, if you have a lot of additional `::reply_to` invocations, you may want to consider refactoring so that your call to `RubyNestNats::Client.start!` occurs _after_ those additions.
154
+
155
+ > **NOTE:** The `::start!` method can be safely called multiple times; only the first will be honored, and any subsequent calls to `::start!` after the client is already started will do nothing (except write a _"NATS is already running"_ log to the logger at the `DEBUG` level).
156
+
157
+ <a id="controller-section"></a>
158
+
159
+ ### Creating "controller"-style classes for listener organization
160
+
161
+ Create controller classes which inherit from `RubyNestNats::Controller` in order to give your message listeners some structure.
162
+
163
+ Use the `::default_queue` macro to set a default queue string. If omitted, the controller will fall back on the default queue assigned with `RubyNestNats::Client::default_queue=` (as described [here](#default-queue-section)). If no default queue is set in either the controller or globally, then the default queue will be blank.
164
+
165
+ Use the `::subject` macro to create a block for listening to that subject segment. Nested calls to `::subject` will append each subsequent subject/pattern string to the last (joined by a periods). There is no limit to the level of nesting.
166
+
167
+ You can register a response for the built-up subject/pattern string using the `::response` macro. Pass a block to `::response` which optionally takes two arguments ([the same arguments supplied to `RubyNestNats::Client::reply_to`](#reply-to-section)). The result of that block will be sent as a response to the message received.
168
+
169
+ ```rb
170
+ class HelloController < RubyNestNats::Controller
171
+ default_queue "foobar"
172
+
173
+ subject "hello" do
174
+ subject "jerk" do
175
+ response do |data|
176
+ # The subject at this point is "hello.jerk"
177
+ "Hey #{data['name']}... that's not cool, man."
178
+ end
179
+ end
180
+
181
+ subject "and" do
182
+ subject "wassup" do
183
+ response do |data|
184
+ # The subject at this point is "hello.and.wassup"
185
+ "Hey, how ya doin', #{data['name']}?"
186
+ end
187
+ end
188
+
189
+ subject "goodbye" do
190
+ response do |data|
191
+ # The subject at this point is "hello.and.goodbye"
192
+ "Hi #{data['name']}! But also GOODBYE."
193
+ end
194
+ end
195
+ end
196
+ end
197
+
198
+ subject "hows" do
199
+ subject "*" do
200
+ subject "doing" do
201
+ response do |data, subject|
202
+ # The subject at this point is "hows.<wildcard>.doing" (i.e., the
203
+ # subjects "hows.jack.doing" and "hows.jill.doing" will both match)
204
+ sender_name = data["name"]
205
+ other_person_name = subject.split(".")[1]
206
+ desc = rand < 0.5 ? "terribly" : "great"
207
+ "Well, #{sender_name}, #{other_person_name} is actually doing #{desc}."
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
213
+ ```
214
+
215
+ > **NOTE:** If you implement controllers like this and you are using code-autoloading machinery (like Zeitwerk in Rails), you will need to make sure these paths are eager-loaded when your app starts. **If you don't, `ruby_nest_nats` will not register the listeners,** and will not respond to messages for the specified subjects.
216
+ >
217
+ > For example: in a Rails project (assuming you have your NATS controllers in a directory called `app/nats/`), you may want to put something like the following in an initializer (such as `config/initializers/nats.rb`):
218
+ >
219
+ > ```rb
220
+ > RubyNestNats::Client.logger = Rails.logger
221
+ > RubyNestNats::Client.default_queue = "foobar"
222
+ >
223
+ > # ...
224
+ >
225
+ > Rails.application.config.after_initialize do
226
+ > nats_controller_paths = Dir[Rails.root.join("app", "nats", "**", "*_controller.rb")]
227
+ > nats_controller_paths.each { |file_path| require_dependency(file_path) }
228
+ >
229
+ > RubyNestNats::Client.start!
230
+ > end
231
+ > ```
232
+
132
233
  ## Development
133
234
 
134
235
  ### Install dependencies
@@ -139,7 +240,10 @@ To install the Ruby dependencies, run:
139
240
  bin/setup
140
241
  ```
141
242
 
142
- This gem also requires a NATS server to be running. See [the NATS documentation](https://docs.nats.io/nats-server/installation) for more details.
243
+ This gem also requires a NATS server to be installed and running. See [the NATS documentation](https://docs.nats.io/nats-server/installation) for more details.
244
+ <!-- sudo docker run -p 4222:4222 -p 8222:8222 -p 6222:6222 -ti nats:latest -->
245
+ <!-- nats-tail -s nats://localhost:4222 ">" -->
246
+ <!-- curl --data '{"name":"Keegan"}' --header 'Content-Type: application/json' http://localhost:3000/hello -->
143
247
 
144
248
  ### Open a console
145
249
 
@@ -1,164 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "ruby_nest_nats/version"
4
3
  require "nats/client"
4
+ require_relative "ruby_nest_nats/version"
5
+ require_relative "ruby_nest_nats/utils"
6
+ require_relative "ruby_nest_nats/client"
7
+ require_relative "ruby_nest_nats/controller"
5
8
 
6
9
  module RubyNestNats
7
10
  class Error < StandardError; end
8
-
9
- class Client
10
- class << self
11
- def logger=(some_logger)
12
- log("Setting the logger to #{some_logger.inspect}")
13
- @logger = some_logger
14
- end
15
-
16
- def logger
17
- @logger
18
- end
19
-
20
- def default_queue=(some_queue)
21
- queue = presence(some_queue.to_s)
22
- log("Setting the default queue to #{queue}", level: :debug)
23
- @default_queue = queue
24
- end
25
-
26
- def default_queue
27
- @default_queue
28
- end
29
-
30
- def started?
31
- @started ||= false
32
- end
33
-
34
- def stopped?
35
- !started?
36
- end
37
-
38
- def reply_to(subject, queue: nil, &block)
39
- subject = subject.to_s
40
- queue = (presence(queue) || default_queue).to_s
41
- log("Registering a reply handler for subject '#{subject}'#{" in queue '#{queue}'" if queue}", level: :debug)
42
- register_reply!(subject: subject, handler: block, queue: queue)
43
- end
44
-
45
- def listen
46
- NATS.start do
47
- replies.each do |replier|
48
- log("Subscribing to subject '#{replier[:subject]}'#{" in queue '#{replier[:queue]}'" if replier[:queue]}", level: :debug)
49
-
50
- NATS.subscribe(replier[:subject], queue: replier[:queue]) do |message, inbox, subject|
51
- parsed_message = JSON.parse(message)
52
- id, data, pattern = parsed_message.values_at("id", "data", "pattern")
53
-
54
- log("Received a message!")
55
- message_desc = <<~LOG_MESSAGE
56
- id: #{id || '(none)'}
57
- pattern: #{pattern || '(none)'}
58
- subject: #{subject || '(none)'}
59
- data: #{data.to_json}
60
- inbox: #{inbox || '(none)'}
61
- LOG_MESSAGE
62
- log(message_desc, indent: 2)
63
-
64
- response_data = replier[:handler].call(data)
65
-
66
- log("Responding with '#{response_data}'")
67
-
68
- NATS.publish(inbox, response_data.to_json, queue: replier[:queue])
69
- end
70
- end
71
- end
72
- end
73
-
74
- def stop!
75
- log("Stopping NATS", level: :debug)
76
- NATS.stop rescue nil
77
- stopped!
78
- end
79
-
80
- def restart!
81
- log("Restarting NATS", level: :warn)
82
- stop!
83
- start!
84
- end
85
-
86
- def start!
87
- log("Starting NATS", level: :debug)
88
-
89
- if started?
90
- log("NATS is already running", level: :debug)
91
- return
92
- end
93
-
94
- started!
95
-
96
- Thread.new do
97
- Thread.handle_interrupt(StandardError => :never) do
98
- begin
99
- Thread.handle_interrupt(StandardError => :immediate) { listen }
100
- rescue => e
101
- log("Encountered an error:", level: :error)
102
- log(e.full_message, level: :error, indent: 2)
103
-
104
- restart!
105
- raise e
106
- end
107
- end
108
- end
109
- end
110
-
111
- private
112
-
113
- def log(text, level: :info, indent: 0)
114
- return unless logger
115
-
116
- timestamp = Time.now.to_s
117
- text_lines = text.split("\n")
118
- indentation = indent.is_a?(String) ? indent : (" " * indent)
119
-
120
- text_lines.each do |line|
121
- logger.send(level, "[#{timestamp}] RubyNestNats | #{indentation}#{line}")
122
- end
123
- end
124
-
125
- def started!
126
- @started = true
127
- end
128
-
129
- def stopped!
130
- @started = false
131
- end
132
-
133
- def replies
134
- @replies ||= []
135
- end
136
-
137
- def reply_registered?(raw_subject)
138
- subject = raw_subject.to_s
139
- replies.any? { |reply| reply[:subject] == subject }
140
- end
141
-
142
- def register_reply!(subject:, handler:, queue: nil)
143
- raise StandardError, "NATS already started" if started? # TODO: remove when runtime additions are implemented
144
- raise ArgumentError, "Subject must be a string" unless subject.is_a?(String)
145
- raise ArgumentError, "Must provide a message handler for #{subject}" unless handler.respond_to?(:call)
146
- raise ArgumentError, "Already registered a reply to #{subject}" if reply_registered?(subject)
147
-
148
- replies << { subject: subject, handler: handler, queue: presence(queue) || default_queue }
149
- end
150
-
151
- def blank?(value)
152
- value.respond_to?(:empty?) ? value.empty? : !value
153
- end
154
-
155
- def present?(value)
156
- !blank?(value)
157
- end
158
-
159
- def presence(value)
160
- present?(value) ? value : nil
161
- end
162
- end
163
- end
11
+ class NewSubscriptionsError < StandardError; end
164
12
  end
@@ -0,0 +1,170 @@
1
+ require "json"
2
+ require "nats/client"
3
+ require_relative "./utils"
4
+
5
+ module RubyNestNats
6
+ class Client
7
+ class << self
8
+ def logger=(some_logger)
9
+ log("Setting the logger to #{some_logger.inspect}")
10
+ @logger = some_logger
11
+ end
12
+
13
+ def logger
14
+ @logger
15
+ end
16
+
17
+ def default_queue=(some_queue)
18
+ queue = Utils.presence(some_queue.to_s)
19
+ log("Setting the default queue to #{queue || '(none)'}", level: :debug)
20
+ @default_queue = queue
21
+ end
22
+
23
+ def default_queue
24
+ @default_queue
25
+ end
26
+
27
+ def started?
28
+ @started ||= false
29
+ end
30
+
31
+ def stopped?
32
+ !started?
33
+ end
34
+
35
+ def reply_to(subject, queue: nil, &block)
36
+ queue = Utils.presence(queue) || default_queue
37
+ log("Registering a reply handler for subject '#{subject}'#{" in queue '#{queue}'" if queue}", level: :debug)
38
+ register_reply!(subject: subject.to_s, handler: block, queue: queue.to_s)
39
+ end
40
+
41
+ def start!
42
+ log("Starting NATS", level: :debug)
43
+
44
+ if started?
45
+ log("NATS is already running", level: :debug)
46
+ return
47
+ end
48
+
49
+ started!
50
+
51
+ self.current_thread = Thread.new do
52
+ Thread.handle_interrupt(StandardError => :never) do
53
+ begin
54
+ Thread.handle_interrupt(StandardError => :immediate) { listen }
55
+ rescue NATS::ConnectError => e
56
+ log("Could not connect to NATS server:", level: :error)
57
+ log(e.full_message, level: :error, indent: 2)
58
+ Thread.current.exit
59
+ rescue NewSubscriptionsError => e
60
+ log("New subscriptions! Restarting...", level: :info)
61
+ restart!
62
+ raise e # TODO: there has to be a better way
63
+ rescue StandardError => e
64
+ log("Encountered an error:", level: :error)
65
+ log(e.full_message, level: :error, indent: 2)
66
+ restart!
67
+ raise e
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def log(text, level: :info, indent: 0)
76
+ return unless logger
77
+
78
+ timestamp = Time.now.to_s
79
+ text_lines = text.split("\n")
80
+ indentation = indent.is_a?(String) ? indent : (" " * indent)
81
+
82
+ text_lines.each do |line|
83
+ logger.send(level, "[#{timestamp}] RubyNestNats | #{indentation}#{line}")
84
+ end
85
+ end
86
+
87
+ def stop!
88
+ log("Stopping NATS", level: :debug)
89
+ NATS.stop rescue nil
90
+ stopped!
91
+ end
92
+
93
+ def restart!
94
+ log("Restarting NATS", level: :warn)
95
+ stop!
96
+ start!
97
+ end
98
+
99
+ def started!
100
+ @started = true
101
+ end
102
+
103
+ def stopped!
104
+ @started = false
105
+ end
106
+
107
+ def replies
108
+ @replies ||= []
109
+ end
110
+
111
+ def current_thread
112
+ @current_thread
113
+ end
114
+
115
+ def current_thread=(some_thread)
116
+ @current_thread = some_thread
117
+ end
118
+
119
+ def reply_registered?(raw_subject)
120
+ subject = raw_subject.to_s
121
+ replies.any? { |reply| reply[:subject] == subject }
122
+ end
123
+
124
+ def register_reply!(subject:, handler:, queue: nil)
125
+ raise ArgumentError, "Subject must be a string" unless subject.is_a?(String)
126
+ raise ArgumentError, "Must provide a message handler for #{subject}" unless handler.respond_to?(:call)
127
+ raise ArgumentError, "Already registered a reply to #{subject}" if reply_registered?(subject)
128
+
129
+ reply = {
130
+ subject: subject,
131
+ handler: handler,
132
+ queue: Utils.presence(queue) || default_queue
133
+ }
134
+
135
+ replies << reply
136
+
137
+ self.current_thread.raise(NewSubscriptionsError, "New reply registered") if started?
138
+ end
139
+
140
+ def listen
141
+ NATS.start do
142
+ replies.each do |replier|
143
+ log("Subscribing to subject '#{replier[:subject]}'#{" in queue '#{replier[:queue]}'" if replier[:queue]}", level: :debug)
144
+
145
+ NATS.subscribe(replier[:subject], queue: replier[:queue]) do |message, inbox, subject|
146
+ parsed_message = JSON.parse(message)
147
+ id, data, pattern = parsed_message.values_at("id", "data", "pattern")
148
+
149
+ log("Received a message!")
150
+ message_desc = <<~LOG_MESSAGE
151
+ id: #{id || '(none)'}
152
+ pattern: #{pattern || '(none)'}
153
+ subject: #{subject || '(none)'}
154
+ data: #{data.to_json}
155
+ inbox: #{inbox || '(none)'}
156
+ LOG_MESSAGE
157
+ log(message_desc, indent: 2)
158
+
159
+ response_data = replier[:handler].call(data)
160
+
161
+ log("Responding with '#{response_data}'")
162
+
163
+ NATS.publish(inbox, response_data.to_json, queue: replier[:queue])
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,67 @@
1
+ require_relative "./utils"
2
+
3
+ module RubyNestNats
4
+ class Controller
5
+ NO_QUEUE_GIVEN = :ruby_nest_nats_super_special_no_op_queue_symbol_qwertyuiop_1234567890
6
+
7
+ class << self
8
+ # Default queue for the controller. Falls back to the client's default
9
+ # queue if the controller's default queue is `nil`.
10
+ #
11
+ # - Call with no argument (`::default_queue`) to get the default queue.
12
+ # - Call as a macro with an argument (`default_queue "something"`) to set
13
+ # the default queue.
14
+ #
15
+ # Example:
16
+ #
17
+ # class FoobarNatsController < RubyNatsController
18
+ # default_queue "foobar"
19
+ #
20
+ # # ...
21
+ # end
22
+ #
23
+ def default_queue(some_queue = NO_QUEUE_GIVEN)
24
+ # `NO_QUEUE_GIVEN` is a special symbol (rather than `nil`) so that the
25
+ # default queue can be "unset" to `nil` (given a non-`nil` global
26
+ # default set with `RubyNestNats::Client::default_queue=`).
27
+ if some_queue == NO_QUEUE_GIVEN
28
+ @default_queue || Client.default_queue
29
+ else
30
+ @default_queue = Utils.presence(some_queue.to_s)
31
+ end
32
+ end
33
+
34
+ def subject(subject_segment, queue: nil)
35
+ subject_chain.push(subject_segment)
36
+ old_queue = current_queue
37
+ self.current_queue = queue if Utils.present?(queue)
38
+ yield
39
+ self.current_queue = old_queue
40
+ subject_chain.pop
41
+ end
42
+
43
+ def response(queue: nil, &block)
44
+ response_queue = Utils.presence(queue.to_s) || current_queue || default_queue
45
+ Client.reply_to(current_subject, queue: response_queue, &block)
46
+ end
47
+
48
+ private
49
+
50
+ def subject_chain
51
+ @subject_chain ||= []
52
+ end
53
+
54
+ def current_subject
55
+ subject_chain.join(".")
56
+ end
57
+
58
+ def current_queue
59
+ @current_queue ||= nil
60
+ end
61
+
62
+ def current_queue=(some_queue)
63
+ @current_queue = Utils.presence(some_queue)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,17 @@
1
+ module RubyNestNats
2
+ class Utils
3
+ class << self
4
+ def blank?(value)
5
+ value.respond_to?(:empty?) ? value.empty? : !value
6
+ end
7
+
8
+ def present?(value)
9
+ !blank?(value)
10
+ end
11
+
12
+ def presence(value)
13
+ present?(value) ? value : nil
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyNestNats
4
- VERSION = "0.1.3"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_nest_nats
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keegan Leitz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-12 00:00:00.000000000 Z
11
+ date: 2021-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -155,6 +155,9 @@ files:
155
155
  - bin/console
156
156
  - bin/setup
157
157
  - lib/ruby_nest_nats.rb
158
+ - lib/ruby_nest_nats/client.rb
159
+ - lib/ruby_nest_nats/controller.rb
160
+ - lib/ruby_nest_nats/utils.rb
158
161
  - lib/ruby_nest_nats/version.rb
159
162
  - ruby_nest_nats.gemspec
160
163
  homepage: https://github.com/openbay/ruby_nest_nats