bps-nats 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|