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'- SSE_ACCEPT_EXP =
/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.
-
#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.
-
#patch_elements(elements, options = BLANK_OPTIONS) ⇒ Object
Send one-off elements to the UI See data-star.dev/reference/sse_events#datastar-patch-elements.
-
#patch_signals(signals, options = BLANK_OPTIONS) ⇒ Object
One-off patch signals in the UI See data-star.dev/reference/sse_events#datastar-patch-signals.
-
#redirect(url) ⇒ Object
Send an execute_script event to change window.location.
-
#remove_elements(selector, options = BLANK_OPTIONS) ⇒ Object
One-off remove elements from the UI Sugar on top of patch-elements with mode: ‘remove’ See data-star.dev/reference/sse_events#datastar-patch-elements.
-
#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.
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 71 |
# File 'lib/datastar/dispatcher.rb', line 40 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.
31 32 33 |
# File 'lib/datastar/dispatcher.rb', line 31 def request @request end |
#response ⇒ Object (readonly)
Returns the value of attribute response.
31 32 33 |
# File 'lib/datastar/dispatcher.rb', line 31 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
190 191 192 193 194 |
# File 'lib/datastar/dispatcher.rb', line 190 def execute_script(script, = BLANK_OPTIONS) stream_no_heartbeat do |sse| sse.execute_script(script, ) end end |
#on_client_disconnect(callable = nil, &block) ⇒ self
Register a callback for client disconnection Ex. when the browser is closed mid-stream
93 94 95 96 |
# File 'lib/datastar/dispatcher.rb', line 93 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
84 85 86 87 |
# File 'lib/datastar/dispatcher.rb', line 84 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
111 112 113 114 |
# File 'lib/datastar/dispatcher.rb', line 111 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
102 103 104 105 |
# File 'lib/datastar/dispatcher.rb', line 102 def on_server_disconnect(callable = nil, &block) @on_server_disconnect << (callable || block) self end |
#patch_elements(elements, options = BLANK_OPTIONS) ⇒ Object
Send one-off elements to the UI See data-star.dev/reference/sse_events#datastar-patch-elements
133 134 135 136 137 |
# File 'lib/datastar/dispatcher.rb', line 133 def patch_elements(elements, = BLANK_OPTIONS) stream_no_heartbeat do |sse| sse.patch_elements(elements, ) end end |
#patch_signals(signals, options = BLANK_OPTIONS) ⇒ Object
One-off patch signals in the UI See data-star.dev/reference/sse_events#datastar-patch-signals
162 163 164 165 166 |
# File 'lib/datastar/dispatcher.rb', line 162 def patch_signals(signals, = BLANK_OPTIONS) stream_no_heartbeat do |sse| sse.patch_signals(signals, ) end end |
#redirect(url) ⇒ Object
Send an execute_script event to change window.location
200 201 202 203 204 |
# File 'lib/datastar/dispatcher.rb', line 200 def redirect(url) stream_no_heartbeat do |sse| sse.redirect(url) end end |
#remove_elements(selector, options = BLANK_OPTIONS) ⇒ Object
One-off remove elements from the UI Sugar on top of patch-elements with mode: ‘remove’ See data-star.dev/reference/sse_events#datastar-patch-elements
148 149 150 151 152 |
# File 'lib/datastar/dispatcher.rb', line 148 def remove_elements(selector, = BLANK_OPTIONS) stream_no_heartbeat do |sse| sse.remove_elements(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
176 177 178 179 180 |
# File 'lib/datastar/dispatcher.rb', line 176 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
119 120 121 |
# File 'lib/datastar/dispatcher.rb', line 119 def signals @signals ||= parse_signals(request).freeze end |
#sse? ⇒ Boolean
Check if the request accepts SSE responses
75 76 77 |
# File 'lib/datastar/dispatcher.rb', line 75 def sse? !!(@request.get_header(HTTP_ACCEPT).to_s =~ SSE_ACCEPT_EXP) 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.
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/datastar/dispatcher.rb', line 245 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 |