pressure 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a048ddc780e8947da7c84ca8413e5a0366a207a6
4
- data.tar.gz: 3aa8ae820e8817db9fea3d85309afc6e7c2d49a2
3
+ metadata.gz: 875dd6186d88bf1269640e4166024fd481803a3d
4
+ data.tar.gz: d193fd7bc0074ba85eb6938fbbb68d08dca89eda
5
5
  SHA512:
6
- metadata.gz: d14fbd0645a711683472d96c3b3e977f4fa68d3ac9ec9d547bb69b928f641ae5b7d8098bb46c3b8d1f536acd1f35f487c62a11e7118e944577e13153f25f38e6
7
- data.tar.gz: adf676d1ac5a7e333c773e7ea22291c499cabc0dcef8fde1d94b1991ebc12fad4e6df3e2877dd15cb0b1968c437bbcea59a764094dc15e5e9e26fa11c4d14359
6
+ metadata.gz: 0a3542194409705a6ad347b8ecaf06d4e15cb68e8cb11c9c2f7fcf9fd0e898ab5d09b26ab91f6152f8004088aa4344f8f99f74c30319d587760fd1565f8e1263
7
+ data.tar.gz: 142f22d60d5f869d8c8e939491cecb93f99fcb6523298be4edd902a0b84af9e37bfcf4f8eba7f1ffd0d52e4722690f8ccb46dd3273ccab69fc70c0fb93d721cd
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/bsdavidson/pressure.svg?branch=master)](https://travis-ci.org/bsdavidson/pressure)
4
4
 
5
- Multicast upstream data to downstream websocket clients.
5
+ Broadcast upstream data to downstream websocket clients.
6
6
 
7
7
  Documentation is [available on RubyDoc.info](http://www.rubydoc.info/github/bsdavidson/pressure/).
8
8
 
data/lib/pressure.rb CHANGED
@@ -1,38 +1,137 @@
1
- require_relative 'pressure/version'
1
+ require 'hamster'
2
+ require 'json'
2
3
  require 'logger'
3
4
  require 'time'
4
- require 'json'
5
5
 
6
+ require_relative 'pressure/version'
7
+
8
+ # Instances of the Pressure class can be used to read data from an upstream
9
+ # provider and broadcast it out to a set of downstream consumers.
10
+ #
11
+ # @!attribute [rw] logger
12
+ # @return [Logger] Messages are logged to this object.
13
+ # @!attribute [r] sockets
14
+ # @return [Hamster::Set<#send>] List of downstream sockets the instance is sending
15
+ # to. These objects don't necessarily need to be sockets, as long as they
16
+ # support a send method. Add objects to this list using the << method.
17
+ # @!attribute [rw] wrapper_template
18
+ # @return [Hash] The template used to wrap upstream data before sending it
19
+ # to downstream consumers. See wrap_data and the no_wrap option to
20
+ # initialize.
6
21
  class Pressure
7
- attr_accessor :wrapper_template
22
+ attr_writer :logger
23
+ attr_reader :running
8
24
  attr_reader :sockets
25
+ attr_accessor :wrapper_template
26
+
27
+ # The default delay between loops of worker threads.
28
+ DEFAULT_DELAY = (1.0 / 20.0)
9
29
 
30
+ # Create a new Pressure instance and start reading data.
31
+ #
32
+ # @param options [Hash] Additional options.
33
+ # @option options [Boolean] :no_wrap Data from upstream is wrapped in a JSON
34
+ # container by default, with some additional metadata. If this option is
35
+ # set to true, the data will be passed through without modification.
36
+ # @option options [Float] :read_worker_delay The amount of time, in seconds,
37
+ # to sleep between attempts to read data from upstream. Defaults to
38
+ # DEFAULT_DELAY.
39
+ # @option options [Float] :broadcast_worker_delay The amount of time, in
40
+ # seconds, to sleep between attempts to broadcast data to downstream
41
+ # sockets. Defaults to DEFAULT_DELAY.
42
+ # @yield Block to call to read data from upstream.
43
+ # @yieldreturn Data to send downstream.
10
44
  def initialize(options = {}, &data_source_block)
45
+ @threads = []
11
46
  @wrapper_template = {}
12
47
  @current_upstream = {}
13
48
  @send_queue = Queue.new
14
- @sockets = []
15
- @websocket_worker_delay = options[:websocket_worker_delay] || (1.0 / 20.0)
16
- @incoming_monitor_delay = options[:incoming_monitor_delay] || (1.0 / 20.0)
49
+ @sockets = Hamster::Set.new
50
+ @broadcast_worker_delay = (options[:broadcast_worker_delay] ||
51
+ options[:websocket_worker_delay] ||
52
+ DEFAULT_DELAY)
53
+ @read_worker_delay = (options[:read_worker_delay] ||
54
+ options[:incoming_monitor_delay] ||
55
+ DEFAULT_DELAY)
17
56
  @no_wrap = options[:no_wrap] || false
18
- incoming_monitor(&data_source_block)
19
- websocket_worker_loop
57
+ @running = false
58
+ @data_source_block = data_source_block
59
+ start unless options[:start] == false
60
+ end
61
+
62
+ def logger
63
+ @logger ||= Logger.new(STDERR).tap do |logger|
64
+ logger.progname = 'pressure'
65
+ logger.level = Logger::WARN
66
+ end
20
67
  end
21
68
 
69
+ # Add a downstream socket to the Pressure instance. The latest upstream
70
+ # data will be immediately sent to the socket.
71
+ #
72
+ # @param socket [Socket, #send] A socket, or object that responds to #send.
22
73
  def <<(socket)
23
- @sockets << socket
24
- socket.send JSON.generate(@current_upstream)
74
+ new_sockets = @sockets.add? socket
75
+ if new_sockets != false
76
+ @sockets = new_sockets
77
+ socket.send JSON.generate(@current_upstream)
78
+ end
25
79
  end
26
80
 
81
+ # Remove a downstream socket from the Pressure instance.
82
+ #
83
+ # @param socket [Socket, #send] A socket, or object that responds to #send,
84
+ # as added using <<.
85
+ # @return the deleted socket object, or nil.
27
86
  def delete(socket)
28
- @sockets.delete socket
87
+ new_sockets = @sockets.delete? socket
88
+ if new_sockets != false
89
+ @sockets = new_sockets
90
+ socket
91
+ else
92
+ nil
93
+ end
29
94
  end
30
95
 
96
+ # Start the worker threads.
97
+ def start
98
+ stop
99
+ @running = true
100
+ @threads << broadcast_worker_loop
101
+ @threads << read_worker_loop
102
+ end
103
+
104
+ # Stop the worker threads.
105
+ def stop
106
+ @running = false
107
+ @threads.each do |thread|
108
+ thread.kill(5)
109
+ thread.join
110
+ end
111
+ @threads = []
112
+ end
113
+
114
+ # @return [Boolean] true if the workers are running.
115
+ def running?
116
+ @running
117
+ end
118
+
119
+ protected
120
+
121
+ # Wraps upstream data in a container to add metadata to the object.
122
+ #
123
+ # @param data Upstream data.
124
+ # @return [Hash] wrapped data.
31
125
  def wrap_data(data)
32
126
  @wrapper_template.merge(upstream_data: Marshal.load(Marshal.dump(data)),
33
127
  last_update_ts: Time.now.utc.to_i)
34
128
  end
35
129
 
130
+ # Check whether two pieces of upstream data are different.
131
+ #
132
+ # @param current_data The most recent data read from upstream.
133
+ # @param previous_data The last set of data read from upstream.
134
+ # @return [Boolean] true if the data is different.
36
135
  def data_changed?(current_data, previous_data)
37
136
  if current_data && previous_data
38
137
  current_data != previous_data
@@ -41,12 +140,13 @@ class Pressure
41
140
  end
42
141
  end
43
142
 
44
- def incoming_monitor(&data_source_block)
143
+ # Loop function for the thread reading data from the upstream provider.
144
+ def read_worker_loop
45
145
  Thread.new do
46
146
  begin
47
147
  data = {}
48
- loop do
49
- upstream_data = data_source_block.call
148
+ while @running
149
+ upstream_data = @data_source_block.call
50
150
  if data_changed?(upstream_data, data[:upstream_data])
51
151
  data = wrap_data(upstream_data)
52
152
  @current_upstream = data
@@ -56,31 +156,34 @@ class Pressure
56
156
  @send_queue << data
57
157
  end
58
158
  end
59
- sleep(@incoming_monitor_delay)
159
+ sleep(@read_worker_delay)
60
160
  end
61
161
  rescue => e
62
- puts "error #{e}"
162
+ logger.error "Read worker error:"
163
+ logger.error e
63
164
  end
64
165
  end
65
166
  end
66
167
 
67
- def websocket_worker
68
- # logger.info data.inspect
168
+ # Write data to downstream sockets.
169
+ def broadcast
69
170
  queued_data = JSON.generate(@send_queue.shift)
70
171
  @sockets.each do |socket|
71
172
  socket.send queued_data
72
173
  end
73
174
  end
74
175
 
75
- def websocket_worker_loop
176
+ # Loop function for the thread writing data to the downstream providers.
177
+ def broadcast_worker_loop
76
178
  Thread.new do
77
179
  begin
78
- loop do
79
- websocket_worker
80
- sleep(@websocket_worker_delay)
180
+ while @running
181
+ broadcast
182
+ sleep(@broadcast_worker_delay)
81
183
  end
82
184
  rescue => e
83
- puts "Worker error: #{e}"
185
+ logger.error "Broadcast worker error:"
186
+ logger.error e
84
187
  retry
85
188
  end
86
189
  end
@@ -1,3 +1,4 @@
1
1
  class Pressure
2
- VERSION = '0.1.5'
2
+ # Current version of the Pressure gem.
3
+ VERSION = '0.1.6'
3
4
  end
data/pressure.gemspec CHANGED
@@ -20,10 +20,15 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ['lib']
22
22
 
23
- spec.add_development_dependency 'bundler', '~> 1.9'
24
- spec.add_development_dependency 'rake', '~> 10.0'
23
+ spec.add_dependency 'hamster', '~> 3.0'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.16'
26
+ spec.add_development_dependency 'rake', '~> 12.3'
25
27
  spec.add_development_dependency 'rspec'
26
- spec.add_development_dependency 'redcarpet', '~> 3.3'
27
- spec.add_development_dependency 'sinatra', '~> 1.4'
28
- spec.add_development_dependency 'yard', '~> 0.8'
28
+ spec.add_development_dependency 'redcarpet', '~> 3.4'
29
+ spec.add_development_dependency 'simplecov', '~>0.15'
30
+ spec.add_development_dependency 'sinatra', '~> 2.0'
31
+ spec.add_development_dependency 'sinatra-websocket', '~> 0.3'
32
+ spec.add_development_dependency 'timecop', '~> 0.9'
33
+ spec.add_development_dependency 'yard', '~> 0.9'
29
34
  end
metadata CHANGED
@@ -1,43 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pressure
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Davidson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-01-09 00:00:00.000000000 Z
11
+ date: 2018-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: hamster
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: '1.9'
33
+ version: '1.16'
20
34
  type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: '1.9'
40
+ version: '1.16'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '10.0'
47
+ version: '12.3'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: '10.0'
54
+ version: '12.3'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rspec
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -58,42 +72,84 @@ dependencies:
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: '3.3'
75
+ version: '3.4'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.4'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.15'
62
90
  type: :development
63
91
  prerelease: false
64
92
  version_requirements: !ruby/object:Gem::Requirement
65
93
  requirements:
66
94
  - - "~>"
67
95
  - !ruby/object:Gem::Version
68
- version: '3.3'
96
+ version: '0.15'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: sinatra
71
99
  requirement: !ruby/object:Gem::Requirement
72
100
  requirements:
73
101
  - - "~>"
74
102
  - !ruby/object:Gem::Version
75
- version: '1.4'
103
+ version: '2.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: sinatra-websocket
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.3'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.3'
125
+ - !ruby/object:Gem::Dependency
126
+ name: timecop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.9'
76
132
  type: :development
77
133
  prerelease: false
78
134
  version_requirements: !ruby/object:Gem::Requirement
79
135
  requirements:
80
136
  - - "~>"
81
137
  - !ruby/object:Gem::Version
82
- version: '1.4'
138
+ version: '0.9'
83
139
  - !ruby/object:Gem::Dependency
84
140
  name: yard
85
141
  requirement: !ruby/object:Gem::Requirement
86
142
  requirements:
87
143
  - - "~>"
88
144
  - !ruby/object:Gem::Version
89
- version: '0.8'
145
+ version: '0.9'
90
146
  type: :development
91
147
  prerelease: false
92
148
  version_requirements: !ruby/object:Gem::Requirement
93
149
  requirements:
94
150
  - - "~>"
95
151
  - !ruby/object:Gem::Version
96
- version: '0.8'
152
+ version: '0.9'
97
153
  description:
98
154
  email:
99
155
  - bsdavidson@gmail.com
@@ -137,9 +193,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
193
  version: '0'
138
194
  requirements: []
139
195
  rubyforge_project:
140
- rubygems_version: 2.4.5.1
196
+ rubygems_version: 2.6.11
141
197
  signing_key:
142
198
  specification_version: 4
143
199
  summary: Multicast upstream data to websocket clients
144
200
  test_files: []
145
- has_rdoc: