pubcontrol 0.2.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ab97545468d3337e4e281e5d36f515a3acb707d4
4
- data.tar.gz: f9649e54bce224b03683182c09583c283b358e4c
3
+ metadata.gz: 72a4849cda3e8c5921a09ff97df674726be6bc06
4
+ data.tar.gz: 53cb42aa569100d5f2d788545bcdd8a43435e904
5
5
  SHA512:
6
- metadata.gz: ffe3037a12a43e76a5a1fbc09cccda35833c3c5528c04ee66d3ccdb670ae657f0d300a4e88a1410d63e8d83959083a8a9836dfe7cfc68f3cf695fe85093751bc
7
- data.tar.gz: cfd4eb7cd7c050d8e67c5741545a1ceba708f0f4e29b32d5c2f7a423ebbe7b26508cfffc408e850d121afc6be63ed32fc05dc5e4d16604038b96f65297c3cf8b
6
+ metadata.gz: 8c6bec7d9dd4efd0806012f471449ef6086a5c97427fb13ce8ca26290a679d0809e94e953ec1f294dfc4a01f3f7c10c42c517ab409ef90e19705767fe2911a56
7
+ data.tar.gz: beda44c933432151d9ccc7b7fa73430c789830ca5f1e9db0f76a4a7fb5d9ec56def1c61913d551799c429af14c2b7884a96cafb8edf5de1f081088e30418e6b6
@@ -1,11 +1,11 @@
1
- # format.rb
1
+ # pcccbhandler.rb
2
2
  # ~~~~~~~~~
3
- # This module implements the PubControlCallbackHandler class.
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 PubControlCallbackHandler
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 'pubcontrolset.rb'
9
+ require_relative 'item.rb'
10
+ require_relative 'pubcontrolclient.rb'
11
+ require_relative 'pcccbhandler.rb'
17
12
 
18
13
  class PubControl
19
- attr_accessor :req_queue
20
-
21
- def initialize(uri)
22
- @uri = uri
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 set_auth_jwt(claim, key)
42
- @lock.synchronize do
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 publish(channel, item)
49
- export = item.export
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 publish_async(channel, item, callback=nil)
61
- export = item.export
62
- export['channel'] = channel
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
- queue_req(['pub', uri, auth, export, callback])
71
- end
72
-
73
- def finish
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 self.pubcall(uri, auth_header, items)
111
- uri = URI(uri + '/publish/')
112
- content = Hash.new
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 self.pubbatch(reqs)
132
- raise 'reqs length == 0' unless reqs.length > 0
133
- uri = reqs[0][0]
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 self.timestamp_utcnow
155
- return Time.now.utc.to_i
156
- end
157
-
158
- private
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
- end
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.2.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/pccbhandler.rb
49
+ - lib/pcccbhandler.rb
50
50
  - lib/pubcontrol.rb
51
- - lib/pubcontrolset.rb
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