pubcontrol 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/{pccbhandler.rb → pcccbhandler.rb} +3 -3
- data/lib/pubcontrol.rb +32 -159
- data/lib/pubcontrolclient.rb +188 -0
- metadata +3 -3
- data/lib/pubcontrolset.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72a4849cda3e8c5921a09ff97df674726be6bc06
|
4
|
+
data.tar.gz: 53cb42aa569100d5f2d788545bcdd8a43435e904
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c6bec7d9dd4efd0806012f471449ef6086a5c97427fb13ce8ca26290a679d0809e94e953ec1f294dfc4a01f3f7c10c42c517ab409ef90e19705767fe2911a56
|
7
|
+
data.tar.gz: beda44c933432151d9ccc7b7fa73430c789830ca5f1e9db0f76a4a7fb5d9ec56def1c61913d551799c429af14c2b7884a96cafb8edf5de1f081088e30418e6b6
|
@@ -1,11 +1,11 @@
|
|
1
|
-
#
|
1
|
+
# pcccbhandler.rb
|
2
2
|
# ~~~~~~~~~
|
3
|
-
# This module implements the
|
3
|
+
# This module implements the PubControlClientCallbackHandler class.
|
4
4
|
# :authors: Konstantin Bokarius.
|
5
5
|
# :copyright: (c) 2015 by Fanout, Inc.
|
6
6
|
# :license: MIT, see LICENSE for more details.
|
7
7
|
|
8
|
-
class
|
8
|
+
class PubControlClientCallbackHandler
|
9
9
|
def initialize(num_calls, callback)
|
10
10
|
@num_calls = num_calls
|
11
11
|
@callback = callback
|
data/lib/pubcontrol.rb
CHANGED
@@ -5,187 +5,60 @@
|
|
5
5
|
# :copyright: (c) 2015 by Fanout, Inc.
|
6
6
|
# :license: MIT, see LICENSE for more details.
|
7
7
|
|
8
|
-
require 'algorithms'
|
9
|
-
require 'thread'
|
10
|
-
require 'base64'
|
11
|
-
require 'jwt'
|
12
|
-
require 'json'
|
13
|
-
require 'net/http'
|
14
|
-
require_relative 'item.rb'
|
15
8
|
require_relative 'format.rb'
|
16
|
-
require_relative '
|
9
|
+
require_relative 'item.rb'
|
10
|
+
require_relative 'pubcontrolclient.rb'
|
11
|
+
require_relative 'pcccbhandler.rb'
|
17
12
|
|
18
13
|
class PubControl
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
@lock = Mutex.new
|
24
|
-
@thread = nil
|
25
|
-
@thread_cond = nil
|
26
|
-
@thread_mutex = nil
|
27
|
-
@req_queue = Containers::Deque.new
|
28
|
-
@auth_basic_user = nil
|
29
|
-
@auth_basic_pass = nil
|
30
|
-
@auth_jwt_claim = nil
|
31
|
-
@auth_jwt_key = nil
|
32
|
-
end
|
33
|
-
|
34
|
-
def set_auth_basic(username, password)
|
35
|
-
@lock.synchronize do
|
36
|
-
@auth_basic_user = username
|
37
|
-
@auth_basic_pass = password
|
14
|
+
def initialize(config=nil)
|
15
|
+
@clients = Array.new
|
16
|
+
if !config.nil?
|
17
|
+
apply_config(config)
|
38
18
|
end
|
39
19
|
end
|
40
20
|
|
41
|
-
def
|
42
|
-
@
|
43
|
-
@auth_jwt_claim = claim
|
44
|
-
@auth_jwt_key = key
|
45
|
-
end
|
21
|
+
def remove_all_clients
|
22
|
+
@clients = Array.new
|
46
23
|
end
|
47
24
|
|
48
|
-
def
|
49
|
-
|
50
|
-
export['channel'] = channel
|
51
|
-
uri = nil
|
52
|
-
auth = nil
|
53
|
-
@lock.synchronize do
|
54
|
-
uri = @uri
|
55
|
-
auth = gen_auth_header
|
56
|
-
end
|
57
|
-
PubControl.pubcall(uri, auth, [export])
|
25
|
+
def add_client(client)
|
26
|
+
@clients.push(client)
|
58
27
|
end
|
59
28
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
uri = nil
|
64
|
-
auth = nil
|
65
|
-
@lock.synchronize do
|
66
|
-
uri = @uri
|
67
|
-
auth = gen_auth_header
|
68
|
-
ensure_thread
|
29
|
+
def apply_config(config)
|
30
|
+
if !config.is_a?(Array)
|
31
|
+
config = [config]
|
69
32
|
end
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
@lock.synchronize do
|
75
|
-
if !@thread.nil?
|
76
|
-
queue_req(['stop'])
|
77
|
-
@thread.join
|
78
|
-
@thread = nil
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def pubworker
|
84
|
-
quit = false
|
85
|
-
while !quit do
|
86
|
-
@thread_mutex.lock
|
87
|
-
if @req_queue.length == 0
|
88
|
-
@thread_cond.wait(@thread_mutex)
|
89
|
-
if @req_queue.length == 0
|
90
|
-
@thread_mutex.unlock
|
91
|
-
next
|
92
|
-
end
|
93
|
-
end
|
94
|
-
reqs = Array.new
|
95
|
-
while @req_queue.length > 0 and reqs.length < 10 do
|
96
|
-
m = @req_queue.pop_front
|
97
|
-
if m[0] == 'stop'
|
98
|
-
quit = true
|
99
|
-
break
|
100
|
-
end
|
101
|
-
reqs.push([m[1], m[2], m[3], m[4]])
|
102
|
-
end
|
103
|
-
@thread_mutex.unlock
|
104
|
-
if reqs.length > 0
|
105
|
-
PubControl.pubbatch(reqs)
|
33
|
+
config.each do |entry|
|
34
|
+
pub = PubControlClient.new(entry['uri'])
|
35
|
+
if entry.key?('iss')
|
36
|
+
pub.set_auth_jwt({'iss' => entry['iss']}, entry['key'])
|
106
37
|
end
|
38
|
+
@clients.push(pub)
|
107
39
|
end
|
108
40
|
end
|
109
41
|
|
110
|
-
def
|
111
|
-
|
112
|
-
|
113
|
-
content['items'] = items
|
114
|
-
request = Net::HTTP::Post.new(uri.request_uri)
|
115
|
-
request.body = content.to_json
|
116
|
-
if !auth_header.nil?
|
117
|
-
request['Authorization'] = auth_header
|
118
|
-
end
|
119
|
-
request['Content-Type'] = 'application/json'
|
120
|
-
use_ssl = uri.scheme == 'https'
|
121
|
-
response = Net::HTTP.start(uri.host, uri.port, use_ssl: use_ssl) do |http|
|
122
|
-
http.request(request)
|
123
|
-
end
|
124
|
-
# REVIEW: HTTPSuccess does not include 3xx status codes.
|
125
|
-
if !response.kind_of? Net::HTTPSuccess
|
126
|
-
raise 'failed to publish: ' + response.class.to_s + ' ' +
|
127
|
-
response.message
|
42
|
+
def finish
|
43
|
+
@clients.each do |pub|
|
44
|
+
pub.finish
|
128
45
|
end
|
129
46
|
end
|
130
47
|
|
131
|
-
def
|
132
|
-
|
133
|
-
|
134
|
-
auth_header = reqs[0][1]
|
135
|
-
items = Array.new
|
136
|
-
callbacks = Array.new
|
137
|
-
reqs.each do |req|
|
138
|
-
items.push(req[2])
|
139
|
-
callbacks.push(req[3])
|
140
|
-
end
|
141
|
-
begin
|
142
|
-
PubControl.pubcall(uri, auth_header, items)
|
143
|
-
result = [true, '']
|
144
|
-
rescue => e
|
145
|
-
result = [false, e.message]
|
146
|
-
end
|
147
|
-
callbacks.each do |callback|
|
148
|
-
if !callback.nil?
|
149
|
-
callback.call(result[0], result[1])
|
150
|
-
end
|
48
|
+
def publish(channel, item)
|
49
|
+
@clients.each do |pub|
|
50
|
+
pub.publish(channel, item)
|
151
51
|
end
|
152
52
|
end
|
153
53
|
|
154
|
-
def
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
def gen_auth_header
|
161
|
-
if !@auth_basic_user.nil?
|
162
|
-
return 'Basic ' + Base64.encode64(
|
163
|
-
'#{@auth_basic_user}:#{@auth_basic_pass}')
|
164
|
-
elsif !@auth_jwt_claim.nil?
|
165
|
-
if !@auth_jwt_claim.has_key?('exp')
|
166
|
-
claim = @auth_jwt_claim.clone
|
167
|
-
claim['exp'] = PubControl.timestamp_utcnow + 3600
|
168
|
-
else
|
169
|
-
claim = @auth_jwt_claim
|
170
|
-
end
|
171
|
-
return 'Bearer ' + JWT.encode(claim, @auth_jwt_key)
|
172
|
-
else
|
173
|
-
return nil
|
54
|
+
def publish_async(channel, item, callback=nil)
|
55
|
+
cb = nil
|
56
|
+
if !callback.nil?
|
57
|
+
cb = PubControlClientCallbackHandler.new(@clients.length, callback).
|
58
|
+
handler_method_symbol
|
174
59
|
end
|
175
|
-
|
176
|
-
|
177
|
-
def ensure_thread
|
178
|
-
if @thread.nil?
|
179
|
-
@thread_cond = ConditionVariable.new
|
180
|
-
@thread_mutex = Mutex.new
|
181
|
-
@thread = Thread.new { pubworker }
|
60
|
+
@clients.each do |pub|
|
61
|
+
pub.publish_async(channel, item, cb)
|
182
62
|
end
|
183
63
|
end
|
184
|
-
|
185
|
-
def queue_req(req)
|
186
|
-
@thread_mutex.lock
|
187
|
-
@req_queue.push_back(req)
|
188
|
-
@thread_cond.signal
|
189
|
-
@thread_mutex.unlock
|
190
|
-
end
|
191
64
|
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# pubcontrolclient.rb
|
2
|
+
# ~~~~~~~~~
|
3
|
+
# This module implements the PubControlClient class.
|
4
|
+
# :authors: Konstantin Bokarius.
|
5
|
+
# :copyright: (c) 2015 by Fanout, Inc.
|
6
|
+
# :license: MIT, see LICENSE for more details.
|
7
|
+
|
8
|
+
require 'algorithms'
|
9
|
+
require 'thread'
|
10
|
+
require 'base64'
|
11
|
+
require 'jwt'
|
12
|
+
require 'json'
|
13
|
+
require 'net/http'
|
14
|
+
require_relative 'item.rb'
|
15
|
+
|
16
|
+
class PubControlClient
|
17
|
+
attr_accessor :req_queue
|
18
|
+
|
19
|
+
def initialize(uri)
|
20
|
+
@uri = uri
|
21
|
+
@lock = Mutex.new
|
22
|
+
@thread = nil
|
23
|
+
@thread_cond = nil
|
24
|
+
@thread_mutex = nil
|
25
|
+
@req_queue = Containers::Deque.new
|
26
|
+
@auth_basic_user = nil
|
27
|
+
@auth_basic_pass = nil
|
28
|
+
@auth_jwt_claim = nil
|
29
|
+
@auth_jwt_key = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_auth_basic(username, password)
|
33
|
+
@lock.synchronize do
|
34
|
+
@auth_basic_user = username
|
35
|
+
@auth_basic_pass = password
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def set_auth_jwt(claim, key)
|
40
|
+
@lock.synchronize do
|
41
|
+
@auth_jwt_claim = claim
|
42
|
+
@auth_jwt_key = key
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def publish(channel, item)
|
47
|
+
export = item.export
|
48
|
+
export['channel'] = channel
|
49
|
+
uri = nil
|
50
|
+
auth = nil
|
51
|
+
@lock.synchronize do
|
52
|
+
uri = @uri
|
53
|
+
auth = gen_auth_header
|
54
|
+
end
|
55
|
+
PubControlClient.pubcall(uri, auth, [export])
|
56
|
+
end
|
57
|
+
|
58
|
+
def publish_async(channel, item, callback=nil)
|
59
|
+
export = item.export
|
60
|
+
export['channel'] = channel
|
61
|
+
uri = nil
|
62
|
+
auth = nil
|
63
|
+
@lock.synchronize do
|
64
|
+
uri = @uri
|
65
|
+
auth = gen_auth_header
|
66
|
+
ensure_thread
|
67
|
+
end
|
68
|
+
queue_req(['pub', uri, auth, export, callback])
|
69
|
+
end
|
70
|
+
|
71
|
+
def finish
|
72
|
+
@lock.synchronize do
|
73
|
+
if !@thread.nil?
|
74
|
+
queue_req(['stop'])
|
75
|
+
@thread.join
|
76
|
+
@thread = nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def pubworker
|
82
|
+
quit = false
|
83
|
+
while !quit do
|
84
|
+
@thread_mutex.lock
|
85
|
+
if @req_queue.length == 0
|
86
|
+
@thread_cond.wait(@thread_mutex)
|
87
|
+
if @req_queue.length == 0
|
88
|
+
@thread_mutex.unlock
|
89
|
+
next
|
90
|
+
end
|
91
|
+
end
|
92
|
+
reqs = Array.new
|
93
|
+
while @req_queue.length > 0 and reqs.length < 10 do
|
94
|
+
m = @req_queue.pop_front
|
95
|
+
if m[0] == 'stop'
|
96
|
+
quit = true
|
97
|
+
break
|
98
|
+
end
|
99
|
+
reqs.push([m[1], m[2], m[3], m[4]])
|
100
|
+
end
|
101
|
+
@thread_mutex.unlock
|
102
|
+
if reqs.length > 0
|
103
|
+
PubControlClient.pubbatch(reqs)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.pubcall(uri, auth_header, items)
|
109
|
+
uri = URI(uri + '/publish/')
|
110
|
+
content = Hash.new
|
111
|
+
content['items'] = items
|
112
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
113
|
+
request.body = content.to_json
|
114
|
+
if !auth_header.nil?
|
115
|
+
request['Authorization'] = auth_header
|
116
|
+
end
|
117
|
+
request['Content-Type'] = 'application/json'
|
118
|
+
use_ssl = uri.scheme == 'https'
|
119
|
+
response = Net::HTTP.start(uri.host, uri.port, use_ssl: use_ssl) do |http|
|
120
|
+
http.request(request)
|
121
|
+
end
|
122
|
+
if !response.kind_of? Net::HTTPSuccess
|
123
|
+
raise 'failed to publish: ' + response.class.to_s + ' ' +
|
124
|
+
response.message
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.pubbatch(reqs)
|
129
|
+
raise 'reqs length == 0' unless reqs.length > 0
|
130
|
+
uri = reqs[0][0]
|
131
|
+
auth_header = reqs[0][1]
|
132
|
+
items = Array.new
|
133
|
+
callbacks = Array.new
|
134
|
+
reqs.each do |req|
|
135
|
+
items.push(req[2])
|
136
|
+
callbacks.push(req[3])
|
137
|
+
end
|
138
|
+
begin
|
139
|
+
PubControlClient.pubcall(uri, auth_header, items)
|
140
|
+
result = [true, '']
|
141
|
+
rescue => e
|
142
|
+
result = [false, e.message]
|
143
|
+
end
|
144
|
+
callbacks.each do |callback|
|
145
|
+
if !callback.nil?
|
146
|
+
callback.call(result[0], result[1])
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.timestamp_utcnow
|
152
|
+
return Time.now.utc.to_i
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
|
157
|
+
def gen_auth_header
|
158
|
+
if !@auth_basic_user.nil?
|
159
|
+
return 'Basic ' + Base64.encode64(
|
160
|
+
'#{@auth_basic_user}:#{@auth_basic_pass}')
|
161
|
+
elsif !@auth_jwt_claim.nil?
|
162
|
+
if !@auth_jwt_claim.has_key?('exp')
|
163
|
+
claim = @auth_jwt_claim.clone
|
164
|
+
claim['exp'] = PubControlClient.timestamp_utcnow + 3600
|
165
|
+
else
|
166
|
+
claim = @auth_jwt_claim
|
167
|
+
end
|
168
|
+
return 'Bearer ' + JWT.encode(claim, @auth_jwt_key)
|
169
|
+
else
|
170
|
+
return nil
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def ensure_thread
|
175
|
+
if @thread.nil?
|
176
|
+
@thread_cond = ConditionVariable.new
|
177
|
+
@thread_mutex = Mutex.new
|
178
|
+
@thread = Thread.new { pubworker }
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def queue_req(req)
|
183
|
+
@thread_mutex.lock
|
184
|
+
@req_queue.push_back(req)
|
185
|
+
@thread_cond.signal
|
186
|
+
@thread_mutex.unlock
|
187
|
+
end
|
188
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pubcontrol
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Konstantin Bokarius
|
@@ -46,9 +46,9 @@ extra_rdoc_files: []
|
|
46
46
|
files:
|
47
47
|
- lib/format.rb
|
48
48
|
- lib/item.rb
|
49
|
-
- lib/
|
49
|
+
- lib/pcccbhandler.rb
|
50
50
|
- lib/pubcontrol.rb
|
51
|
-
- lib/
|
51
|
+
- lib/pubcontrolclient.rb
|
52
52
|
homepage: http://rubygems.org/gems/pubcontrol
|
53
53
|
licenses:
|
54
54
|
- MIT
|
data/lib/pubcontrolset.rb
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
# pubcontrolset.rb
|
2
|
-
# ~~~~~~~~~
|
3
|
-
# This module implements the PubControlSet class.
|
4
|
-
# :authors: Konstantin Bokarius.
|
5
|
-
# :copyright: (c) 2015 by Fanout, Inc.
|
6
|
-
# :license: MIT, see LICENSE for more details.
|
7
|
-
|
8
|
-
require_relative 'pubcontrol.rb'
|
9
|
-
require_relative 'pccbhandler.rb'
|
10
|
-
|
11
|
-
class PubControlSet
|
12
|
-
def initialize
|
13
|
-
@pubs = Array.new
|
14
|
-
at_exit { finish }
|
15
|
-
end
|
16
|
-
|
17
|
-
def clear
|
18
|
-
@pubs = Array.new
|
19
|
-
end
|
20
|
-
|
21
|
-
def add(pub)
|
22
|
-
@pubs.push(pub)
|
23
|
-
end
|
24
|
-
|
25
|
-
def apply_config(config)
|
26
|
-
config.each do |entry|
|
27
|
-
pub = PubControl.new(entry['uri'])
|
28
|
-
if entry.key?('iss')
|
29
|
-
pub.set_auth_jwt({'iss' => entry['iss']}, entry['key'])
|
30
|
-
end
|
31
|
-
@pubs.push(pub)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def apply_grip_config(config)
|
36
|
-
config.each do |entry|
|
37
|
-
if !entry.key?('control_uri')
|
38
|
-
next
|
39
|
-
end
|
40
|
-
pub = PubControl.new(entry['control_uri'])
|
41
|
-
if !entry.key?('control_iss')
|
42
|
-
pub.set_auth_jwt({'iss' => entry['control_iss']}, entry['key'])
|
43
|
-
end
|
44
|
-
@pubs.push(pub)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def publish(channel, item)
|
49
|
-
@pubs.each do |pub|
|
50
|
-
pub.publish(channel, item)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def publish_async(channel, item, callback=nil)
|
55
|
-
cb = nil
|
56
|
-
if !callback.nil?
|
57
|
-
cb = PubControlCallbackHandler.new(@pubs.length, callback).
|
58
|
-
handler_method_symbol
|
59
|
-
end
|
60
|
-
@pubs.each do |pub|
|
61
|
-
pub.publish_async(channel, item, cb)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def finish
|
68
|
-
@pubs.each do |pub|
|
69
|
-
pub.finish
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|