roda-sse 0.1.0 → 0.2.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 +4 -4
- data/README.md +0 -2
- data/lib/roda/plugins/sse.rb +56 -6
- data/spec/roda-sse_spec.rb +52 -21
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e98e9c2879bb55ccadf0400d243d97ecff39fa4d6535a044cae739e3410878c
|
4
|
+
data.tar.gz: aa3d255a8cb4ecab1ddb9b5d71c916f6907c36529a934c38467ca57b4e3cb1a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dee16a19a420769ed068a7bf977b4ef3a05b1d5425e1f9bf4ab2899697e0e13ac2255dc96af84178cb18ada3d6e85645ce91b5b7b4d91508213ecb422fc9a08b
|
7
|
+
data.tar.gz: 946654c542c416ae617e641e5dff7b3cb16d9fa8c5873946db293f5ff98b1d6043fdf9e71c6caa16acdf9f655affe0a14b38cf10fa89edeea0c774ebe1af02c8
|
data/README.md
CHANGED
data/lib/roda/plugins/sse.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'async'
|
4
|
+
require 'async/barrier'
|
5
|
+
|
3
6
|
class Roda
|
4
7
|
module RodaPlugins
|
5
8
|
# Example:
|
@@ -11,22 +14,69 @@ class Roda
|
|
11
14
|
# # GET /
|
12
15
|
# r.sse do |stream|
|
13
16
|
# stream.write "data: hola\n\n"
|
14
|
-
# ensure
|
15
|
-
# stream.close
|
16
17
|
# end
|
17
18
|
# end
|
18
19
|
# end
|
19
20
|
module SSE
|
21
|
+
class Stream
|
22
|
+
def initialize(&block)
|
23
|
+
@block = block
|
24
|
+
@barrier = Async::Barrier.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def write(message)
|
28
|
+
data = message.to_s
|
29
|
+
|
30
|
+
@barrier.async do
|
31
|
+
@stream.write(data)
|
32
|
+
rescue Errno::ECONNRESET, Errno::EPIPE
|
33
|
+
@barrier.close
|
34
|
+
end
|
35
|
+
|
36
|
+
data.bytesize
|
37
|
+
end
|
38
|
+
|
39
|
+
def <<(message)
|
40
|
+
write(message)
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def call(stream)
|
45
|
+
Sync do
|
46
|
+
@stream = stream
|
47
|
+
@block.call(stream)
|
48
|
+
ensure
|
49
|
+
close
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def close
|
54
|
+
return if @closed
|
55
|
+
|
56
|
+
@barrier.stop
|
57
|
+
@stream&.close
|
58
|
+
@closed = true
|
59
|
+
end
|
60
|
+
|
61
|
+
def closed? = @closed
|
62
|
+
end
|
63
|
+
|
20
64
|
module RequestMethods
|
21
65
|
def sse(&block)
|
22
|
-
|
23
|
-
|
66
|
+
get do
|
67
|
+
response['Content-Type'] = 'text/event-stream'
|
68
|
+
response['Cache-Control'] = 'no-cache'
|
24
69
|
|
25
|
-
|
26
|
-
halt response.finish_with_body(block)
|
70
|
+
halt response.finish_with_body(Stream.new(&block))
|
27
71
|
end
|
28
72
|
end
|
29
73
|
end
|
74
|
+
|
75
|
+
module InstanceMethods
|
76
|
+
def last_event_id
|
77
|
+
env['HTTP_LAST_EVENT_ID']
|
78
|
+
end
|
79
|
+
end
|
30
80
|
end
|
31
81
|
|
32
82
|
register_plugin(:sse, SSE)
|
data/spec/roda-sse_spec.rb
CHANGED
@@ -12,9 +12,8 @@ class App < Roda
|
|
12
12
|
route do |r|
|
13
13
|
r.root do
|
14
14
|
r.sse do |stream|
|
15
|
+
last_event_id
|
15
16
|
stream.write "data: hola\n\n"
|
16
|
-
ensure
|
17
|
-
stream.close
|
18
17
|
end
|
19
18
|
end
|
20
19
|
end
|
@@ -23,34 +22,66 @@ end
|
|
23
22
|
def app = App.freeze.app
|
24
23
|
|
25
24
|
describe 'roda-sse plugin' do
|
26
|
-
include Rack::Test::Methods
|
27
|
-
|
28
25
|
prove_it!
|
29
26
|
|
30
|
-
|
31
|
-
|
27
|
+
describe 'roda app' do
|
28
|
+
include Rack::Test::Methods
|
32
29
|
|
33
|
-
|
34
|
-
|
30
|
+
it 'responds 200 OK' do
|
31
|
+
get '/'
|
32
|
+
|
33
|
+
assert last_response.ok?
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'does not respond to PUT' do
|
37
|
+
post '/'
|
35
38
|
|
36
|
-
|
37
|
-
|
39
|
+
refute last_response.ok?
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'has SSE headers' do
|
43
|
+
get '/'
|
44
|
+
|
45
|
+
headers = {'content-type' => 'text/event-stream', 'cache-control' => 'no-cache'}
|
46
|
+
assert_equal headers, last_response.headers
|
47
|
+
end
|
38
48
|
|
39
|
-
|
40
|
-
|
49
|
+
it 'streams the body' do
|
50
|
+
get '/'
|
51
|
+
|
52
|
+
stream = Minitest::Mock.new
|
53
|
+
stream.expect(:write, nil, ["data: hola\n\n"])
|
54
|
+
stream.expect(:close, nil)
|
55
|
+
response_body = last_response.instance_variable_get(:@body)
|
56
|
+
assert_instance_of Roda::RodaPlugins::SSE::Stream, response_body
|
57
|
+
|
58
|
+
response_body.call(stream)
|
59
|
+
|
60
|
+
stream.verify
|
61
|
+
end
|
41
62
|
end
|
42
63
|
|
43
|
-
|
44
|
-
|
64
|
+
describe 'stream class' do
|
65
|
+
before do
|
66
|
+
@stream = Roda::RodaPlugins::SSE::Stream.new do |stream|
|
67
|
+
stream << 42
|
68
|
+
stream.write(43)
|
69
|
+
end
|
70
|
+
end
|
45
71
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
response_body = last_response.instance_variable_get(:@body)
|
50
|
-
assert_instance_of Proc, response_body
|
72
|
+
it 'opens' do
|
73
|
+
refute @stream.closed?
|
74
|
+
end
|
51
75
|
|
52
|
-
|
76
|
+
it 'streams and closes' do
|
77
|
+
stream = Minitest::Mock.new
|
78
|
+
stream.expect(:<<, nil, [42])
|
79
|
+
stream.expect(:write, nil, [43])
|
80
|
+
stream.expect(:close, nil)
|
81
|
+
@stream.call(stream)
|
82
|
+
assert_instance_of Roda::RodaPlugins::SSE::Stream, @stream
|
53
83
|
|
54
|
-
|
84
|
+
stream.verify
|
85
|
+
end
|
55
86
|
end
|
56
87
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roda-sse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shannon Skipper
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2024-
|
10
|
+
date: 2024-11-01 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: roda
|
@@ -15,14 +15,28 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - "~>"
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: '3.
|
18
|
+
version: '3.85'
|
19
19
|
type: :runtime
|
20
20
|
prerelease: false
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
23
|
- - "~>"
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version: '3.
|
25
|
+
version: '3.85'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: async
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.18'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.18'
|
26
40
|
description: The roda-sse gem integrates simple SSE streaming into the roda web toolkit.
|
27
41
|
email: shannonskipper@gmail.com
|
28
42
|
executables: []
|