roda-sse 0.2.0 → 0.3.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 +7 -1
- data/lib/roda/plugins/sse.rb +27 -31
- data/spec/roda-sse_spec.rb +2 -26
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e63c433081f53c50061c380222d40ba9ea30bedd06b5d95982c3dcf9bbd15fa3
|
4
|
+
data.tar.gz: 5bd7d45309f2903e6a953d59b9c02e58c6e965d758859f990ba435eed1372f23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18b52b5dd1fc76864d52c74ee81ede34cdc266f3dde68e83c7235aae3f96fdb0a9af1c6451afe6be0a63ee4bd68bc830b275ae371d7cb6ae3fb81b56bc2bf882
|
7
|
+
data.tar.gz: b862451ef7df47f104892033286e14de121a5716c2857f8b31ce3bda2db1d66d130cbd6bcef22ddeedfdcd166372ca6c2505704cf2750efd752362ecf371027c
|
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# roda-sse
|
2
2
|
|
3
|
-
The roda-sse Roda plugin adds SSE
|
3
|
+
The roda-sse Roda plugin adds SSE provides a streaming interface for
|
4
|
+
server-sent events. Each stream is wrapped in an [Async](https://github.com/socketry/async) reactor
|
5
|
+
and events are sent asyncronously via tasks. The roda-sse plugin sets
|
6
|
+
appropriate SSE headers, handles disconnection errors, ensures
|
7
|
+
streams are properly closed and provies a `last_event_id` helper.
|
4
8
|
|
5
9
|
## Installation
|
6
10
|
|
@@ -15,6 +19,8 @@ https://github.com/havenwood/roda-sse
|
|
15
19
|
|
16
20
|
## Usage
|
17
21
|
|
22
|
+
See the [examples/](https://github.com/havenwood/roda-sse/tree/main/example) directory for an example app.
|
23
|
+
|
18
24
|
roda-sse is a Roda plugin, so you need to load it into your Roda
|
19
25
|
application similar to other plugins:
|
20
26
|
|
data/lib/roda/plugins/sse.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'async'
|
4
|
-
require 'async/barrier'
|
5
4
|
|
6
5
|
class Roda
|
7
6
|
module RodaPlugins
|
@@ -18,22 +17,15 @@ class Roda
|
|
18
17
|
# end
|
19
18
|
# end
|
20
19
|
module SSE
|
21
|
-
class
|
22
|
-
def initialize(
|
23
|
-
@
|
24
|
-
@barrier = Async::Barrier.new
|
20
|
+
class Output
|
21
|
+
def initialize(stream)
|
22
|
+
@stream = stream
|
25
23
|
end
|
26
24
|
|
27
25
|
def write(message)
|
28
26
|
data = message.to_s
|
29
|
-
|
30
|
-
|
31
|
-
@stream.write(data)
|
32
|
-
rescue Errno::ECONNRESET, Errno::EPIPE
|
33
|
-
@barrier.close
|
34
|
-
end
|
35
|
-
|
36
|
-
data.bytesize
|
27
|
+
@stream.write(data)
|
28
|
+
return data.bytesize
|
37
29
|
end
|
38
30
|
|
39
31
|
def <<(message)
|
@@ -41,33 +33,37 @@ class Roda
|
|
41
33
|
self
|
42
34
|
end
|
43
35
|
|
44
|
-
def
|
45
|
-
|
46
|
-
@stream =
|
47
|
-
|
48
|
-
ensure
|
49
|
-
close
|
36
|
+
def close(error = nil)
|
37
|
+
if stream = @stream
|
38
|
+
@stream = nil
|
39
|
+
stream.close_write(error)
|
50
40
|
end
|
51
41
|
end
|
42
|
+
end
|
52
43
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
44
|
+
class Body
|
45
|
+
def initialize(block)
|
46
|
+
@block = block
|
47
|
+
end
|
48
|
+
|
49
|
+
def call(stream)
|
50
|
+
output = Output.new(stream)
|
51
|
+
@block.call(output)
|
52
|
+
rescue => error
|
53
|
+
ensure
|
54
|
+
stream.close_write(error)
|
59
55
|
end
|
60
|
-
|
61
|
-
def closed? = @closed
|
62
56
|
end
|
63
57
|
|
64
58
|
module RequestMethods
|
59
|
+
HEADERS = {
|
60
|
+
'content-type' => 'text/event-stream',
|
61
|
+
'cache-control' => 'no-cache',
|
62
|
+
}.freeze
|
63
|
+
|
65
64
|
def sse(&block)
|
66
65
|
get do
|
67
|
-
|
68
|
-
response['Cache-Control'] = 'no-cache'
|
69
|
-
|
70
|
-
halt response.finish_with_body(Stream.new(&block))
|
66
|
+
halt [200, HEADERS.dup, Body.new(block)]
|
71
67
|
end
|
72
68
|
end
|
73
69
|
end
|
data/spec/roda-sse_spec.rb
CHANGED
@@ -51,37 +51,13 @@ describe 'roda-sse plugin' do
|
|
51
51
|
|
52
52
|
stream = Minitest::Mock.new
|
53
53
|
stream.expect(:write, nil, ["data: hola\n\n"])
|
54
|
-
stream.expect(:
|
54
|
+
stream.expect(:close_write, nil, [nil])
|
55
55
|
response_body = last_response.instance_variable_get(:@body)
|
56
|
-
assert_instance_of Roda::RodaPlugins::SSE::
|
56
|
+
assert_instance_of Roda::RodaPlugins::SSE::Body, response_body
|
57
57
|
|
58
58
|
response_body.call(stream)
|
59
59
|
|
60
60
|
stream.verify
|
61
61
|
end
|
62
62
|
end
|
63
|
-
|
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
|
71
|
-
|
72
|
-
it 'opens' do
|
73
|
-
refute @stream.closed?
|
74
|
-
end
|
75
|
-
|
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
|
83
|
-
|
84
|
-
stream.verify
|
85
|
-
end
|
86
|
-
end
|
87
63
|
end
|
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roda-sse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shannon Skipper
|
8
|
+
- Samuel Williams
|
8
9
|
bindir: bin
|
9
10
|
cert_chain: []
|
10
|
-
date: 2024-11-
|
11
|
+
date: 2024-11-04 00:00:00.000000000 Z
|
11
12
|
dependencies:
|
12
13
|
- !ruby/object:Gem::Dependency
|
13
14
|
name: roda
|