Class: Supabase::Realtime::Presence
- Inherits:
-
Object
- Object
- Supabase::Realtime::Presence
- Defined in:
- lib/supabase/realtime/presence.rb
Overview
Tracks presence state for one channel and implements the Phoenix Presence sync algorithm. Mirrors supabase-py’s AsyncRealtimePresence: raw ‘{ key => { “metas” => [{ “phx_ref” => …, … }] } }` wire payloads are transformed to a flat `{ key => [{ “presence_ref” => …, … }, …] }` shape before being stored or emitted, so listener callbacks receive `(key, current_presences, new_presences)` with `presence_ref` keys.
Instance Attribute Summary collapse
-
#state ⇒ Object
readonly
Returns the value of attribute state.
Class Method Summary collapse
- .transform_meta(meta) ⇒ Object
-
.transform_state(state) ⇒ Object
Convert raw Phoenix wire format ‘{ key => { “metas” => […] } }` to flat `{ key => […, …] }`.
Instance Method Summary collapse
- #any_callbacks? ⇒ Boolean
-
#initialize ⇒ Presence
constructor
A new instance of Presence.
-
#list ⇒ Object
Flat list of every presence currently tracked.
- #on_join(&block) ⇒ Object
- #on_leave(&block) ⇒ Object
- #on_sync(&block) ⇒ Object
-
#sync_diff(raw_diff) ⇒ Object
Subsequent presence_diff messages: apply joins/leaves to the local state.
-
#sync_state(raw_state) ⇒ Object
First snapshot after joining: diff against the (possibly empty) local state and apply the joins/leaves through the same code path as ‘sync_diff`.
Constructor Details
#initialize ⇒ Presence
Returns a new instance of Presence.
14 15 16 17 18 19 |
# File 'lib/supabase/realtime/presence.rb', line 14 def initialize @state = {} @on_sync_callbacks = [] @on_join_callbacks = [] @on_leave_callbacks = [] end |
Instance Attribute Details
#state ⇒ Object (readonly)
Returns the value of attribute state.
12 13 14 |
# File 'lib/supabase/realtime/presence.rb', line 12 def state @state end |
Class Method Details
.transform_meta(meta) ⇒ Object
98 99 100 101 102 103 104 105 106 107 |
# File 'lib/supabase/realtime/presence.rb', line 98 def self.() = .dup .delete("phx_ref_prev") if .key?("phx_ref") ref = .delete("phx_ref") { "presence_ref" => ref }.merge() else end end |
.transform_state(state) ⇒ Object
Convert raw Phoenix wire format ‘{ key => { “metas” => […] } }` to flat `{ key => […, …] }`. Idempotent on already transformed input.
86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/supabase/realtime/presence.rb', line 86 def self.transform_state(state) new_state = {} (state || {}).each do |key, presences| new_state[key] = if presences.is_a?(Hash) && presences.key?("metas") presences["metas"].map { || () } else Array(presences).map { || () } end end new_state end |
Instance Method Details
#any_callbacks? ⇒ Boolean
79 80 81 |
# File 'lib/supabase/realtime/presence.rb', line 79 def any_callbacks? [@on_sync_callbacks, @on_join_callbacks, @on_leave_callbacks].any? { |list| !list.empty? } end |
#list ⇒ Object
Flat list of every presence currently tracked.
60 61 62 |
# File 'lib/supabase/realtime/presence.rb', line 60 def list @state.values.flatten end |
#on_join(&block) ⇒ Object
69 70 71 72 |
# File 'lib/supabase/realtime/presence.rb', line 69 def on_join(&block) @on_join_callbacks << block self end |
#on_leave(&block) ⇒ Object
74 75 76 77 |
# File 'lib/supabase/realtime/presence.rb', line 74 def on_leave(&block) @on_leave_callbacks << block self end |
#on_sync(&block) ⇒ Object
64 65 66 67 |
# File 'lib/supabase/realtime/presence.rb', line 64 def on_sync(&block) @on_sync_callbacks << block self end |
#sync_diff(raw_diff) ⇒ Object
Subsequent presence_diff messages: apply joins/leaves to the local state. Raw input is transformed before being applied.
51 52 53 54 55 56 57 |
# File 'lib/supabase/realtime/presence.rb', line 51 def sync_diff(raw_diff) joins = self.class.transform_state(raw_diff["joins"] || {}) leaves = self.class.transform_state(raw_diff["leaves"] || {}) sync_diff_internal(joins, leaves) @on_sync_callbacks.each(&:call) @state end |
#sync_state(raw_state) ⇒ Object
First snapshot after joining: diff against the (possibly empty) local state and apply the joins/leaves through the same code path as ‘sync_diff`.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/supabase/realtime/presence.rb', line 24 def sync_state(raw_state) new_state = self.class.transform_state(raw_state) joins = {} leaves = @state.reject { |k, _| new_state.key?(k) } new_state.each do |key, presences| current = @state[key] || [] if current.any? current_refs = current.map { |p| p["presence_ref"] } new_refs = presences.map { |p| p["presence_ref"] } joined_presences = presences.reject { |p| current_refs.include?(p["presence_ref"]) } left_presences = current.reject { |p| new_refs.include?(p["presence_ref"]) } joins[key] = joined_presences if joined_presences.any? leaves[key] = left_presences if left_presences.any? else joins[key] = presences end end sync_diff_internal(joins, leaves) @on_sync_callbacks.each(&:call) @state end |