routemaster-client 2.0.0 → 2.1.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 +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +12 -1
- data/README.md +5 -0
- data/routemaster/client/backends/sidekiq/worker.rb +24 -0
- data/routemaster/client/backends/sidekiq.rb +26 -0
- data/routemaster/client/backends/synchronous.rb +24 -0
- data/routemaster/client/backends.rb +10 -0
- data/routemaster/client/connection.rb +75 -0
- data/routemaster/client/version.rb +1 -1
- data/routemaster/client.rb +31 -61
- data/spec/client_spec.rb +55 -14
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ab7db72b3f45ca016af6ddfcd31727c08448d04
|
4
|
+
data.tar.gz: 864cc421186071bf194c01c230f778016ab4011c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d48921d988693488e7aed1b03b22526a88cd320eb85ce97976c32b0b0458fd79703043a0ef9f3e82971a9afcc3712f6427ce55c7aacc3ce5b00af81dd15ca24e
|
7
|
+
data.tar.gz: 856f4e0a2f340dbbe9d5c8b13e39fea9026b94ce48f53ec81bbca6da1ba5d860fd4460339cbd5fefdf3f43129cc51bc63130b81aa5e4132a2a84ee350bd34573
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
routemaster-client (2.
|
4
|
+
routemaster-client (2.1.0)
|
5
5
|
faraday (>= 0.9.0)
|
6
6
|
oj (~> 2.17)
|
7
7
|
typhoeus (~> 1.1)
|
@@ -16,6 +16,8 @@ GEM
|
|
16
16
|
codeclimate-test-reporter (1.0.3)
|
17
17
|
simplecov
|
18
18
|
coderay (1.1.1)
|
19
|
+
concurrent-ruby (1.0.2)
|
20
|
+
connection_pool (2.2.1)
|
19
21
|
crack (0.4.3)
|
20
22
|
safe_yaml (~> 1.0.0)
|
21
23
|
diff-lcs (1.2.5)
|
@@ -64,12 +66,15 @@ GEM
|
|
64
66
|
psych (2.2.1)
|
65
67
|
public_suffix (2.0.4)
|
66
68
|
rack (2.0.1)
|
69
|
+
rack-protection (1.5.3)
|
70
|
+
rack
|
67
71
|
rack-test (0.6.3)
|
68
72
|
rack (>= 1.0)
|
69
73
|
rake (11.3.0)
|
70
74
|
rb-fsevent (0.9.8)
|
71
75
|
rb-inotify (0.9.7)
|
72
76
|
ffi (>= 0.5.0)
|
77
|
+
redis (3.3.2)
|
73
78
|
rspec (3.5.0)
|
74
79
|
rspec-core (~> 3.5.0)
|
75
80
|
rspec-expectations (~> 3.5.0)
|
@@ -86,6 +91,11 @@ GEM
|
|
86
91
|
ruby_dep (1.5.0)
|
87
92
|
safe_yaml (1.0.4)
|
88
93
|
shellany (0.0.1)
|
94
|
+
sidekiq (4.2.1)
|
95
|
+
concurrent-ruby (~> 1.0)
|
96
|
+
connection_pool (~> 2.2, >= 2.2.0)
|
97
|
+
rack-protection (~> 1.5)
|
98
|
+
redis (~> 3.2, >= 3.2.1)
|
89
99
|
simplecov (0.12.0)
|
90
100
|
docile (~> 1.1.0)
|
91
101
|
json (>= 1.8, < 3)
|
@@ -113,6 +123,7 @@ DEPENDENCIES
|
|
113
123
|
rack-test
|
114
124
|
rake
|
115
125
|
routemaster-client!
|
126
|
+
sidekiq
|
116
127
|
simplecov
|
117
128
|
webmock
|
118
129
|
|
data/README.md
CHANGED
@@ -34,6 +34,11 @@ You can also specify a timeout value in seconds if you like with the ```timeout`
|
|
34
34
|
Routemaster::Client.new(url: 'https://bus.example.com', uuid: 'demo', timeout: 2)
|
35
35
|
```
|
36
36
|
|
37
|
+
If you are using Sidekiq in your project, you can specify the usage of a Sidekiq backend, where event sending will be processed asynchronously.
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
Routemaster::Client.new(url, 'https://bus.example.com', uuid: 'demo', backend_type: Routemaster::Client::Backends::Sidekiq)
|
41
|
+
```
|
37
42
|
|
38
43
|
**Push** an event about an entity in the topic `widgets` with a callback URL:
|
39
44
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'routemaster/client/connection'
|
2
|
+
|
3
|
+
module Routemaster
|
4
|
+
class Client
|
5
|
+
module Backends
|
6
|
+
class Sidekiq
|
7
|
+
class Worker
|
8
|
+
include ::Sidekiq::Worker
|
9
|
+
|
10
|
+
def perform(event, topic, callback, timestamp, options)
|
11
|
+
conn = Routemaster::Client::Connection.new(_symbolize_keys(options))
|
12
|
+
conn.send_event(event, topic, callback, timestamp)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def _symbolize_keys(hash)
|
18
|
+
Hash[hash.map{|(k,v)| [k.to_sym,v]}]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
require 'routemaster/client/backends/sidekiq/worker'
|
3
|
+
|
4
|
+
module Routemaster
|
5
|
+
class Client
|
6
|
+
module Backends
|
7
|
+
class Sidekiq
|
8
|
+
@queue = :realtime
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def configure(options)
|
12
|
+
new(options)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(options)
|
17
|
+
@_options = options
|
18
|
+
end
|
19
|
+
|
20
|
+
def send_event(event, topic, callback, timestamp = nil)
|
21
|
+
Worker.perform_async(event, topic, callback, timestamp, @_options)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'routemaster/client/connection'
|
2
|
+
|
3
|
+
module Routemaster
|
4
|
+
class Client
|
5
|
+
module Backends
|
6
|
+
class Synchronous
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def configure(options)
|
10
|
+
new(options)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(options)
|
15
|
+
@conn = Routemaster::Client::Connection.new(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def send_event(event, topic, callback, timestamp = nil)
|
19
|
+
@conn.send_event(event, topic, callback, timestamp)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Routemaster
|
2
|
+
class Client
|
3
|
+
module Backends
|
4
|
+
NAMES = ["Routemaster::Client::Backends::Synchronous", "Routemaster::Client::Backends::Sidekiq"]
|
5
|
+
|
6
|
+
autoload 'Synchronous', 'routemaster/client/backends/synchronous'
|
7
|
+
autoload 'Sidekiq', 'routemaster/client/backends/sidekiq'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
# Internal class used by Routemaster::Client
|
4
|
+
|
5
|
+
module Routemaster
|
6
|
+
class Client
|
7
|
+
class Connection
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
@_url = options[:url]
|
11
|
+
@_uuid = options[:uuid]
|
12
|
+
@_timeout = options.fetch(:timeout, 1)
|
13
|
+
@_verify_ssl = options.fetch(:verify_ssl, true)
|
14
|
+
end
|
15
|
+
|
16
|
+
def http(method, path, &block)
|
17
|
+
_conn.send(method, path, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def post(path, &block)
|
21
|
+
http(:post, path, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def get(path, &block)
|
25
|
+
http(:get, path, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete(path, &block)
|
29
|
+
http(:delete, path, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def send_event(event, topic, callback, timestamp = nil)
|
33
|
+
data = { type: event, url: callback, timestamp: timestamp }
|
34
|
+
|
35
|
+
response = post("/topics/#{topic}") do |r|
|
36
|
+
r.headers['Content-Type'] = 'application/json'
|
37
|
+
r.body = Oj.dump(_stringify_keys data)
|
38
|
+
end
|
39
|
+
fail "event rejected (#{response.status})" unless response.success?
|
40
|
+
end
|
41
|
+
|
42
|
+
def subscribe(options)
|
43
|
+
response = post('/subscription') do |r|
|
44
|
+
r.headers['Content-Type'] = 'application/json'
|
45
|
+
r.body = Oj.dump(_stringify_keys options)
|
46
|
+
end
|
47
|
+
|
48
|
+
unless response.success?
|
49
|
+
raise 'subscribe rejected'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def _stringify_keys(hash)
|
56
|
+
hash.dup.tap do |h|
|
57
|
+
h.keys.each do |k|
|
58
|
+
h[k.to_s] = h.delete(k)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def _conn
|
64
|
+
@_conn ||= Faraday.new(@_url, ssl: { verify: @_verify_ssl }) do |f|
|
65
|
+
f.request :retry, max: 2, interval: 100e-3, backoff_factor: 2
|
66
|
+
f.request :basic_auth, @_uuid, 'x'
|
67
|
+
f.adapter :typhoeus
|
68
|
+
|
69
|
+
f.options.timeout = @_timeout
|
70
|
+
f.options.open_timeout = @_timeout
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/routemaster/client.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'routemaster/client/backends'
|
2
|
+
require 'routemaster/client/connection'
|
1
3
|
require 'routemaster/client/version'
|
2
4
|
require 'routemaster/topic'
|
3
5
|
require 'uri'
|
@@ -9,17 +11,22 @@ require 'oj'
|
|
9
11
|
|
10
12
|
module Routemaster
|
11
13
|
class Client
|
12
|
-
|
14
|
+
|
13
15
|
def initialize(options = {})
|
14
|
-
@
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
@_options = options.tap do |o|
|
17
|
+
o[:timeout] ||= 1
|
18
|
+
o[:backend_type] ||= Backends::Synchronous
|
19
|
+
end
|
20
|
+
|
21
|
+
@_backend_type = @_options.fetch(:backend_type)
|
22
|
+
|
23
|
+
_assert_valid_url(@_options[:url])
|
24
|
+
_assert_valid_backend_type(@_backend_type)
|
25
|
+
_assert (@_options[:uuid] =~ /^[a-z0-9_-]{1,64}$/), 'uuid should be alpha'
|
26
|
+
_assert_valid_timeout(@_options[:timeout])
|
18
27
|
|
19
|
-
_assert (options[:uuid] =~ /^[a-z0-9_-]{1,64}$/), 'uuid should be alpha'
|
20
|
-
_assert_valid_timeout(@_timeout)
|
21
28
|
|
22
|
-
unless
|
29
|
+
unless @_options[:lazy]
|
23
30
|
_conn.get('/pulse').tap do |response|
|
24
31
|
raise 'cannot connect to bus' unless response.success?
|
25
32
|
end
|
@@ -53,22 +60,14 @@ module Routemaster
|
|
53
60
|
|
54
61
|
options[:topics].each { |t| _assert_valid_topic(t) }
|
55
62
|
_assert_valid_url(options[:callback])
|
56
|
-
|
57
|
-
response = _post('/subscription') do |r|
|
58
|
-
r.headers['Content-Type'] = 'application/json'
|
59
|
-
r.body = Oj.dump(_stringify_keys options)
|
60
|
-
end
|
61
|
-
|
62
|
-
unless response.success?
|
63
|
-
raise 'subscribe rejected'
|
64
|
-
end
|
63
|
+
_conn.subscribe(options)
|
65
64
|
end
|
66
65
|
|
67
66
|
def unsubscribe(*topics)
|
68
67
|
topics.each { |t| _assert_valid_topic(t) }
|
69
68
|
|
70
69
|
topics.each do |t|
|
71
|
-
response =
|
70
|
+
response = _conn.delete("/subscriber/topics/#{t}")
|
72
71
|
|
73
72
|
unless response.success?
|
74
73
|
raise 'unsubscribe rejected'
|
@@ -77,7 +76,7 @@ module Routemaster
|
|
77
76
|
end
|
78
77
|
|
79
78
|
def unsubscribe_all
|
80
|
-
response =
|
79
|
+
response = _conn.delete('/subscriber')
|
81
80
|
|
82
81
|
unless response.success?
|
83
82
|
raise 'unsubscribe all rejected'
|
@@ -87,7 +86,7 @@ module Routemaster
|
|
87
86
|
def delete_topic(topic)
|
88
87
|
_assert_valid_topic(topic)
|
89
88
|
|
90
|
-
response =
|
89
|
+
response = _conn.delete("/topics/#{topic}")
|
91
90
|
|
92
91
|
unless response.success?
|
93
92
|
raise 'failed to delete topic'
|
@@ -95,7 +94,7 @@ module Routemaster
|
|
95
94
|
end
|
96
95
|
|
97
96
|
def monitor_topics
|
98
|
-
response =
|
97
|
+
response = _conn.get('/topics') do |r|
|
99
98
|
r.headers['Content-Type'] = 'application/json'
|
100
99
|
end
|
101
100
|
|
@@ -108,17 +107,8 @@ module Routemaster
|
|
108
107
|
end
|
109
108
|
end
|
110
109
|
|
111
|
-
|
112
110
|
private
|
113
111
|
|
114
|
-
def _stringify_keys(hash)
|
115
|
-
hash.dup.tap do |h|
|
116
|
-
h.keys.each do |k|
|
117
|
-
h[k.to_s] = h.delete(k)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
112
|
def _assert_valid_timeout(timeout)
|
123
113
|
_assert (0..3_600_000).include?(timeout), 'bad timeout'
|
124
114
|
end
|
@@ -141,49 +131,29 @@ module Routemaster
|
|
141
131
|
_assert timestamp.kind_of?(Integer), 'not an integer'
|
142
132
|
end
|
143
133
|
|
134
|
+
def _assert_valid_backend_type(backend_type)
|
135
|
+
backends = Backends::NAMES
|
136
|
+
_assert backends.include?(backend_type.to_s), "unknown backend type, must be one of #{backends.map{ |w| "Routemaster::Backends::#{w}" }.join(", ")}"
|
137
|
+
backend_type
|
138
|
+
end
|
139
|
+
|
144
140
|
def _send_event(event, topic, callback, timestamp = nil)
|
145
141
|
_assert_valid_url(callback)
|
146
142
|
_assert_valid_topic(topic)
|
147
143
|
_assert_valid_timestamp(timestamp) if timestamp
|
148
|
-
|
149
|
-
data = { type: event, url: callback, timestamp: timestamp }
|
150
|
-
|
151
|
-
response = _post("/topics/#{topic}") do |r|
|
152
|
-
r.headers['Content-Type'] = 'application/json'
|
153
|
-
r.body = Oj.dump(_stringify_keys data)
|
154
|
-
end
|
155
|
-
fail "event rejected (#{response.status})" unless response.success?
|
144
|
+
_backend.send_event(event, topic, callback, timestamp)
|
156
145
|
end
|
157
146
|
|
158
147
|
def _assert(condition, message)
|
159
148
|
condition or raise ArgumentError.new(message)
|
160
149
|
end
|
161
150
|
|
162
|
-
def _http(method, path, &block)
|
163
|
-
_conn.send(method, path, &block)
|
164
|
-
end
|
165
|
-
|
166
|
-
def _post(path, &block)
|
167
|
-
_http(:post, path, &block)
|
168
|
-
end
|
169
|
-
|
170
|
-
def _get(path, &block)
|
171
|
-
_http(:get, path, &block)
|
172
|
-
end
|
173
|
-
|
174
|
-
def _delete(path, &block)
|
175
|
-
_http(:delete, path, &block)
|
176
|
-
end
|
177
|
-
|
178
151
|
def _conn
|
179
|
-
@_conn ||=
|
180
|
-
|
181
|
-
f.request :basic_auth, @_uuid, 'x'
|
182
|
-
f.adapter :typhoeus
|
152
|
+
@_conn ||= Client::Connection.new(@_options)
|
153
|
+
end
|
183
154
|
|
184
|
-
|
185
|
-
|
186
|
-
end
|
155
|
+
def _backend
|
156
|
+
@_worker ||= @_backend_type.configure(@_options)
|
187
157
|
end
|
188
158
|
end
|
189
159
|
end
|
data/spec/client_spec.rb
CHANGED
@@ -2,6 +2,7 @@ require 'spec_helper'
|
|
2
2
|
require 'routemaster/client'
|
3
3
|
require 'routemaster/topic'
|
4
4
|
require 'webmock/rspec'
|
5
|
+
require 'sidekiq/testing'
|
5
6
|
|
6
7
|
describe Routemaster::Client do
|
7
8
|
let(:options) {{
|
@@ -39,6 +40,12 @@ describe Routemaster::Client do
|
|
39
40
|
expect { subject }.to raise_error(ArgumentError)
|
40
41
|
end
|
41
42
|
|
43
|
+
it 'fails with an invalid worker_type' do
|
44
|
+
Jeff = double
|
45
|
+
options[:backend_type] = Jeff
|
46
|
+
expect { subject }.to raise_error(ArgumentError)
|
47
|
+
end
|
48
|
+
|
42
49
|
context 'when connection fails' do
|
43
50
|
before do
|
44
51
|
stub_request(:any, %r{^https://bus.example.com}).
|
@@ -167,24 +174,58 @@ describe Routemaster::Client do
|
|
167
174
|
end
|
168
175
|
end
|
169
176
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
177
|
+
context "With no background worker specified" do
|
178
|
+
describe '#created' do
|
179
|
+
let(:event) { 'created' }
|
180
|
+
it_behaves_like 'an event sender'
|
181
|
+
end
|
174
182
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
183
|
+
describe '#updated' do
|
184
|
+
let(:event) { 'updated' }
|
185
|
+
it_behaves_like 'an event sender'
|
186
|
+
end
|
187
|
+
|
188
|
+
describe '#deleted' do
|
189
|
+
let(:event) { 'deleted' }
|
190
|
+
it_behaves_like 'an event sender'
|
191
|
+
end
|
179
192
|
|
180
|
-
|
181
|
-
|
182
|
-
|
193
|
+
describe '#noop' do
|
194
|
+
let(:event) { 'noop' }
|
195
|
+
it_behaves_like 'an event sender'
|
196
|
+
end
|
183
197
|
end
|
184
198
|
|
185
|
-
|
186
|
-
|
187
|
-
|
199
|
+
context "With the sidekiq back end" do
|
200
|
+
before do
|
201
|
+
options[:backend_type] = Routemaster::Client::Backends::Sidekiq
|
202
|
+
end
|
203
|
+
|
204
|
+
around do |example|
|
205
|
+
Sidekiq::Testing.inline! do
|
206
|
+
example.run
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe '#created' do
|
211
|
+
let(:event) { 'created' }
|
212
|
+
it_behaves_like 'an event sender'
|
213
|
+
end
|
214
|
+
|
215
|
+
describe '#updated' do
|
216
|
+
let(:event) { 'updated' }
|
217
|
+
it_behaves_like 'an event sender'
|
218
|
+
end
|
219
|
+
|
220
|
+
describe '#deleted' do
|
221
|
+
let(:event) { 'deleted' }
|
222
|
+
it_behaves_like 'an event sender'
|
223
|
+
end
|
224
|
+
|
225
|
+
describe '#noop' do
|
226
|
+
let(:event) { 'noop' }
|
227
|
+
it_behaves_like 'an event sender'
|
228
|
+
end
|
188
229
|
end
|
189
230
|
|
190
231
|
describe '#subscribe' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: routemaster-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julien Letessier
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
11
|
+
date: 2016-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: typhoeus
|
@@ -86,6 +86,11 @@ files:
|
|
86
86
|
- Rakefile
|
87
87
|
- routemaster-client.gemspec
|
88
88
|
- routemaster/client.rb
|
89
|
+
- routemaster/client/backends.rb
|
90
|
+
- routemaster/client/backends/sidekiq.rb
|
91
|
+
- routemaster/client/backends/sidekiq/worker.rb
|
92
|
+
- routemaster/client/backends/synchronous.rb
|
93
|
+
- routemaster/client/connection.rb
|
89
94
|
- routemaster/client/version.rb
|
90
95
|
- routemaster/receiver.rb
|
91
96
|
- routemaster/topic.rb
|