nats-streaming 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2b4619f24307110860a56b03d04b15be8c8f35b3
4
+ data.tar.gz: 79e03889f056cfbd5fb64491c236ffe66b99f4e9
5
+ SHA512:
6
+ metadata.gz: 64d4045d951790d2207aa80cc5732b0f08078f7fe244f5ea033663c74a70f901d78e5015758300fa198a7fb35457fb70ad0f5a311ca0be83a6ccaae37ef745f4
7
+ data.tar.gz: 7cbbcef0b8ab55e53b8ca2124427ff41f77356eb326d775106249ea58c880cea88dd065657df323289abea2e7dbae517cb6383be4a26133a35857355b6cfbafc
@@ -0,0 +1,531 @@
1
+ require 'stan/pb/protocol.pb'
2
+ require 'nats/io/client'
3
+ require 'securerandom'
4
+ require 'monitor'
5
+
6
+ module STAN
7
+
8
+ # Subject namespaces for clients to ack and connect
9
+ DEFAULT_ACKS_SUBJECT = "_STAN.acks".freeze
10
+ DEFAULT_DISCOVER_SUBJECT = "_STAN.discover".freeze
11
+
12
+ # Ack timeout in seconds
13
+ DEFAULT_ACK_WAIT = 30
14
+
15
+ # Max number of inflight acks from received messages
16
+ DEFAULT_MAX_INFLIGHT = 1024
17
+
18
+ # Connect timeout in seconds
19
+ DEFAULT_CONNECT_TIMEOUT = 2
20
+
21
+ # Max number of inflight pub acks
22
+ DEFAULT_MAX_PUB_ACKS_INFLIGHT = 16384
23
+
24
+ # Errors
25
+ class Error < StandardError; end
26
+
27
+ # When we detect we cannot connect to the server
28
+ class ConnectError < Error; end
29
+
30
+ # When we detect we have a request timeout
31
+ class TimeoutError < Error; end
32
+
33
+ class Client
34
+ include MonitorMixin
35
+
36
+ attr_reader :nats, :options, :client_id, :sub_map, :unsub_req_subject, :sub_close_req_subject, :pending_pub_acks
37
+
38
+ def initialize
39
+ super
40
+
41
+ # Connection to NATS, either owned or borrowed
42
+ @nats = nil
43
+ @borrowed_nats_connection = false
44
+
45
+ # STAN subscriptions map
46
+ @sub_map = {}
47
+
48
+ # Publish Ack map (guid => ack)
49
+ @pub_ack_map = {}
50
+ @pending_pub_acks = nil
51
+
52
+ # Cluster to which we are connecting
53
+ @cluster_id = nil
54
+ @client_id = nil
55
+
56
+ # Connect options
57
+ @options = {}
58
+
59
+ # NATS Streaming subjects
60
+
61
+ # Inbox subscription for periodical heartbeat messages
62
+ @hb_inbox = nil
63
+ @hb_inbox_sid = nil
64
+
65
+ # Subscription for processing received acks from the server
66
+ @ack_subject = nil
67
+ @ack_subject_sid = nil
68
+
69
+ # Publish prefix set by stan to which we append our subject on publish.
70
+ @pub_prefix = nil
71
+ @sub_req_subject = nil
72
+ @unsub_req_subject = nil
73
+ @close_req_subject = nil
74
+ @sub_close_req_subject = nil
75
+
76
+ # For initial connect request to discover subjects used by
77
+ # the streaming server.
78
+ @discover_subject = nil
79
+ end
80
+
81
+ # Plugs into a NATS Streaming cluster, establishing a connection
82
+ # to NATS in case there is not one available to be borrowed.
83
+ def connect(cluster_id, client_id, opts={}, &blk)
84
+ @cluster_id = cluster_id
85
+ @client_id = client_id
86
+ @options = opts
87
+
88
+ # Defaults
89
+ @options[:connect_timeout] ||= DEFAULT_CONNECT_TIMEOUT
90
+ @options[:max_pub_acks_inflight] ||= DEFAULT_MAX_PUB_ACKS_INFLIGHT
91
+
92
+ # Buffered queue for controlling inflight published acks
93
+ @pending_pub_acks = SizedQueue.new(options[:max_pub_acks_inflight])
94
+
95
+ # Prepare connect discovery request
96
+ @discover_subject = "#{DEFAULT_DISCOVER_SUBJECT}.#{@cluster_id}".freeze
97
+
98
+ # Prepare delivered msgs acks processing subscription
99
+ @ack_subject = "#{DEFAULT_ACKS_SUBJECT}.#{STAN.create_guid}".freeze
100
+
101
+ if @nats.nil?
102
+ case options[:nats]
103
+ when Hash
104
+ # Custom NATS options in case borrowed connection not present
105
+ # can be passed to establish a connection and have stan client
106
+ # owning it.
107
+ @nats = NATS::IO::Client.new
108
+ nats.connect(options[:nats])
109
+ when NATS::IO::Client
110
+ @nats = options[:nats]
111
+ @borrowed_nats_connection = true
112
+ else
113
+ # Try to connect with NATS defaults
114
+ @nats = NATS::IO::Client.new
115
+ nats.connect(servers: ["nats://127.0.0.1:4222"])
116
+ end
117
+ end
118
+
119
+ # If no connection to NATS present at this point then bail already
120
+ raise ConnectError.new("stan: invalid connection to nats") unless @nats
121
+
122
+ # Heartbeat subscription
123
+ @hb_inbox = (STAN.create_inbox).freeze
124
+
125
+ # Setup acks and heartbeats processing callbacks
126
+ @hb_inbox_sid = nats.subscribe(@hb_inbox) { |raw| process_heartbeats(raw) }
127
+ @ack_subject_sid = nats.subscribe(@ack_subject) { |raw| process_ack(raw) }
128
+ nats.flush
129
+
130
+ # Initial connect request to discover subjects to be used
131
+ # for communicating with STAN.
132
+ req = STAN::Protocol::ConnectRequest.new({
133
+ clientID: @client_id,
134
+ heartbeatInbox: @hb_inbox
135
+ })
136
+
137
+ # TODO: Check for error and bail if required
138
+ raw = nats.request(@discover_subject, req.to_proto, timeout: options[:connect_timeout])
139
+ resp = STAN::Protocol::ConnectResponse.decode(raw.data)
140
+ @pub_prefix = resp.pubPrefix.freeze
141
+ @sub_req_subject = resp.subRequests.freeze
142
+ @unsub_req_subject = resp.unsubRequests.freeze
143
+ @close_req_subject = resp.closeRequests.freeze
144
+ @sub_close_req_subject = resp.subCloseRequests.freeze
145
+
146
+ # If callback given then we send a close request on exit
147
+ # and wrap up session to STAN.
148
+ if blk
149
+ blk.call(self)
150
+
151
+ # Close session to the STAN cluster
152
+ close
153
+ end
154
+ end
155
+
156
+ # Publish will publish to the cluster and wait for an ack
157
+ def publish(subject, payload, opts={}, &blk)
158
+ stan_subject = "#{@pub_prefix}.#{subject}"
159
+ future = nil
160
+ guid = STAN.create_guid
161
+
162
+ pe = STAN::Protocol::PubMsg.new({
163
+ clientID: @client_id,
164
+ guid: guid,
165
+ subject: subject,
166
+ data: payload
167
+ })
168
+
169
+ # Use buffered queue to control number of outstanding acks
170
+ @pending_pub_acks << :ack
171
+
172
+ if blk
173
+ # Asynchronously handled if block given
174
+ synchronize do
175
+ # Map ack to guid
176
+ @pub_ack_map[guid] = proc do |ack|
177
+ # If block is given, handle the result asynchronously
178
+ error = ack.error.empty? ? nil : Error.new(ack.error)
179
+ case blk.arity
180
+ when 0 then blk.call
181
+ when 1 then blk.call(ack.guid)
182
+ when 2 then blk.call(ack.guid, error)
183
+ end
184
+
185
+ @pub_ack_map.delete(ack.guid)
186
+ end
187
+
188
+ nats.publish(stan_subject, pe.to_proto, @ack_subject)
189
+ end
190
+ else
191
+ # No block means waiting for response before giving back control
192
+ future = new_cond
193
+ opts[:timeout] ||= DEFAULT_ACK_WAIT
194
+
195
+ synchronize do
196
+ # Map ack to guid
197
+ ack_response = nil
198
+
199
+ # FIXME: Maybe use fiber instead?
200
+ @pub_ack_map[guid] = proc do |ack|
201
+ # Capture the ack response
202
+ ack_response = ack
203
+ future.signal
204
+ end
205
+
206
+ # Send publish request and wait for the ack response
207
+ nats.publish(stan_subject, pe.to_proto, @ack_subject)
208
+ start_time = NATS::MonotonicTime.now
209
+ future.wait(opts[:timeout])
210
+ end_time = NATS::MonotonicTime.now
211
+ if (end_time - start_time) > opts[:timeout]
212
+ # Remove ack
213
+ @pub_ack_map.delete(guid)
214
+ raise TimeoutError.new("stan: timeout")
215
+ end
216
+
217
+ # Remove ack
218
+ @pub_ack_map.delete(guid)
219
+ return guid
220
+ end
221
+ end
222
+ # TODO: Loop for processing of expired acks
223
+ end
224
+
225
+ # Create subscription which dispatches messages to callback asynchronously
226
+ def subscribe(subject, opts={}, &cb)
227
+ sub_options = {}
228
+ sub_options.merge!(opts)
229
+ sub_options[:ack_wait] ||= DEFAULT_ACK_WAIT
230
+ sub_options[:max_inflight] ||= DEFAULT_MAX_INFLIGHT
231
+ sub_options[:stan] = self
232
+
233
+ sub = Subscription.new(subject, sub_options, cb)
234
+ sub.extend(MonitorMixin)
235
+ synchronize { @sub_map[sub.inbox] = sub }
236
+
237
+ # Hold lock throughout
238
+ sub.synchronize do
239
+ # Listen for actual messages
240
+ sid = nats.subscribe(sub.inbox) { |raw, reply, subject| process_msg(raw, reply, subject) }
241
+ sub.sid = sid
242
+ nats.flush
243
+
244
+ # Create the subscription request announcing the inbox on which
245
+ # we have made the NATS subscription for processing messages.
246
+ # First, we normalize customized subscription options before
247
+ # encoding to protobuf.
248
+ sub_opts = normalize_sub_req_params(sub_options)
249
+
250
+ # Set STAN subject and NATS inbox where we will be awaiting
251
+ # for the messages to be delivered.
252
+ sub_opts[:subject] = subject
253
+ sub_opts[:inbox] = sub.inbox
254
+
255
+ sr = STAN::Protocol::SubscriptionRequest.new(sub_opts)
256
+ reply = nil
257
+ response = nil
258
+ begin
259
+ reply = nats.request(@sub_req_subject, sr.to_proto, timeout: options[:connect_timeout])
260
+ response = STAN::Protocol::SubscriptionResponse.decode(reply.data)
261
+ rescue NATS::IO::Timeout, Google::Protobuf::ParseError => e
262
+ # FIXME: Error handling on unsubscribe
263
+ nats.unsubscribe(sub.sid)
264
+ raise e
265
+ end
266
+
267
+ unless response.error.empty?
268
+ # FIXME: Error handling on unsubscribe
269
+ nats.unsubscribe(sub.sid)
270
+ raise Error.new(response.error)
271
+ end
272
+
273
+ # Capture ack inbox for the subscription
274
+ sub.ack_inbox = response.ackInbox.freeze
275
+
276
+ return sub
277
+ end
278
+ end
279
+
280
+ # Close wraps us the session with the NATS Streaming server
281
+ def close
282
+ req = STAN::Protocol::CloseRequest.new(clientID: @client_id)
283
+ raw = nats.request(@close_req_subject, req.to_proto)
284
+
285
+ resp = STAN::Protocol::CloseResponse.decode(raw.data)
286
+ unless resp.error.empty?
287
+ raise Error.new(resp.error)
288
+ end
289
+
290
+ # TODO: If connection to nats was borrowed then we should
291
+ # unsubscribe from all topics from STAN. If not borrowed
292
+ # and we own the connection, then we just close.
293
+ begin
294
+ # Remove all present subscriptions
295
+ @sub_map.each_pair do |_, sub|
296
+ nats.unsubscribe(sub.sid)
297
+ end
298
+
299
+ # Finally, remove the core subscriptions for STAN
300
+ nats.unsubscribe(@hb_inbox_sid)
301
+ nats.unsubscribe(@ack_subject_sid)
302
+ rescue => e
303
+ # TODO: Async error handling
304
+ ensure
305
+ if @borrowed_nats_connection
306
+ @nats = nil
307
+ else
308
+ @nats.close
309
+ end
310
+ end
311
+ end
312
+
313
+ # Ack takes a received message and publishes an ack manually
314
+ def ack(msg)
315
+ return unless msg.sub
316
+ msg.sub.synchronize do
317
+ ack_proto = STAN::Protocol::Ack.new({
318
+ subject: msg.proto.subject,
319
+ sequence: msg.proto.sequence
320
+ }).to_proto
321
+ nats.publish(msg.sub.ack_inbox, ack_proto)
322
+ end
323
+ end
324
+
325
+ private
326
+
327
+ # Process received publishes acks
328
+ def process_ack(data)
329
+ # FIXME: This should handle errors asynchronously in case there are any
330
+
331
+ # Process ack
332
+ pub_ack = STAN::Protocol::PubAck.decode(data)
333
+ unless pub_ack.error.empty?
334
+ raise Error.new(pub_ack.error)
335
+ end
336
+
337
+ # Unblock publishing queue
338
+ @pending_pub_acks.pop if @pending_pub_acks.size > 0
339
+
340
+ synchronize do
341
+ # yield the ack response back to original publisher caller
342
+ if cb = @pub_ack_map[pub_ack.guid]
343
+ cb.call(pub_ack)
344
+ end
345
+ end
346
+ end
347
+
348
+ # Process heartbeats by replying to them
349
+ def process_heartbeats(data, reply, subject)
350
+ # No payload assumed, just reply to the heartbeat.
351
+ nats.publish(reply, '')
352
+ end
353
+
354
+ # Process any received messages
355
+ def process_msg(data, reply, subject)
356
+ msg = Msg.new
357
+ msg.proto = STAN::Protocol::MsgProto.decode(data)
358
+ msg_ack = STAN::Protocol::Ack.new({
359
+ subject: msg.proto.subject,
360
+ sequence: msg.proto.sequence
361
+ })
362
+
363
+ # Lookup the subscription
364
+ sub = nil
365
+ synchronize do
366
+ sub = @sub_map[subject]
367
+ end
368
+ # Check if sub is no longer valid
369
+ return unless sub
370
+
371
+ # Store in msg for backlink
372
+ msg.sub = sub
373
+
374
+ cb = nil
375
+ ack_subject = nil
376
+ using_manual_acks = nil
377
+ sub.synchronize do
378
+ cb = sub.cb
379
+ ack_subject = sub.ack_inbox
380
+ using_manual_acks = sub.options[:manual_acks]
381
+ end
382
+
383
+ # Perform the callback if sub still subscribed
384
+ cb.call(msg) if cb
385
+
386
+ # Process auto-ack if not done manually
387
+ nats.publish(ack_subject, msg_ack.to_proto) if not using_manual_acks
388
+ end
389
+
390
+ def normalize_sub_req_params(opts)
391
+ sub_opts = {}
392
+ sub_opts[:qGroup] = opts[:queue] if opts[:queue]
393
+ sub_opts[:durableName] = opts[:durable_name] if opts[:durable_name]
394
+
395
+ sub_opts[:clientID] = @client_id
396
+ sub_opts[:maxInFlight] = opts[:max_inflight]
397
+ sub_opts[:ackWaitInSecs] = opts[:ack_wait] || opts[:ack_timeout]
398
+
399
+ # TODO: Error checking when all combinations of options are not declared
400
+ case opts[:start_at]
401
+ when :new_only
402
+ # By default, it already acts as :new_only which is
403
+ # without no initial replay, similar to bare NATS,
404
+ # but we allow setting it explicitly anyway.
405
+ sub_opts[:startPosition] = :NewOnly
406
+ when :last_received
407
+ sub_opts[:startPosition] = :LastReceived
408
+ when :time, :timedelta
409
+ # If using timedelta, need to get current time in UnixNano format
410
+ # FIXME: Implement support for :ago option which uses time in human.
411
+ sub_opts[:startPosition] = :TimeDeltaStart
412
+ start_at_time = opts[:time] * 1_000_000_000
413
+ sub_opts[:startTimeDelta] = (Time.now.to_f * 1_000_000_000) - start_at_time
414
+ when :sequence
415
+ sub_opts[:startPosition] = :SequenceStart
416
+ sub_opts[:startSequence] = opts[:sequence] || 0
417
+ when :first, :beginning
418
+ sub_opts[:startPosition] = :First
419
+ else
420
+ sub_opts[:startPosition] = :First if opts[:deliver_all_available]
421
+ end
422
+
423
+ sub_opts
424
+ end
425
+ end
426
+
427
+ class Subscription
428
+ attr_reader :subject, :queue, :inbox, :options, :cb, :durable_name, :stan
429
+ attr_accessor :sid, :ack_inbox
430
+
431
+ def initialize(subject, opts={}, cb)
432
+ @subject = subject
433
+ @queue = opts[:queue]
434
+ @inbox = STAN.create_inbox
435
+ @sid = nil # inbox subscription sid
436
+ @options = opts
437
+ @cb = cb
438
+ @ack_inbox = nil
439
+ @stan = opts[:stan]
440
+ @durable_name = opts[:durable_name]
441
+ end
442
+
443
+ # Unsubscribe removes interest in the subscription.
444
+ # For durables, it means that the durable interest is also removed from
445
+ # the server. Restarting a durable with the same name will not resume
446
+ # the subscription, it will be considered a new one.
447
+ def unsubscribe
448
+ synchronize do
449
+ stan.nats.unsubscribe(self.sid)
450
+ end
451
+
452
+ # Make client stop tracking the subscription inbox
453
+ # and grab unsub request subject under the lock.
454
+ unsub_subject = nil
455
+ stan.synchronize do
456
+ stan.sub_map.delete(self.ack_inbox)
457
+ unsub_subject = stan.unsub_req_subject
458
+ end
459
+
460
+ unsub_req = STAN::Protocol::UnsubscribeRequest.new({
461
+ clientID: stan.client_id,
462
+ subject: self.subject,
463
+ inbox: self.ack_inbox
464
+ })
465
+
466
+ if self.durable_name
467
+ unsub_req[:durableName] = self.durable_name
468
+ end
469
+
470
+ raw = stan.nats.request(unsub_subject, unsub_req.to_proto, {
471
+ timeout: stan.options[:connect_timeout]
472
+ })
473
+ response = STAN::Protocol::SubscriptionResponse.decode(raw.data)
474
+ unless response.error.empty?
475
+ # FIXME: Error handling on unsubscribe
476
+ raise Error.new(response.error)
477
+ end
478
+ end
479
+
480
+ def close
481
+ synchronize do
482
+ stan.nats.unsubscribe(self.sid)
483
+ end
484
+
485
+ # Make client stop tracking the subscription inbox
486
+ # and grab close request subject under the lock.
487
+ sub_close_subject = nil
488
+ stan.synchronize do
489
+ stan.sub_map.delete(self.ack_inbox)
490
+ sub_close_subject = stan.sub_close_req_subject
491
+ end
492
+
493
+ sub_close_req = STAN::Protocol::UnsubscribeRequest.new({
494
+ clientID: stan.client_id,
495
+ subject: self.subject,
496
+ inbox: self.ack_inbox
497
+ })
498
+
499
+ raw = stan.nats.request(sub_close_subject, sub_close_req.to_proto, {
500
+ timeout: stan.options[:connect_timeout]
501
+ })
502
+ response = STAN::Protocol::SubscriptionResponse.decode(raw.data)
503
+ unless response.error.empty?
504
+ # FIXME: Error handling on unsubscribe/close
505
+ raise Error.new(response.error)
506
+ end
507
+ end
508
+ end
509
+
510
+ # Data holder for sent messages
511
+ # It should have an Ack method as well to reply back?
512
+ Msg = Struct.new(:proto, :sub) do
513
+ def data
514
+ self.proto.data
515
+ end
516
+ def sequence
517
+ self.proto.sequence
518
+ end
519
+ alias seq sequence
520
+ end
521
+
522
+ class << self
523
+ def create_guid
524
+ SecureRandom.hex(11)
525
+ end
526
+
527
+ def create_inbox
528
+ SecureRandom.hex(13)
529
+ end
530
+ end
531
+ end
@@ -0,0 +1,97 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: pb/protocol.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_message "STAN.Protocol.PubMsg" do
8
+ optional :clientID, :string, 1
9
+ optional :guid, :string, 2
10
+ optional :subject, :string, 3
11
+ optional :reply, :string, 4
12
+ optional :data, :bytes, 5
13
+ optional :sha256, :bytes, 10
14
+ end
15
+ add_message "STAN.Protocol.PubAck" do
16
+ optional :guid, :string, 1
17
+ optional :error, :string, 2
18
+ end
19
+ add_message "STAN.Protocol.MsgProto" do
20
+ optional :sequence, :uint64, 1
21
+ optional :subject, :string, 2
22
+ optional :reply, :string, 3
23
+ optional :data, :bytes, 4
24
+ optional :timestamp, :int64, 5
25
+ optional :redelivered, :bool, 6
26
+ optional :CRC32, :uint32, 10
27
+ end
28
+ add_message "STAN.Protocol.Ack" do
29
+ optional :subject, :string, 1
30
+ optional :sequence, :uint64, 2
31
+ end
32
+ add_message "STAN.Protocol.ConnectRequest" do
33
+ optional :clientID, :string, 1
34
+ optional :heartbeatInbox, :string, 2
35
+ end
36
+ add_message "STAN.Protocol.ConnectResponse" do
37
+ optional :pubPrefix, :string, 1
38
+ optional :subRequests, :string, 2
39
+ optional :unsubRequests, :string, 3
40
+ optional :closeRequests, :string, 4
41
+ optional :error, :string, 5
42
+ optional :subCloseRequests, :string, 6
43
+ optional :publicKey, :string, 100
44
+ end
45
+ add_message "STAN.Protocol.SubscriptionRequest" do
46
+ optional :clientID, :string, 1
47
+ optional :subject, :string, 2
48
+ optional :qGroup, :string, 3
49
+ optional :inbox, :string, 4
50
+ optional :maxInFlight, :int32, 5
51
+ optional :ackWaitInSecs, :int32, 6
52
+ optional :durableName, :string, 7
53
+ optional :startPosition, :enum, 10, "STAN.Protocol.StartPosition"
54
+ optional :startSequence, :uint64, 11
55
+ optional :startTimeDelta, :int64, 12
56
+ end
57
+ add_message "STAN.Protocol.SubscriptionResponse" do
58
+ optional :ackInbox, :string, 2
59
+ optional :error, :string, 3
60
+ end
61
+ add_message "STAN.Protocol.UnsubscribeRequest" do
62
+ optional :clientID, :string, 1
63
+ optional :subject, :string, 2
64
+ optional :inbox, :string, 3
65
+ optional :durableName, :string, 4
66
+ end
67
+ add_message "STAN.Protocol.CloseRequest" do
68
+ optional :clientID, :string, 1
69
+ end
70
+ add_message "STAN.Protocol.CloseResponse" do
71
+ optional :error, :string, 1
72
+ end
73
+ add_enum "STAN.Protocol.StartPosition" do
74
+ value :NewOnly, 0
75
+ value :LastReceived, 1
76
+ value :TimeDeltaStart, 2
77
+ value :SequenceStart, 3
78
+ value :First, 4
79
+ end
80
+ end
81
+
82
+ module STAN
83
+ module Protocol
84
+ PubMsg = Google::Protobuf::DescriptorPool.generated_pool.lookup("STAN.Protocol.PubMsg").msgclass
85
+ PubAck = Google::Protobuf::DescriptorPool.generated_pool.lookup("STAN.Protocol.PubAck").msgclass
86
+ MsgProto = Google::Protobuf::DescriptorPool.generated_pool.lookup("STAN.Protocol.MsgProto").msgclass
87
+ Ack = Google::Protobuf::DescriptorPool.generated_pool.lookup("STAN.Protocol.Ack").msgclass
88
+ ConnectRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("STAN.Protocol.ConnectRequest").msgclass
89
+ ConnectResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("STAN.Protocol.ConnectResponse").msgclass
90
+ SubscriptionRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("STAN.Protocol.SubscriptionRequest").msgclass
91
+ SubscriptionResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("STAN.Protocol.SubscriptionResponse").msgclass
92
+ UnsubscribeRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("STAN.Protocol.UnsubscribeRequest").msgclass
93
+ CloseRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("STAN.Protocol.CloseRequest").msgclass
94
+ CloseResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("STAN.Protocol.CloseResponse").msgclass
95
+ StartPosition = Google::Protobuf::DescriptorPool.generated_pool.lookup("STAN.Protocol.StartPosition").enummodule
96
+ end
97
+ end
@@ -0,0 +1,3 @@
1
+ module STAN
2
+ VERSION = '0.1.0'
3
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nats-streaming
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Waldemar Quevedo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nats-pure
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: google-protobuf
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Ruby client for the NATS Streaming messaging system.
42
+ email:
43
+ - wally@apcera.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/stan/client.rb
49
+ - lib/stan/pb/protocol.pb.rb
50
+ - lib/stan/version.rb
51
+ homepage: https://nats.io
52
+ licenses:
53
+ - MIT
54
+ metadata: {}
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubyforge_project:
71
+ rubygems_version: 2.5.2
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: Ruby client for the NATS Streaming messaging system.
75
+ test_files: []