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.
- checksums.yaml +7 -0
- data/bps-nats.gemspec +22 -0
- data/lib/bps-nats.rb +1 -0
- data/lib/bps/nats.rb +12 -0
- data/lib/bps/publisher/nats.rb +78 -0
- data/spec/bps/nats_spec.rb +75 -0
- metadata +76 -0
checksums.yaml
ADDED
@@ -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
|
data/bps-nats.gemspec
ADDED
@@ -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
|
data/lib/bps-nats.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bps/nats'
|
data/lib/bps/nats.rb
ADDED
@@ -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
|