bps-nats 0.2.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 202e41923cbb093a7504969a3dfa266574e6b5d1f0982cf5c08bb7393252eecf
4
+ data.tar.gz: 4beb06613f160e27a140e5efeb6b0055df4bcbdff596abecdaf2579685c7515d
5
+ SHA512:
6
+ metadata.gz: 78975cd84023ae46da605d0a1380b0854383f533f1fb528fb60be9a923e65414b7c7eeac03c4327262d5e586957624a69de5469fad83d3d168609bc9eedef482
7
+ data.tar.gz: bb70c2a34954e52f923612b7e2ebb77989a553dfa0f7d2179d393cb58089a5f02d011b6de4ccb549f17d59ac6c12574ddd3758a53ed031477acfec10214d8b8b
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'bps-nats'
3
+ s.version = File.read(File.expand_path('../../.version', __dir__)).strip
4
+ s.platform = Gem::Platform::RUBY
5
+
6
+ s.licenses = ['Apache-2.0']
7
+ s.summary = 'BPS adapter for nats'
8
+ s.description = 'https://github.com/bsm/bps'
9
+
10
+ s.authors = ['Black Square Media']
11
+ s.email = 'info@blacksquaremedia.com'
12
+ s.homepage = 'https://github.com/bsm/bps'
13
+
14
+ s.executables = []
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- spec/*`.split("\n")
17
+ s.require_paths = ['lib']
18
+ s.required_ruby_version = '>= 2.6.0'
19
+
20
+ s.add_dependency 'bps', s.version
21
+ s.add_dependency 'nats-pure', '~> 0.6.2'
22
+ end
@@ -0,0 +1 @@
1
+ require 'bps/nats'
@@ -0,0 +1,12 @@
1
+ require 'bps'
2
+ require 'bps/publisher/nats'
3
+
4
+ module BPS
5
+ module Publisher
6
+ register('nats') do |url, **opts|
7
+ url_opts = NATS.parse_url(url)
8
+ url_opts.update(opts)
9
+ NATS.new(**NATS.coercer.coerce(url_opts))
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,78 @@
1
+ require 'cgi'
2
+ require 'nats/io/client'
3
+
4
+ module BPS
5
+ module Publisher
6
+ class NATS < Abstract
7
+ FLUSH_TIMEOUT = 5
8
+
9
+ class Topic < Abstract::Topic
10
+ def initialize(client, topic)
11
+ super()
12
+
13
+ @client = client
14
+ @topic = topic
15
+ end
16
+
17
+ def publish(message, **_opts)
18
+ @client.publish(@topic, message)
19
+ end
20
+
21
+ def flush(**)
22
+ @client.flush(FLUSH_TIMEOUT)
23
+ end
24
+ end
25
+
26
+ CLIENT_OPTS = {
27
+ servers: [:string],
28
+ dont_randomize_servers: :bool,
29
+ reconnect_time_wait: :float,
30
+ max_reconnect_attempts: :int,
31
+ connect_timeout: :float,
32
+ tls_ca_file: :string,
33
+ # TODO: review, list all of them: https://github.com/nats-io/nats-pure.rb
34
+ }.freeze
35
+
36
+ def self.parse_url(url)
37
+ port = url.port&.to_s || '4222'
38
+ servers = CGI.unescape(url.host).split(',').map do |host|
39
+ addr = "nats://#{host}"
40
+ addr << ':' << port unless /:\d+$/.match?(addr)
41
+ addr
42
+ end
43
+ opts = CGI.parse(url.query || '').transform_values {|v| v.size == 1 ? v[0] : v }
44
+ opts.merge(servers: servers)
45
+ end
46
+
47
+ # @return [BPS::Coercer] the options coercer.
48
+ def self.coercer
49
+ @coercer ||= BPS::Coercer.new(CLIENT_OPTS).freeze
50
+ end
51
+
52
+ # @param [Hash] options.
53
+ def initialize(**opts)
54
+ super()
55
+
56
+ # handle TLS if CA file is provided:
57
+ if !opts[:tls] && opts[:tls_ca_file]
58
+ ctx = OpenSSL::SSL::SSLContext.new
59
+ ctx.set_params
60
+ ctx.ca_file = opts.delete(:tls_ca_file)
61
+ opts[:tls] = ctx
62
+ end
63
+
64
+ @topics = {}
65
+ @client = ::NATS::IO::Client.new
66
+ @client.connect(**opts.slice(*CLIENT_OPTS.keys))
67
+ end
68
+
69
+ def topic(name)
70
+ @topics[name] ||= self.class::Topic.new(@client, name)
71
+ end
72
+
73
+ def close
74
+ @client.close
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,75 @@
1
+ require 'bps/nats'
2
+ require 'spec_helper'
3
+
4
+ RSpec.describe 'NATS', nats: true do
5
+ context 'with addr resolving' do
6
+ let(:publisher) { instance_double('BPS::Publisher::NATS') }
7
+
8
+ before { allow(BPS::Publisher::NATS).to receive(:new).and_return(publisher) }
9
+
10
+ it 'resolves simple URLs' do
11
+ allow(BPS::Publisher::NATS)
12
+ .to receive(:new)
13
+ .with(servers: ['nats://test.host:4222'])
14
+ .and_return(publisher)
15
+ BPS::Publisher.resolve(URI.parse('nats://test.host:4222'))
16
+ end
17
+
18
+ it 'resolves URLs with multiple hosts' do
19
+ allow(BPS::Publisher::NATS)
20
+ .to receive(:new)
21
+ .with(servers: ['nats://foo.host:4222', 'nats://bar.host:4222'])
22
+ .and_return(publisher)
23
+ BPS::Publisher.resolve(URI.parse('nats://foo.host,bar.host:4222'))
24
+ end
25
+
26
+ it 'resolves URLs with multiple hosts/ports' do
27
+ allow(BPS::Publisher::NATS)
28
+ .to receive(:new)
29
+ .with(servers: ['nats://foo.host:4223', 'nats://bar.host:4222'])
30
+ .and_return(publisher)
31
+ BPS::Publisher.resolve(URI.parse('nats://foo.host%3A4223,bar.host'))
32
+ end
33
+ end
34
+
35
+ context BPS::Publisher::NATS do
36
+ let(:nats_servers) { ENV.fetch('NATS_SERVERS', '127.0.0.1:4222').split(',') }
37
+ let(:messages_queue) { Queue.new }
38
+ let(:nats_servers_with_scheme) { nats_servers.map {|s| "nats://#{s}" } }
39
+
40
+ let(:publisher_url) { "nats://#{CGI.escape(nats_servers.join(','))}" }
41
+
42
+ # Pure NATS doesn't retain messages, so we need to subscribe BEFORE emitting.
43
+ # Also, subscription is asynchronous, so we have to use blocking queue to wait for messages.
44
+
45
+ # connect to NATS before any test code runs:
46
+ let!(:nats_client) do
47
+ opts = {
48
+ servers: nats_servers_with_scheme,
49
+ dont_randomize_servers: true,
50
+ }
51
+ client = ::NATS::IO::Client.new
52
+ client.connect(opts)
53
+ client
54
+ end
55
+
56
+ # don't forget to close NATS connection after tests are done:
57
+ after do
58
+ nats_client.close
59
+ end
60
+
61
+ # blocking queue to gather messages in background thread:
62
+
63
+ # subscribe to test topic, non-blocking; messages will be pushed into blocking queue:
64
+ def setup_topic(topic_name, num_messages)
65
+ nats_client.subscribe(topic_name, max: num_messages) {|msg| messages_queue << msg }
66
+ end
67
+
68
+ # simply drain messages queue to get messages:
69
+ def read_messages(_topic_name, num_messages)
70
+ Array.new(num_messages) { messages_queue.pop }
71
+ end
72
+
73
+ it_behaves_like 'publisher'
74
+ end
75
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bps-nats
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Black Square Media
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-01-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bps
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.2.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.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: nats-pure
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.6.2
41
+ description: https://github.com/bsm/bps
42
+ email: info@blacksquaremedia.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - bps-nats.gemspec
48
+ - lib/bps-nats.rb
49
+ - lib/bps/nats.rb
50
+ - lib/bps/publisher/nats.rb
51
+ - spec/bps/nats_spec.rb
52
+ homepage: https://github.com/bsm/bps
53
+ licenses:
54
+ - Apache-2.0
55
+ metadata: {}
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 2.6.0
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubygems_version: 3.1.4
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: BPS adapter for nats
75
+ test_files:
76
+ - spec/bps/nats_spec.rb