Class: Admin::EventsController
- Inherits:
-
BaseController
- Object
- ActionController::Base
- BaseController
- Admin::EventsController
- Includes:
- ActionController::Live
- Defined in:
- lib/generators/open_loam/install/templates/admin/events_controller.rb
Overview
Server-Sent Events: a per-tenant push stream (OpenLoam::EventStream) so the admin updates live instead of polling. Authentication runs in the normal before_action chain (set_open_loam_context) BEFORE any stream write — so an unauthenticated request redirects to login the ordinary way, since no headers have been committed yet. Once the loop starts writing, the response is committed and there is no going back; that ordering is the whole safety of a Live action.
Constant Summary collapse
- HEARTBEAT_SECONDS =
20
Constants included from Pagination
Instance Method Summary collapse
Methods inherited from BaseController
Methods included from Pagination
Instance Method Details
#stream ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/generators/open_loam/install/templates/admin/events_controller.rb', line 16 def stream response.headers["Content-Type"] = "text/event-stream" response.headers["Cache-Control"] = "no-cache" handle = nil # so the ensure never raises NameError if subscribe below does queue = Queue.new # Subscribe as the FIRST thing in the begin whose ensure unsubscribes: a # leaked AS::Notifications subscriber would fire on every future event in # the process, holding this dead stream's queue forever. handle = OpenLoam::EventStream.broadcaster.subscribe(tenant: current_tenant, actor: current_actor) do |sse| queue << sse end loop do # A heartbeat comment both keeps the connection alive AND detects a dead # client: writing to a closed socket raises IOError → the loop exits → # ensure runs and the subscription is dropped. = queue.pop(timeout: HEARTBEAT_SECONDS) response.stream.write( || ": heartbeat\n\n") end rescue IOError, ActionController::Live::ClientDisconnected # The client went away — nothing to do but clean up in `ensure`. ensure OpenLoam::EventStream.broadcaster.unsubscribe(handle) response.stream.close OpenLoam::Current.reset end |