Module: OpenLoam::EventStream

Defined in:
lib/open_loam/event_stream.rb

Overview

The real-time bridge: pushes selected OpenLoam events to a browser over Server-Sent Events, so the admin updates live instead of polling.

SECURITY POSTURE — default OFF. An event reaches a browser only if ALL hold:

* its name matches a declared OpenLoam.broadcast_events pattern (opt-in), AND
* its tenant matches the connected tenant (isolation), AND
* its audience includes the connected actor (a payload `user_id`, if any,
is the sole recipient; no `user_id` means tenant-wide).

FAN-OUT is behind a swappable broadcaster seam (OpenLoam::EventStream.broadcaster). The default in-process broadcaster only sees events published in THIS process — fine for the single-process prototype; a multi-process deploy swaps in a Redis/SolidCable-backed broadcaster with no controller change (see docs/_foundation/overview.md).

Defined Under Namespace

Classes: InProcessBroadcaster

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.broadcaster ⇒ Object



20
21
22
# File 'lib/open_loam/event_stream.rb', line 20

def broadcaster
  @broadcaster ||= InProcessBroadcaster.new
end

Class Method Details

.broadcastable?(event_name) ⇒ Boolean

Is this event name allowed to reach browsers at all? Empty allow-list → false, always (nothing leaks by default).

Returns:

  • (Boolean)


26
27
28
29
30
31
32
# File 'lib/open_loam/event_stream.rb', line 26

def broadcastable?(event_name)
  OpenLoam.broadcast_events.any? do |pattern|
    next false if OpenLoam::Overrides.disabled?(:broadcast_events, pattern) # an app can turn a default pattern off

    OpenLoam::Events.pattern_matches?(pattern, event_name)
  end
end

.deliverable?(event_name, payload, tenant:, actor:) ⇒ Boolean

Should a broadcastable event reach a stream connected as (tenant, actor)?

Returns:

  • (Boolean)


35
36
37
38
39
40
41
42
43
# File 'lib/open_loam/event_stream.rb', line 35

def deliverable?(event_name, payload, tenant:, actor:)
  return false unless broadcastable?(event_name)

  payload = payload.symbolize_keys
  return false unless payload[:tenant_id] == tenant&.id

  recipient = payload[:user_id]
  recipient.nil? || recipient == actor&.id
end

.frame(event_name, payload) ⇒ Object

One SSE message: an event: line (the OpenLoam event name) and a data: line (JSON), ended by a blank line. Only small id-ish keys ride along — OpenLoam events carry no attribute values, and this slices to a safe set as belt-and-suspenders (tenant_id is dropped; it is implied by the connection).



49
50
51
# File 'lib/open_loam/event_stream.rb', line 49

def frame(event_name, payload)
  "event: #{event_name}\ndata: #{safe_payload(payload).to_json}\n\n"
end