nats-pure 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|