Class: Datastar::Dispatcher
- Inherits:
-
Object
- Object
- Datastar::Dispatcher
- Defined in:
- lib/datastar/dispatcher.rb
Overview
The Dispatcher encapsulates the logic of handling a request and building a response with streaming datastar messages. You’ll normally instantiate a Dispatcher in your controller action of Rack handler via Datastar.new.
Constant Summary collapse
- BLANK_BODY =
[].freeze
- SSE_CONTENT_TYPE =
'text/event-stream'- HTTP_ACCEPT =
'HTTP_ACCEPT'- HTTP1 =
'HTTP/1.1'
Instance Attribute Summary collapse
-
#request ⇒ Object
readonly
Returns the value of attribute request.
-
#response ⇒ Object
readonly
Returns the value of attribute response.
Instance Method Summary collapse
-
#execute_script(script, options = BLANK_OPTIONS) ⇒ Object
One-off execute script in the UI See data-star.dev/reference/sse_events#datastar-execute-script.
-
#initialize(request:, response: nil, view_context: nil, executor: Datastar.config.executor, error_callback: Datastar.config.error_callback, finalize: Datastar.config.finalize, heartbeat: Datastar.config.heartbeat) ⇒ Dispatcher
constructor
A new instance of Dispatcher.
-
#merge_fragments(fragments, options = BLANK_OPTIONS) ⇒ Object
Send one-off fragments to the UI See data-star.dev/reference/sse_events#datastar-merge-fragments.
-
#merge_signals(signals, options = BLANK_OPTIONS) ⇒ Object
One-off merge signals in the UI See data-star.dev/reference/sse_events#datastar-merge-signals.
-
#on_client_disconnect(callable = nil, &block) ⇒ self
Register a callback for client disconnection Ex.
-
#on_connect(callable = nil) {|sse| ... } ⇒ self
Register an on-connect callback Triggered when the request is handled.
-
#on_error(callable = nil, &block) ⇒ self
Register a callback server-side exceptions Ex.
-
#on_server_disconnect(callable = nil, &block) ⇒ self
Register a callback for server disconnection Ex.
-
#redirect(url) ⇒ Object
Send an execute_script event to change window.location.
-
#remove_fragments(selector, options = BLANK_OPTIONS) ⇒ Object
One-off remove fragments from the UI See data-star.dev/reference/sse_events#datastar-remove-fragments.
-
#remove_signals(paths, options = BLANK_OPTIONS) ⇒ Object
One-off remove signals from the UI See data-star.dev/reference/sse_events#datastar-remove-signals.
-
#signals ⇒ Hash
Parse and returns Datastar signals sent by the client.
-
#sse? ⇒ Boolean
Check if the request accepts SSE responses.
-
#stream(streamer = nil) {|sse| ... } ⇒ Object
Start a streaming response A generator object is passed to the block The generator supports all the Datastar methods listed above (it’s the same type) But you can call them multiple times to send multiple messages down an open SSE connection.
Constructor Details
#initialize(request:, response: nil, view_context: nil, executor: Datastar.config.executor, error_callback: Datastar.config.error_callback, finalize: Datastar.config.finalize, heartbeat: Datastar.config.heartbeat) ⇒ Dispatcher
Returns a new instance of Dispatcher.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/datastar/dispatcher.rb', line 39 def initialize( request:, response: nil, view_context: nil, executor: Datastar.config.executor, error_callback: Datastar.config.error_callback, finalize: Datastar.config.finalize, heartbeat: Datastar.config.heartbeat ) @on_connect = [] @on_client_disconnect = [] @on_server_disconnect = [] @on_error = [error_callback] @finalize = finalize @streamers = [] @queue = nil @executor = executor @view_context = view_context @request = request @response = Rack::Response.new(BLANK_BODY, 200, response&.headers || {}) @response.content_type = SSE_CONTENT_TYPE @response.headers['Cache-Control'] = 'no-cache' @response.headers['Connection'] = 'keep-alive' if @request.env['SERVER_PROTOCOL'] == HTTP1 # Disable response buffering in NGinx and other proxies @response.headers['X-Accel-Buffering'] = 'no' @response.delete_header 'Content-Length' @executor.prepare(@response) raise ArgumentError, ':heartbeat must be a number' if heartbeat && !heartbeat.is_a?(Numeric) @heartbeat = heartbeat @heartbeat_on = false end |
Instance Attribute Details
#request ⇒ Object (readonly)
Returns the value of attribute request.
30 31 32 |
# File 'lib/datastar/dispatcher.rb', line 30 def request @request end |
#response ⇒ Object (readonly)
Returns the value of attribute response.
30 31 32 |
# File 'lib/datastar/dispatcher.rb', line 30 def response @response end |
Instance Method Details
#execute_script(script, options = BLANK_OPTIONS) ⇒ Object
One-off execute script in the UI See data-star.dev/reference/sse_events#datastar-execute-script
188 189 190 191 192 |
# File 'lib/datastar/dispatcher.rb', line 188 def execute_script(script, = BLANK_OPTIONS) stream_no_heartbeat do |sse| sse.execute_script(script, ) end end |
#merge_fragments(fragments, options = BLANK_OPTIONS) ⇒ Object
Send one-off fragments to the UI See data-star.dev/reference/sse_events#datastar-merge-fragments
132 133 134 135 136 |
# File 'lib/datastar/dispatcher.rb', line 132 def merge_fragments(fragments, = BLANK_OPTIONS) stream_no_heartbeat do |sse| sse.merge_fragments(fragments, ) end end |
#merge_signals(signals, options = BLANK_OPTIONS) ⇒ Object
One-off merge signals in the UI See data-star.dev/reference/sse_events#datastar-merge-signals
160 161 162 163 164 |
# File 'lib/datastar/dispatcher.rb', line 160 def merge_signals(signals, = BLANK_OPTIONS) stream_no_heartbeat do |sse| sse.merge_signals(signals, ) end end |
#on_client_disconnect(callable = nil, &block) ⇒ self
Register a callback for client disconnection Ex. when the browser is closed mid-stream
92 93 94 95 |
# File 'lib/datastar/dispatcher.rb', line 92 def on_client_disconnect(callable = nil, &block) @on_client_disconnect << (callable || block) self end |
#on_connect(callable = nil) {|sse| ... } ⇒ self
Register an on-connect callback Triggered when the request is handled
83 84 85 86 |
# File 'lib/datastar/dispatcher.rb', line 83 def on_connect(callable = nil, &block) @on_connect << (callable || block) self end |
#on_error(callable = nil, &block) ⇒ self
Register a callback server-side exceptions Ex. when one of the server threads raises an exception
110 111 112 113 |
# File 'lib/datastar/dispatcher.rb', line 110 def on_error(callable = nil, &block) @on_error << (callable || block) self end |
#on_server_disconnect(callable = nil, &block) ⇒ self
Register a callback for server disconnection Ex. when the server finishes serving the request
101 102 103 104 |
# File 'lib/datastar/dispatcher.rb', line 101 def on_server_disconnect(callable = nil, &block) @on_server_disconnect << (callable || block) self end |
#redirect(url) ⇒ Object
Send an execute_script event to change window.location
198 199 200 201 202 |
# File 'lib/datastar/dispatcher.rb', line 198 def redirect(url) stream_no_heartbeat do |sse| sse.redirect(url) end end |
#remove_fragments(selector, options = BLANK_OPTIONS) ⇒ Object
One-off remove fragments from the UI See data-star.dev/reference/sse_events#datastar-remove-fragments
146 147 148 149 150 |
# File 'lib/datastar/dispatcher.rb', line 146 def remove_fragments(selector, = BLANK_OPTIONS) stream_no_heartbeat do |sse| sse.remove_fragments(selector, ) end end |
#remove_signals(paths, options = BLANK_OPTIONS) ⇒ Object
One-off remove signals from the UI See data-star.dev/reference/sse_events#datastar-remove-signals
174 175 176 177 178 |
# File 'lib/datastar/dispatcher.rb', line 174 def remove_signals(paths, = BLANK_OPTIONS) stream_no_heartbeat do |sse| sse.remove_signals(paths, ) end end |
#signals ⇒ Hash
Parse and returns Datastar signals sent by the client. See data-star.dev/guide/getting_started#data-signals
118 119 120 |
# File 'lib/datastar/dispatcher.rb', line 118 def signals @signals ||= parse_signals(request).freeze end |
#sse? ⇒ Boolean
Check if the request accepts SSE responses
74 75 76 |
# File 'lib/datastar/dispatcher.rb', line 74 def sse? @request.get_header(HTTP_ACCEPT) == SSE_CONTENT_TYPE end |
#stream(streamer = nil) {|sse| ... } ⇒ Object
Start a streaming response A generator object is passed to the block The generator supports all the Datastar methods listed above (it’s the same type) But you can call them multiple times to send multiple messages down an open SSE connection. This methods also captures exceptions raised in the block and triggers any error callbacks. Client disconnection errors trigger the @on_client_disconnect callbacks. Finally, when the block is done streaming, the @on_server_disconnect callbacks are triggered.
When multiple streams are scheduled this way, this SDK will spawn each block in separate threads (or fibers, depending on executor) and linearize their writes to the connection socket As a last step, the finalize callback is called with the view context and the response This is so that different frameworks can setup their responses correctly. By default, the built-in Rack finalzer just returns the resposne Array which can be used by any Rack handler. On Rails, the Rails controller response is set to this objects streaming response.
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/datastar/dispatcher.rb', line 243 def stream(streamer = nil, &block) streamer ||= block @streamers << streamer if @heartbeat && !@heartbeat_on @heartbeat_on = true @streamers << proc do |sse| while true sleep @heartbeat sse.check_connection! end end end body = if @streamers.size == 1 stream_one(streamer) else stream_many(streamer) end @response.body = body @finalize.call(@view_context, @response) end |