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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5e98e9c2879bb55ccadf0400d243d97ecff39fa4d6535a044cae739e3410878c
4
- data.tar.gz: aa3d255a8cb4ecab1ddb9b5d71c916f6907c36529a934c38467ca57b4e3cb1a7
3
+ metadata.gz: e63c433081f53c50061c380222d40ba9ea30bedd06b5d95982c3dcf9bbd15fa3
4
+ data.tar.gz: 5bd7d45309f2903e6a953d59b9c02e58c6e965d758859f990ba435eed1372f23
5
5
  SHA512:
6
- metadata.gz: dee16a19a420769ed068a7bf977b4ef3a05b1d5425e1f9bf4ab2899697e0e13ac2255dc96af84178cb18ada3d6e85645ce91b5b7b4d91508213ecb422fc9a08b
7
- data.tar.gz: 946654c542c416ae617e641e5dff7b3cb16d9fa8c5873946db293f5ff98b1d6043fdf9e71c6caa16acdf9f655affe0a14b38cf10fa89edeea0c774ebe1af02c8
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 headers and provides Rack 3 streaming for you to send your own events.
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
 
@@ -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 Stream
22
- def initialize(&block)
23
- @block = block
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
- @barrier.async do
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 call(stream)
45
- Sync do
46
- @stream = stream
47
- @block.call(stream)
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
- def close
54
- return if @closed
55
-
56
- @barrier.stop
57
- @stream&.close
58
- @closed = true
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
- response['Content-Type'] = 'text/event-stream'
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
@@ -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(:close, nil)
54
+ stream.expect(:close_write, nil, [nil])
55
55
  response_body = last_response.instance_variable_get(:@body)
56
- assert_instance_of Roda::RodaPlugins::SSE::Stream, response_body
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.2.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-01 00:00:00.000000000 Z
11
+ date: 2024-11-04 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: roda