nats-pure 0.6.2 → 0.7.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.
- checksums.yaml +4 -4
- data/lib/nats/io/client.rb +171 -20
- data/lib/nats/io/parser.rb +17 -3
- data/lib/nats/io/version.rb +2 -2
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d21f9a3f83d1aaa172f0835a2d74b5109a8e937429550981427b84325f97f1d3
|
4
|
+
data.tar.gz: 48ea0ef20a7c2611023573f883384d15ebf6bf9c342f37336b25157d79963098
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b72826e0d687cee2e303f3fae2abbc34ad6fe10ce35967d2201ecd3838c27f186e70c99c880288bfd2fbdc840edebfa80f4f31e282caafb15f899b41301a5a94
|
7
|
+
data.tar.gz: b5328d07ffa92de70d32cb37b28bf1c08db2866b58902dee2f761b6c0cf758c18037262fca4f42a3ab5bf6c4f0663abb733d8322cdfe8a2e30d8bd9de9a4139f
|
data/lib/nats/io/client.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2016-
|
1
|
+
# Copyright 2016-2021 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
|
@@ -64,6 +64,12 @@ module NATS
|
|
64
64
|
PING_REQUEST = ("PING#{CR_LF}".freeze)
|
65
65
|
PONG_RESPONSE = ("PONG#{CR_LF}".freeze)
|
66
66
|
|
67
|
+
NATS_HDR_LINE = ("NATS/1.0#{CR_LF}".freeze)
|
68
|
+
STATUS_MSG_LEN = 3
|
69
|
+
STATUS_HDR = ("Status".freeze)
|
70
|
+
DESC_HDR = ("Description".freeze)
|
71
|
+
NATS_HDR_LINE_SIZE = (NATS_HDR_LINE.bytesize)
|
72
|
+
|
67
73
|
SUB_OP = ('SUB'.freeze)
|
68
74
|
EMPTY_MSG = (''.freeze)
|
69
75
|
|
@@ -91,6 +97,9 @@ module NATS
|
|
91
97
|
# When we cannot connect since there are no servers available.
|
92
98
|
class NoServersError < ConnectError; end
|
93
99
|
|
100
|
+
# When there are no subscribers available to respond.
|
101
|
+
class NoRespondersError < ConnectError; end
|
102
|
+
|
94
103
|
# When the connection exhausts max number of pending pings replies.
|
95
104
|
class StaleConnectionError < Error; end
|
96
105
|
|
@@ -346,6 +355,36 @@ module NATS
|
|
346
355
|
@flush_queue << :pub if @flush_queue.empty?
|
347
356
|
end
|
348
357
|
|
358
|
+
# Publishes a NATS::Msg that may include headers.
|
359
|
+
def publish_msg(msg)
|
360
|
+
raise TypeError, "nats: expected NATS::Msg, got #{msg.class.name}" unless msg.is_a?(Msg)
|
361
|
+
raise BadSubject if !msg.subject or msg.subject.empty?
|
362
|
+
|
363
|
+
msg.reply ||= ''
|
364
|
+
msg.data ||= ''
|
365
|
+
msg_size = msg.data.bytesize
|
366
|
+
|
367
|
+
# Accounting
|
368
|
+
@stats[:out_msgs] += 1
|
369
|
+
@stats[:out_bytes] += msg_size
|
370
|
+
|
371
|
+
if msg.header
|
372
|
+
hdr = ''
|
373
|
+
hdr << NATS_HDR_LINE
|
374
|
+
msg.header.each do |k, v|
|
375
|
+
hdr << "#{k}: #{v}#{CR_LF}"
|
376
|
+
end
|
377
|
+
hdr << CR_LF
|
378
|
+
hdr_len = hdr.bytesize
|
379
|
+
total_size = msg_size + hdr_len
|
380
|
+
send_command("HPUB #{msg.subject} #{msg.reply} #{hdr_len} #{total_size}\r\n#{hdr}#{msg.data}\r\n")
|
381
|
+
else
|
382
|
+
send_command("PUB #{msg.subject} #{msg.reply} #{msg_size}\r\n#{msg.data}\r\n")
|
383
|
+
end
|
384
|
+
|
385
|
+
@flush_queue << :pub if @flush_queue.empty?
|
386
|
+
end
|
387
|
+
|
349
388
|
# Create subscription which is dispatched asynchronously
|
350
389
|
# messages to a callback.
|
351
390
|
def subscribe(subject, opts={}, &callback)
|
@@ -393,7 +432,8 @@ module NATS
|
|
393
432
|
when 0 then cb.call
|
394
433
|
when 1 then cb.call(msg.data)
|
395
434
|
when 2 then cb.call(msg.data, msg.reply)
|
396
|
-
|
435
|
+
when 3 then cb.call(msg.data, msg.reply, msg.subject)
|
436
|
+
else cb.call(msg.data, msg.reply, msg.subject, msg.header)
|
397
437
|
end
|
398
438
|
rescue => e
|
399
439
|
synchronize do
|
@@ -411,11 +451,12 @@ module NATS
|
|
411
451
|
# It times out in case the request is not retrieved within the
|
412
452
|
# specified deadline.
|
413
453
|
# If given a callback, then the request happens asynchronously.
|
414
|
-
def request(subject, payload, opts={}, &blk)
|
415
|
-
|
454
|
+
def request(subject, payload="", opts={}, &blk)
|
455
|
+
raise BadSubject if !subject or subject.empty?
|
416
456
|
|
417
457
|
# If a block was given then fallback to method using auto unsubscribe.
|
418
458
|
return old_request(subject, payload, opts, &blk) if blk
|
459
|
+
return old_request(subject, payload, opts) if opts[:old_style]
|
419
460
|
|
420
461
|
token = nil
|
421
462
|
inbox = nil
|
@@ -437,16 +478,81 @@ module NATS
|
|
437
478
|
|
438
479
|
# Publish request and wait for reply.
|
439
480
|
publish(subject, payload, inbox)
|
440
|
-
|
441
|
-
|
442
|
-
|
481
|
+
begin
|
482
|
+
with_nats_timeout(timeout) do
|
483
|
+
@resp_sub.synchronize do
|
484
|
+
future.wait(timeout)
|
485
|
+
end
|
443
486
|
end
|
487
|
+
rescue NATS::IO::Timeout => e
|
488
|
+
synchronize { @resp_map.delete(token) }
|
489
|
+
raise e
|
444
490
|
end
|
445
491
|
|
446
|
-
# Check if there is a response already
|
492
|
+
# Check if there is a response already.
|
447
493
|
synchronize do
|
448
494
|
result = @resp_map[token]
|
449
495
|
response = result[:response]
|
496
|
+
@resp_map.delete(token)
|
497
|
+
end
|
498
|
+
|
499
|
+
if response and response.header
|
500
|
+
status = response.header[STATUS_HDR]
|
501
|
+
raise NoRespondersError if status == "503"
|
502
|
+
end
|
503
|
+
|
504
|
+
response
|
505
|
+
end
|
506
|
+
|
507
|
+
# Makes a NATS request using a NATS::Msg that may include headers.
|
508
|
+
def request_msg(msg, opts={})
|
509
|
+
raise TypeError, "nats: expected NATS::Msg, got #{msg.class.name}" unless msg.is_a?(Msg)
|
510
|
+
raise BadSubject if !msg.subject or msg.subject.empty?
|
511
|
+
|
512
|
+
token = nil
|
513
|
+
inbox = nil
|
514
|
+
future = nil
|
515
|
+
response = nil
|
516
|
+
timeout = opts[:timeout] ||= 0.5
|
517
|
+
synchronize do
|
518
|
+
start_resp_mux_sub! unless @resp_sub_prefix
|
519
|
+
|
520
|
+
# Create token for this request.
|
521
|
+
token = @nuid.next
|
522
|
+
inbox = "#{@resp_sub_prefix}.#{token}"
|
523
|
+
|
524
|
+
# Create the a future for the request that will
|
525
|
+
# get signaled when it receives the request.
|
526
|
+
future = @resp_sub.new_cond
|
527
|
+
@resp_map[token][:future] = future
|
528
|
+
end
|
529
|
+
msg.reply = inbox
|
530
|
+
msg.data ||= ''
|
531
|
+
msg_size = msg.data.bytesize
|
532
|
+
|
533
|
+
# Publish request and wait for reply.
|
534
|
+
publish_msg(msg)
|
535
|
+
begin
|
536
|
+
with_nats_timeout(timeout) do
|
537
|
+
@resp_sub.synchronize do
|
538
|
+
future.wait(timeout)
|
539
|
+
end
|
540
|
+
end
|
541
|
+
rescue NATS::IO::Timeout => e
|
542
|
+
synchronize { @resp_map.delete(token) }
|
543
|
+
raise e
|
544
|
+
end
|
545
|
+
|
546
|
+
# Check if there is a response already.
|
547
|
+
synchronize do
|
548
|
+
result = @resp_map[token]
|
549
|
+
response = result[:response]
|
550
|
+
@resp_map.delete(token)
|
551
|
+
end
|
552
|
+
|
553
|
+
if response and response.header
|
554
|
+
status = response.header[STATUS_HDR]
|
555
|
+
raise NoRespondersError if status == "503"
|
450
556
|
end
|
451
557
|
|
452
558
|
response
|
@@ -464,11 +570,13 @@ module NATS
|
|
464
570
|
# the messages asynchronously and return the sid.
|
465
571
|
if blk
|
466
572
|
opts[:max] ||= 1
|
467
|
-
s = subscribe(inbox, opts) do |msg, reply|
|
573
|
+
s = subscribe(inbox, opts) do |msg, reply, subject, header|
|
468
574
|
case blk.arity
|
469
575
|
when 0 then blk.call
|
470
576
|
when 1 then blk.call(msg)
|
471
|
-
|
577
|
+
when 2 then blk.call(msg, reply)
|
578
|
+
when 3 then blk.call(msg, reply, subject)
|
579
|
+
else blk.call(msg, reply, subject, header)
|
472
580
|
end
|
473
581
|
end
|
474
582
|
publish(subject, payload, inbox)
|
@@ -594,8 +702,7 @@ module NATS
|
|
594
702
|
process_op_error(e)
|
595
703
|
end
|
596
704
|
|
597
|
-
def process_msg(subject, sid, reply, data)
|
598
|
-
# Accounting
|
705
|
+
def process_msg(subject, sid, reply, data, header)
|
599
706
|
@stats[:in_msgs] += 1
|
600
707
|
@stats[:in_bytes] += data.size
|
601
708
|
|
@@ -604,7 +711,7 @@ module NATS
|
|
604
711
|
synchronize { sub = @subs[sid] }
|
605
712
|
return unless sub
|
606
713
|
|
607
|
-
|
714
|
+
err = nil
|
608
715
|
sub.synchronize do
|
609
716
|
sub.received += 1
|
610
717
|
|
@@ -625,7 +732,8 @@ module NATS
|
|
625
732
|
# do so here already while holding the lock and return
|
626
733
|
if sub.future
|
627
734
|
future = sub.future
|
628
|
-
|
735
|
+
hdr = process_hdr(header)
|
736
|
+
sub.response = Msg.new(subject: subject, reply: reply, data: data, header: hdr)
|
629
737
|
future.signal
|
630
738
|
|
631
739
|
return
|
@@ -634,20 +742,54 @@ module NATS
|
|
634
742
|
# and should be able to consume messages in parallel.
|
635
743
|
if sub.pending_queue.size >= sub.pending_msgs_limit \
|
636
744
|
or sub.pending_size >= sub.pending_bytes_limit then
|
637
|
-
|
745
|
+
err = SlowConsumer.new("nats: slow consumer, messages dropped")
|
638
746
|
else
|
747
|
+
hdr = process_hdr(header)
|
748
|
+
|
639
749
|
# Only dispatch message when sure that it would not block
|
640
750
|
# the main read loop from the parser.
|
641
|
-
|
751
|
+
msg = Msg.new(subject: subject, reply: reply, data: data, header: hdr)
|
752
|
+
sub.pending_queue << msg
|
642
753
|
sub.pending_size += data.size
|
643
754
|
end
|
644
755
|
end
|
645
756
|
end
|
646
757
|
|
647
758
|
synchronize do
|
648
|
-
@last_err =
|
649
|
-
@err_cb.call(
|
650
|
-
end if
|
759
|
+
@last_err = err
|
760
|
+
@err_cb.call(err) if @err_cb
|
761
|
+
end if err
|
762
|
+
end
|
763
|
+
|
764
|
+
def process_hdr(header)
|
765
|
+
hdr = nil
|
766
|
+
if header
|
767
|
+
hdr = {}
|
768
|
+
lines = header.lines
|
769
|
+
|
770
|
+
# Check if it is an inline status and description.
|
771
|
+
if lines.count <= 2
|
772
|
+
status_hdr = lines.first.rstrip
|
773
|
+
hdr[STATUS_HDR] = status_hdr.slice(NATS_HDR_LINE_SIZE-1, STATUS_MSG_LEN)
|
774
|
+
|
775
|
+
if NATS_HDR_LINE_SIZE+2 < status_hdr.bytesize
|
776
|
+
desc = status_hdr.slice(NATS_HDR_LINE_SIZE+STATUS_MSG_LEN, status_hdr.bytesize)
|
777
|
+
hdr[DESC_HDR] = desc unless desc.empty?
|
778
|
+
end
|
779
|
+
end
|
780
|
+
begin
|
781
|
+
lines.slice(1, header.size).each do |line|
|
782
|
+
line.rstrip!
|
783
|
+
next if line.empty?
|
784
|
+
key, value = line.strip.split(/\s*:\s*/, 2)
|
785
|
+
hdr[key] = value
|
786
|
+
end
|
787
|
+
rescue => e
|
788
|
+
err = e
|
789
|
+
end
|
790
|
+
end
|
791
|
+
|
792
|
+
hdr
|
651
793
|
end
|
652
794
|
|
653
795
|
def process_info(line)
|
@@ -831,6 +973,15 @@ module NATS
|
|
831
973
|
cs[:sig] = @signature_cb.call(nonce)
|
832
974
|
end
|
833
975
|
|
976
|
+
if @server_info[:headers]
|
977
|
+
cs[:headers] = @server_info[:headers]
|
978
|
+
cs[:no_responders] = if @options[:no_responders] == false
|
979
|
+
@options[:no_responders]
|
980
|
+
else
|
981
|
+
@server_info[:headers]
|
982
|
+
end
|
983
|
+
end
|
984
|
+
|
834
985
|
"CONNECT #{cs.to_json}#{CR_LF}"
|
835
986
|
end
|
836
987
|
|
@@ -1537,7 +1688,7 @@ module NATS
|
|
1537
1688
|
end
|
1538
1689
|
end
|
1539
1690
|
|
1540
|
-
Msg = Struct.new(:subject, :reply, :data)
|
1691
|
+
Msg = Struct.new(:subject, :reply, :data, :header, keyword_init: true)
|
1541
1692
|
|
1542
1693
|
class Subscription
|
1543
1694
|
include MonitorMixin
|
data/lib/nats/io/parser.rb
CHANGED
@@ -16,6 +16,7 @@ module NATS
|
|
16
16
|
module Protocol
|
17
17
|
|
18
18
|
MSG = /\AMSG\s+([^\s]+)\s+([^\s]+)\s+(([^\s]+)[^\S\r\n]+)?(\d+)\r\n/i
|
19
|
+
HMSG = /\AHMSG\s+([^\s]+)\s+([^\s]+)\s+(([^\s]+)[^\S\r\n]+)?([\d]+)\s+(\d+)\r\n/i
|
19
20
|
OK = /\A\+OK\s*\r\n/i
|
20
21
|
ERR = /\A-ERR\s+('.+')?\r\n/i
|
21
22
|
PING = /\APING\s*\r\n/i
|
@@ -49,6 +50,7 @@ module NATS
|
|
49
50
|
@sid = nil
|
50
51
|
@reply = nil
|
51
52
|
@needed = nil
|
53
|
+
@header_needed = nil
|
52
54
|
end
|
53
55
|
|
54
56
|
def parse(data)
|
@@ -61,6 +63,10 @@ module NATS
|
|
61
63
|
@buf = $'
|
62
64
|
@sub, @sid, @reply, @needed = $1, $2.to_i, $4, $5.to_i
|
63
65
|
@parse_state = AWAITING_MSG_PAYLOAD
|
66
|
+
when HMSG
|
67
|
+
@buf = $'
|
68
|
+
@sub, @sid, @reply, @header_needed, @needed = $1, $2.to_i, $4, $5.to_i, $6.to_i
|
69
|
+
@parse_state = AWAITING_MSG_PAYLOAD
|
64
70
|
when OK # No-op right now
|
65
71
|
@buf = $'
|
66
72
|
when ERR
|
@@ -89,9 +95,17 @@ module NATS
|
|
89
95
|
|
90
96
|
when AWAITING_MSG_PAYLOAD
|
91
97
|
return unless (@needed && @buf.bytesize >= (@needed + CR_LF_SIZE))
|
92
|
-
|
93
|
-
|
94
|
-
|
98
|
+
if @header_needed
|
99
|
+
hbuf = @buf.slice(0, @header_needed)
|
100
|
+
payload = @buf.slice(@header_needed, (@needed-@header_needed))
|
101
|
+
@nc.process_msg(@sub, @sid, @reply, payload, hbuf)
|
102
|
+
@buf = @buf.slice((@needed + CR_LF_SIZE), @buf.bytesize)
|
103
|
+
else
|
104
|
+
@nc.process_msg(@sub, @sid, @reply, @buf.slice(0, @needed), nil)
|
105
|
+
@buf = @buf.slice((@needed + CR_LF_SIZE), @buf.bytesize)
|
106
|
+
end
|
107
|
+
|
108
|
+
@sub = @sid = @reply = @needed = @header_needed = nil
|
95
109
|
@parse_state = AWAITING_CONTROL_LINE
|
96
110
|
@buf = nil if (@buf && @buf.empty?)
|
97
111
|
end
|
data/lib/nats/io/version.rb
CHANGED
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.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Waldemar Quevedo
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-17 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: NATS is an open-source, high-performance, lightweight cloud messaging
|
14
14
|
system.
|
@@ -26,7 +26,7 @@ homepage: https://nats.io
|
|
26
26
|
licenses:
|
27
27
|
- Apache-2.0
|
28
28
|
metadata: {}
|
29
|
-
post_install_message:
|
29
|
+
post_install_message:
|
30
30
|
rdoc_options: []
|
31
31
|
require_paths:
|
32
32
|
- lib
|
@@ -41,8 +41,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
41
41
|
- !ruby/object:Gem::Version
|
42
42
|
version: '0'
|
43
43
|
requirements: []
|
44
|
-
rubygems_version: 3.
|
45
|
-
signing_key:
|
44
|
+
rubygems_version: 3.2.22
|
45
|
+
signing_key:
|
46
46
|
specification_version: 4
|
47
47
|
summary: NATS is an open-source, high-performance, lightweight cloud messaging system.
|
48
48
|
test_files: []
|