pressure 0.1.5 → 0.1.6

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: 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: