rasti-web-broadcaster 1.1.2 → 2.0.1
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 +4 -4
- data/.github/workflows/ci.yml +37 -0
- data/README.md +2 -3
- data/lib/rasti/web/broadcaster/timer.rb +37 -0
- data/lib/rasti/web/broadcaster/version.rb +1 -1
- data/lib/rasti/web/broadcaster.rb +53 -14
- data/rasti-web-broadcaster.gemspec +0 -5
- data/spec/coverage_helper.rb +1 -2
- data/spec/middleware_spec.rb +4 -3
- data/spec/minitest_helper.rb +4 -1
- data/spec/timer_spec.rb +48 -0
- metadata +10 -22
- data/.coveralls.yml +0 -2
- data/.travis.yml +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4274cbf5d65945a27bddcaa7372223972319791e59d74cf87a44b3782ccfd8c
|
4
|
+
data.tar.gz: 1ae384e5c92f88234341f3c7c610409ae0c16aff25d0c1df42fac452f615f85a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fcc2e8c4646744d1016bc3e17e63f5dcf6ebf95703efbe8f0c0434cf2ac9c262266e6b1cbc3e2a6b86a726b448162c97d8d723a6dccfe48618de7e657eb248df
|
7
|
+
data.tar.gz: fadc9eeb6b0633864fd6c418a0194a603d8495e627e631fabb16db8ca7ad7d4b615787626de55eb89897ecff264ff0cb247197c03304aefd3c8ea03644926e75
|
@@ -0,0 +1,37 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ '**' ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ '**' ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
|
12
|
+
name: Tests
|
13
|
+
runs-on: ubuntu-22.04
|
14
|
+
strategy:
|
15
|
+
matrix:
|
16
|
+
ruby-version: ['2.3', '2.4', '2.5', '2.6', '2.7', '3.0', 'jruby-9.2.9.0']
|
17
|
+
|
18
|
+
services:
|
19
|
+
redis:
|
20
|
+
image: redis:7
|
21
|
+
ports:
|
22
|
+
- 6379:6379
|
23
|
+
options: >-
|
24
|
+
--health-cmd "redis-cli ping"
|
25
|
+
--health-interval 10s
|
26
|
+
--health-timeout 5s
|
27
|
+
--health-retries 3
|
28
|
+
|
29
|
+
steps:
|
30
|
+
- uses: actions/checkout@v3
|
31
|
+
- name: Set up Ruby
|
32
|
+
uses: ruby/setup-ruby@v1
|
33
|
+
with:
|
34
|
+
ruby-version: ${{ matrix.ruby-version }}
|
35
|
+
bundler-cache: true
|
36
|
+
- name: Run tests
|
37
|
+
run: bundle exec rake
|
data/README.md
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
# Rasti::Web::Broadcaster
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/rasti-web-broadcaster)
|
4
|
-
[](https://coveralls.io/r/gabynaiman/rasti-web-broadcaster?branch=master)
|
6
|
-
[](https://codeclimate.com/github/gabynaiman/rasti-web-broadcaster)
|
4
|
+
[](https://github.com/gabynaiman/rasti-web-broadcaster/actions/workflows/ci.yml)
|
7
5
|
|
8
6
|
Enable server sent events with rack middleware implemented over Faye and Broadcaster (Redis Pub/Sub)
|
9
7
|
|
@@ -30,6 +28,7 @@ Or install it yourself as:
|
|
30
28
|
Rasti::Web::Broadcaster.configure do |config|
|
31
29
|
config.id = 'AppName'
|
32
30
|
config.redis_settings = "redis://#{ENV['REDIS_HOST']}:#{ENV['REDIS_PORT']}"
|
31
|
+
config.keep_alive_interval = 30
|
33
32
|
config.logger = Logger.new "/log/#{ENV['RACK_ENV']}.log"
|
34
33
|
end
|
35
34
|
```
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Rasti
|
2
|
+
module Web
|
3
|
+
class Broadcaster
|
4
|
+
class Timer
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def every(interval, &block)
|
8
|
+
Thread.new do
|
9
|
+
loop do
|
10
|
+
execute_using_time_slot(interval, &block)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def execute_using_time_slot(interval)
|
18
|
+
started_at = Time.now
|
19
|
+
yield
|
20
|
+
|
21
|
+
rescue => ex
|
22
|
+
Broadcaster.logger.error(self) { ex }
|
23
|
+
|
24
|
+
ensure
|
25
|
+
elapsed_time = Time.now - started_at
|
26
|
+
if elapsed_time > interval
|
27
|
+
Broadcaster.logger.warn(self) { "Elapsed time #{elapsed_time}s for interval of #{interval}s" }
|
28
|
+
else
|
29
|
+
sleep interval - elapsed_time
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -4,18 +4,22 @@ require 'class_config'
|
|
4
4
|
|
5
5
|
require_relative 'broadcaster/safe_event_machine'
|
6
6
|
require_relative 'broadcaster/safe_rack_lint'
|
7
|
+
require_relative 'broadcaster/timer'
|
7
8
|
require_relative 'broadcaster/version'
|
8
9
|
|
9
10
|
module Rasti
|
10
11
|
module Web
|
11
12
|
class Broadcaster
|
12
13
|
|
14
|
+
KEEP_ALIVE_EVENT = 'keepAlive'
|
15
|
+
|
13
16
|
extend ClassConfig
|
14
17
|
|
15
|
-
attr_config :id,
|
16
|
-
attr_config :redis_client,
|
17
|
-
attr_config :redis_settings,
|
18
|
-
attr_config :logger,
|
18
|
+
attr_config :id, 'rasti.web.broadcaster'
|
19
|
+
attr_config :redis_client, Redic
|
20
|
+
attr_config :redis_settings, 'redis://localhost:6379'
|
21
|
+
attr_config :logger, Logger.new(STDOUT)
|
22
|
+
attr_config :keep_alive_interval
|
19
23
|
|
20
24
|
@mutex = Mutex.new
|
21
25
|
|
@@ -23,8 +27,8 @@ module Rasti
|
|
23
27
|
|
24
28
|
extend Forwardable
|
25
29
|
|
26
|
-
def_delegators :broadcaster, :subscribe,
|
27
|
-
:unsubscribe,
|
30
|
+
def_delegators :broadcaster, :subscribe,
|
31
|
+
:unsubscribe,
|
28
32
|
:publish
|
29
33
|
|
30
34
|
private
|
@@ -40,20 +44,20 @@ module Rasti
|
|
40
44
|
def initialize(app, headers={})
|
41
45
|
@app = app
|
42
46
|
@headers = headers
|
47
|
+
@mutex = Mutex.new
|
48
|
+
@subscriptions = {}
|
49
|
+
|
50
|
+
start_sending_keep_alive_messages
|
43
51
|
end
|
44
52
|
|
45
53
|
def call(env)
|
46
54
|
if Faye::EventSource.eventsource? env
|
47
|
-
event_source = Faye::EventSource.new env, headers:
|
48
|
-
channel = env['PATH_INFO'][1..-1]
|
55
|
+
event_source = Faye::EventSource.new env, headers: headers
|
49
56
|
|
50
|
-
subscription_id =
|
51
|
-
event_source.send message[:data], event: message[:event],
|
52
|
-
id: message[:id]
|
53
|
-
end
|
57
|
+
subscription_id = subscribe channel_from(env), event_source
|
54
58
|
|
55
59
|
event_source.on :close do
|
56
|
-
|
60
|
+
unsubscribe subscription_id
|
57
61
|
event_source = nil
|
58
62
|
end
|
59
63
|
|
@@ -65,7 +69,42 @@ module Rasti
|
|
65
69
|
|
66
70
|
private
|
67
71
|
|
68
|
-
attr_reader :app
|
72
|
+
attr_reader :app, :headers, :mutex, :subscriptions
|
73
|
+
|
74
|
+
def subscribe(channel, event_source)
|
75
|
+
subscription_id = self.class.subscribe channel do |message|
|
76
|
+
self.class.logger.info(self.class) { "Sending message to #{subscription_id} | Channel: #{channel} | Message: #{message}" }
|
77
|
+
send_message(event_source, **message)
|
78
|
+
end
|
79
|
+
|
80
|
+
mutex.synchronize { subscriptions[subscription_id] = event_source }
|
81
|
+
|
82
|
+
subscription_id
|
83
|
+
end
|
84
|
+
|
85
|
+
def unsubscribe(subscription_id)
|
86
|
+
self.class.unsubscribe subscription_id
|
87
|
+
mutex.synchronize { subscriptions.delete subscription_id }
|
88
|
+
end
|
89
|
+
|
90
|
+
def send_message(event_source, data:, event: nil, id: nil)
|
91
|
+
event_source.send data, event: event, id: id
|
92
|
+
end
|
93
|
+
|
94
|
+
def start_sending_keep_alive_messages
|
95
|
+
if self.class.keep_alive_interval
|
96
|
+
Timer.every self.class.keep_alive_interval do
|
97
|
+
subscriptions.each do |subscription_id, event_source|
|
98
|
+
self.class.logger.debug(self.class) { "Sending keep alive to #{subscription_id}" }
|
99
|
+
send_message event_source, data: '', event: KEEP_ALIVE_EVENT
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def channel_from(env)
|
106
|
+
env['PATH_INFO'][1..-1]
|
107
|
+
end
|
69
108
|
|
70
109
|
end
|
71
110
|
end
|
@@ -27,11 +27,6 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency 'minitest-colorin', '~> 0.1'
|
28
28
|
spec.add_development_dependency 'minitest-line', '~> 0.6'
|
29
29
|
spec.add_development_dependency 'simplecov', '~> 0.12'
|
30
|
-
spec.add_development_dependency 'coveralls', '~> 0.8'
|
31
30
|
spec.add_development_dependency 'pry-nav', '~> 0.2'
|
32
31
|
spec.add_development_dependency 'rack-test', '~> 0.6'
|
33
|
-
|
34
|
-
if RUBY_VERSION < '2.2.2'
|
35
|
-
spec.add_development_dependency 'rack', '< 2'
|
36
|
-
end
|
37
32
|
end
|
data/spec/coverage_helper.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'simplecov'
|
2
|
-
require 'coveralls'
|
3
2
|
|
4
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new [SimpleCov::Formatter::HTMLFormatter
|
3
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new [SimpleCov::Formatter::HTMLFormatter]
|
5
4
|
SimpleCov.start
|
data/spec/middleware_spec.rb
CHANGED
@@ -47,7 +47,7 @@ describe Rasti::Web::Broadcaster do
|
|
47
47
|
event_source = nil
|
48
48
|
events = []
|
49
49
|
|
50
|
-
env['async.callback'] = proc do |(
|
50
|
+
env['async.callback'] = proc do |(_status, _headers, body)|
|
51
51
|
event_source = body.instance_variable_get(:@socket_object)
|
52
52
|
body.each { |e| events << e }
|
53
53
|
end
|
@@ -60,14 +60,15 @@ describe Rasti::Web::Broadcaster do
|
|
60
60
|
Rasti::Web::Broadcaster.publish 'channel_2', data: 'message 2'
|
61
61
|
Rasti::Web::Broadcaster.publish 'channel_1', data: 'message 3'
|
62
62
|
|
63
|
-
wait_for { events.count ==
|
63
|
+
wait_for { events.count == 4 }
|
64
64
|
|
65
65
|
event_source.close
|
66
66
|
|
67
67
|
events.must_equal [
|
68
68
|
event_headers,
|
69
69
|
event_for(data: 'message 1', event: 'event_1', id: 1),
|
70
|
-
event_for(data: 'message 3')
|
70
|
+
event_for(data: 'message 3'),
|
71
|
+
event_for(event: Rasti::Web::Broadcaster::KEEP_ALIVE_EVENT)
|
71
72
|
]
|
72
73
|
end
|
73
74
|
|
data/spec/minitest_helper.rb
CHANGED
data/spec/timer_spec.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'minitest_helper'
|
2
|
+
|
3
|
+
describe Rasti::Web::Broadcaster::Timer do
|
4
|
+
|
5
|
+
let(:timer) { Rasti::Web::Broadcaster::Timer }
|
6
|
+
|
7
|
+
it 'Tick' do
|
8
|
+
count = 0
|
9
|
+
|
10
|
+
thread = timer.every(0.02) do
|
11
|
+
count += 1
|
12
|
+
end
|
13
|
+
|
14
|
+
sleep 0.07
|
15
|
+
thread.exit
|
16
|
+
|
17
|
+
count.must_equal 4
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'Interval exceded' do
|
21
|
+
count = 0
|
22
|
+
|
23
|
+
thread = timer.every(0.02) do
|
24
|
+
sleep 0.04 if count == 1
|
25
|
+
count += 1
|
26
|
+
end
|
27
|
+
|
28
|
+
sleep 0.07
|
29
|
+
thread.exit
|
30
|
+
|
31
|
+
count.must_equal 3
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'Error safe' do
|
35
|
+
count = 0
|
36
|
+
|
37
|
+
thread = timer.every(0.02) do
|
38
|
+
count += 1
|
39
|
+
raise 'Unexpected error' if count == 2
|
40
|
+
end
|
41
|
+
|
42
|
+
sleep 0.05
|
43
|
+
thread.exit
|
44
|
+
|
45
|
+
count.must_equal 3
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rasti-web-broadcaster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gabriel Naiman
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-06-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faye-websocket
|
@@ -134,20 +134,6 @@ dependencies:
|
|
134
134
|
- - "~>"
|
135
135
|
- !ruby/object:Gem::Version
|
136
136
|
version: '0.12'
|
137
|
-
- !ruby/object:Gem::Dependency
|
138
|
-
name: coveralls
|
139
|
-
requirement: !ruby/object:Gem::Requirement
|
140
|
-
requirements:
|
141
|
-
- - "~>"
|
142
|
-
- !ruby/object:Gem::Version
|
143
|
-
version: '0.8'
|
144
|
-
type: :development
|
145
|
-
prerelease: false
|
146
|
-
version_requirements: !ruby/object:Gem::Requirement
|
147
|
-
requirements:
|
148
|
-
- - "~>"
|
149
|
-
- !ruby/object:Gem::Version
|
150
|
-
version: '0.8'
|
151
137
|
- !ruby/object:Gem::Dependency
|
152
138
|
name: pry-nav
|
153
139
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,11 +170,10 @@ executables: []
|
|
184
170
|
extensions: []
|
185
171
|
extra_rdoc_files: []
|
186
172
|
files:
|
187
|
-
- ".
|
173
|
+
- ".github/workflows/ci.yml"
|
188
174
|
- ".gitignore"
|
189
175
|
- ".ruby-gemset"
|
190
176
|
- ".ruby-version"
|
191
|
-
- ".travis.yml"
|
192
177
|
- Gemfile
|
193
178
|
- LICENSE.txt
|
194
179
|
- README.md
|
@@ -197,16 +182,18 @@ files:
|
|
197
182
|
- lib/rasti/web/broadcaster.rb
|
198
183
|
- lib/rasti/web/broadcaster/safe_event_machine.rb
|
199
184
|
- lib/rasti/web/broadcaster/safe_rack_lint.rb
|
185
|
+
- lib/rasti/web/broadcaster/timer.rb
|
200
186
|
- lib/rasti/web/broadcaster/version.rb
|
201
187
|
- rasti-web-broadcaster.gemspec
|
202
188
|
- spec/coverage_helper.rb
|
203
189
|
- spec/middleware_spec.rb
|
204
190
|
- spec/minitest_helper.rb
|
191
|
+
- spec/timer_spec.rb
|
205
192
|
homepage: https://github.com/gabynaiman/rasti-web-broadcaster
|
206
193
|
licenses:
|
207
194
|
- MIT
|
208
195
|
metadata: {}
|
209
|
-
post_install_message:
|
196
|
+
post_install_message:
|
210
197
|
rdoc_options: []
|
211
198
|
require_paths:
|
212
199
|
- lib
|
@@ -221,11 +208,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
221
208
|
- !ruby/object:Gem::Version
|
222
209
|
version: '0'
|
223
210
|
requirements: []
|
224
|
-
rubygems_version: 3.0.
|
225
|
-
signing_key:
|
211
|
+
rubygems_version: 3.0.9
|
212
|
+
signing_key:
|
226
213
|
specification_version: 4
|
227
214
|
summary: Rack middleware for server sent events
|
228
215
|
test_files:
|
229
216
|
- spec/coverage_helper.rb
|
230
217
|
- spec/middleware_spec.rb
|
231
218
|
- spec/minitest_helper.rb
|
219
|
+
- spec/timer_spec.rb
|
data/.coveralls.yml
DELETED
data/.travis.yml
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
|
3
|
-
rvm:
|
4
|
-
- 2.0
|
5
|
-
- 2.1
|
6
|
-
- 2.2
|
7
|
-
- 2.3
|
8
|
-
- 2.4
|
9
|
-
- 2.5
|
10
|
-
- 2.6
|
11
|
-
- 2.7
|
12
|
-
- jruby-9.2.9.0
|
13
|
-
- ruby-head
|
14
|
-
- jruby-head
|
15
|
-
|
16
|
-
matrix:
|
17
|
-
fast_finish: true
|
18
|
-
allow_failures:
|
19
|
-
- rvm: ruby-head
|
20
|
-
- rvm: jruby-head
|
21
|
-
|
22
|
-
services:
|
23
|
-
- redis-server
|