bps-stan 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bps-stan.gemspec +22 -0
- data/lib/bps-stan.rb +1 -0
- data/lib/bps/publisher/stan.rb +75 -0
- data/lib/bps/stan.rb +12 -0
- data/spec/bps/stan_spec.rb +60 -0
- metadata +76 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5d0143920a7d80cb269a5fd2d8f15ac90becad86b7177a808b6239a0bb77b0a9
|
4
|
+
data.tar.gz: 23eda94ef4b9e1baaa89a806f435c32f4a087bf7b243bd004484a9e97734377f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7c9d5fab51969ffe5d0c7b5799af272301d603810a7a37ec6593dbe71dc997ac9f3643dc3b2637f329857a616434f59f55733c215552b14f4b099fbe44fd6b67
|
7
|
+
data.tar.gz: 17448d25241e07c5608f3d4a80a9d8f5b5620059a84f02f4770a82d86124c8111dc4bfd0c2b634349ef2531b48e9f0570e50ca174bb7af57481be1867d1c8866
|
data/bps-stan.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'bps-stan'
|
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-streaming'
|
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-streaming', '= 0.2.2'
|
22
|
+
end
|
data/lib/bps-stan.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bps/stan'
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'stan/client'
|
3
|
+
|
4
|
+
module BPS
|
5
|
+
module Publisher
|
6
|
+
class STAN < Abstract
|
7
|
+
class Topic < Abstract::Topic
|
8
|
+
def initialize(client, topic)
|
9
|
+
super()
|
10
|
+
|
11
|
+
@client = client
|
12
|
+
@topic = topic
|
13
|
+
end
|
14
|
+
|
15
|
+
def publish(message, **_opts)
|
16
|
+
@client.publish(@topic, message)
|
17
|
+
end
|
18
|
+
|
19
|
+
def flush(**)
|
20
|
+
# noop
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
CLIENT_OPTS = {
|
25
|
+
nats: {
|
26
|
+
servers: [:string],
|
27
|
+
dont_randomize_servers: :bool,
|
28
|
+
reconnect_time_wait: :float,
|
29
|
+
max_reconnect_attempts: :int,
|
30
|
+
connect_timeout: :float,
|
31
|
+
# TODO: review, list all of them: https://github.com/nats-io/nats.rb (there's tls config etc)
|
32
|
+
},
|
33
|
+
}.freeze
|
34
|
+
|
35
|
+
def self.parse_url(url)
|
36
|
+
port = url.port&.to_s || '4222'
|
37
|
+
servers = CGI.unescape(url.host).split(',').map do |host|
|
38
|
+
addr = "nats://#{host}"
|
39
|
+
addr << ':' << port unless addr.match(/:\d+$/)
|
40
|
+
addr
|
41
|
+
end
|
42
|
+
opts = CGI.parse(url.query).transform_values {|v| v.size == 1 ? v[0] : v }
|
43
|
+
cluster_id = opts.delete('cluster_id')
|
44
|
+
client_id = opts.delete('client_id')
|
45
|
+
[cluster_id, client_id, { nats: { servers: servers } }]
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [BPS::Coercer] the options coercer.
|
49
|
+
def self.coercer
|
50
|
+
@coercer ||= BPS::Coercer.new(CLIENT_OPTS).freeze
|
51
|
+
end
|
52
|
+
|
53
|
+
# @param [String] cluster ID.
|
54
|
+
# @param [String] client ID.
|
55
|
+
# @param [Hash] options.
|
56
|
+
def initialize(cluster_id, client_id, nats: {}, **opts)
|
57
|
+
super()
|
58
|
+
|
59
|
+
@topics = {}
|
60
|
+
@client = ::STAN::Client.new
|
61
|
+
@client.connect(cluster_id, client_id, nats: nats, **opts.slice(*CLIENT_OPTS.keys))
|
62
|
+
end
|
63
|
+
|
64
|
+
def topic(name)
|
65
|
+
@topics[name] ||= self.class::Topic.new(@client, name)
|
66
|
+
end
|
67
|
+
|
68
|
+
def close
|
69
|
+
# NATS/STAN do not survive multi-closes, so close only once:
|
70
|
+
@client&.close
|
71
|
+
@client = nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/bps/stan.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'bps'
|
2
|
+
require 'bps/publisher/stan'
|
3
|
+
|
4
|
+
module BPS
|
5
|
+
module Publisher
|
6
|
+
register('stan') do |url, **opts|
|
7
|
+
cluster_id, client_id, url_opts = STAN.parse_url(url)
|
8
|
+
url_opts.update(opts)
|
9
|
+
STAN.new(cluster_id, client_id, **STAN.coercer.coerce(url_opts))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'bps/stan'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
RSpec.describe 'STAN', stan: true do
|
5
|
+
context 'resolve addrs' do
|
6
|
+
let(:publisher) { double('BPS::Publisher::STAN') }
|
7
|
+
before { allow(BPS::Publisher::STAN).to receive(:new).and_return(publisher) }
|
8
|
+
|
9
|
+
it 'should resolve simple URLs' do
|
10
|
+
expect(BPS::Publisher::STAN)
|
11
|
+
.to receive(:new)
|
12
|
+
.with('CLUSTER', 'CLIENT', nats: { servers: ['nats://test.host:4222'] })
|
13
|
+
.and_return(publisher)
|
14
|
+
BPS::Publisher.resolve(URI.parse('stan://test.host:4222?cluster_id=CLUSTER&client_id=CLIENT'))
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should resolve URLs with multiple hosts' do
|
18
|
+
expect(BPS::Publisher::STAN)
|
19
|
+
.to receive(:new)
|
20
|
+
.with('CLUSTER', 'CLIENT', nats: { servers: ['nats://foo.host:4222', 'nats://bar.host:4222'] })
|
21
|
+
.and_return(publisher)
|
22
|
+
BPS::Publisher.resolve(URI.parse('stan://foo.host,bar.host:4222?cluster_id=CLUSTER&client_id=CLIENT'))
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should resolve URLs with multiple hosts/ports' do
|
26
|
+
expect(BPS::Publisher::STAN)
|
27
|
+
.to receive(:new)
|
28
|
+
.with('CLUSTER', 'CLIENT', nats: { servers: ['nats://foo.host:4223', 'nats://bar.host:4222'] })
|
29
|
+
.and_return(publisher)
|
30
|
+
BPS::Publisher.resolve(URI.parse('stan://foo.host%3A4223,bar.host?cluster_id=CLUSTER&client_id=CLIENT'))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context BPS::Publisher::STAN do
|
35
|
+
let(:cluster_id) { 'test-cluster' } # this is a default cluster for https://hub.docker.com/_/nats-streaming
|
36
|
+
let(:client_id) { 'bps-test' }
|
37
|
+
|
38
|
+
let(:nats_servers) { ENV.fetch('NATS_SERVERS', '127.0.0.1:4222').split(',') }
|
39
|
+
let(:nats_servers_with_scheme) { nats_servers.map {|s| "nats://#{s}" } }
|
40
|
+
|
41
|
+
let(:publisher_url) { "stan://#{CGI.escape(nats_servers.join(','))}/?cluster_id=#{cluster_id}&client_id=#{client_id}" }
|
42
|
+
|
43
|
+
def read_messages(topic_name, num_messages)
|
44
|
+
[].tap do |messages|
|
45
|
+
opts = {
|
46
|
+
servers: nats_servers_with_scheme,
|
47
|
+
dont_randomize_servers: true,
|
48
|
+
}
|
49
|
+
::STAN::Client.new.connect(cluster_id, client_id, nats: opts) do |client|
|
50
|
+
client.subscribe(topic_name, start_at: :first) do |msg|
|
51
|
+
messages << msg.data
|
52
|
+
next if messages.size == num_messages
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it_behaves_like 'publisher'
|
59
|
+
end
|
60
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bps-stan
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Black Square Media
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-11-09 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.1.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.1.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nats-streaming
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.2.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.2.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-stan.gemspec
|
48
|
+
- lib/bps-stan.rb
|
49
|
+
- lib/bps/publisher/stan.rb
|
50
|
+
- lib/bps/stan.rb
|
51
|
+
- spec/bps/stan_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.2
|
72
|
+
signing_key:
|
73
|
+
specification_version: 4
|
74
|
+
summary: BPS adapter for nats-streaming
|
75
|
+
test_files:
|
76
|
+
- spec/bps/stan_spec.rb
|