Class: SseRailsEngine::Manager
- Inherits:
-
Object
- Object
- SseRailsEngine::Manager
- Defined in:
- lib/sse_rails_engine/manager.rb
Overview
This class provides the ability to track SSE connections and broadcast events to all connected clients from anywhere in your Rails app.
Example Usage:
class MyController < ActionController::Base
def do_stuff
SseRailsEngine.send_event('event name', 'any ruby object or string for data')
end
end
Note: SSEs are not currently supported by IE.
Constant Summary collapse
- RackHijackUnsupported =
Class.new RuntimeError
- SSE_HEADER =
["HTTP/1.1 200 OK\r\n", "Content-Type: text/event-stream\r\n", "Cache-Control: no-cache, no-store\r\n", "Connection: close\r\n", "\r\n"].join.freeze
Instance Attribute Summary collapse
-
#connections ⇒ Object
readonly
Returns the value of attribute connections.
-
#heartbeat_thread ⇒ Object
readonly
Returns the value of attribute heartbeat_thread.
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize ⇒ Manager
constructor
A new instance of Manager.
-
#open_connection(io) ⇒ Object
rubocop:enable Metrics/MethodLength.
- #register(env) ⇒ Object
-
#send_event(name, data) ⇒ Object
rubocop:disable Metrics/MethodLength.
Constructor Details
#initialize ⇒ Manager
Returns a new instance of Manager.
25 26 27 28 29 |
# File 'lib/sse_rails_engine/manager.rb', line 25 def initialize @mutex = Mutex.new @connections = {} start_heartbeats end |
Instance Attribute Details
#connections ⇒ Object (readonly)
Returns the value of attribute connections.
17 18 19 |
# File 'lib/sse_rails_engine/manager.rb', line 17 def connections @connections end |
#heartbeat_thread ⇒ Object (readonly)
Returns the value of attribute heartbeat_thread.
17 18 19 |
# File 'lib/sse_rails_engine/manager.rb', line 17 def heartbeat_thread @heartbeat_thread end |
Instance Method Details
#call(env) ⇒ Object
69 70 71 72 |
# File 'lib/sse_rails_engine/manager.rb', line 69 def call(env) SseRailsEngine.manager.register(env) [-1, {}, []] end |
#open_connection(io) ⇒ Object
rubocop:enable Metrics/MethodLength
61 62 63 64 65 66 67 |
# File 'lib/sse_rails_engine/manager.rb', line 61 def open_connection(io) Rails.logger.debug "New SSE Client connected: #{io}" io.write(SSE_HEADER) @mutex.synchronize do @connections[io] = ActionController::Live::SSE.new(io) end end |
#register(env) ⇒ Object
31 32 33 34 35 36 37 38 39 40 |
# File 'lib/sse_rails_engine/manager.rb', line 31 def register(env) if env['rack.hijack'] env['rack.hijack'].call socket = env['rack.hijack_io'] # Perform full hijack of socket (http://old.blog.phusion.nl/2013/01/23/the-new-rack-socket-hijacking-api/) SseRailsEngine.manager.open_connection(socket) else fail RackHijackUnsupported, 'This Rack server does not support hijacking, ensure you are using >= v1.5 of Rack' end end |
#send_event(name, data) ⇒ Object
rubocop:disable Metrics/MethodLength
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/sse_rails_engine/manager.rb', line 43 def send_event(name, data) @mutex.synchronize do @connections.dup.each do |stream, sse| begin sse.write(data, event: name) stream.flush rescue IOError, Errno::EPIPE, Errno::ETIMEDOUT Rails.logger.debug "SSE Client disconnected: #{stream}" close_connection(stream) rescue => ex Rails.logger.error "Failed to send event to SSE: #{stream} (#{name}, #{data} - #{ex.message} (#{ex.class}" close_connection(stream) end end end end |