routemaster-client 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|