diff --git a/lib/live_beats/application.ex b/lib/live_beats/application.ex index 823bf5f..e6ce972 100644 --- a/lib/live_beats/application.ex +++ b/lib/live_beats/application.ex @@ -20,9 +20,10 @@ defmodule LiveBeats.Application do #start presence LiveBeatsWeb.Presence, # Start the Endpoint (http/https) - LiveBeatsWeb.Endpoint + LiveBeatsWeb.Endpoint, # Start a worker by calling: LiveBeats.Worker.start_link(arg) # {LiveBeats.Worker, arg} + {Phoenix.Presence.Client, client: LiveBeats.PresenceClient, pubsub: LiveBeats.PubSub, presence: LiveBeats.Presence} ] # See https://hexdocs.pm/elixir/Supervisor.html diff --git a/lib/live_beats/presence/phoenix_presence_client.ex b/lib/live_beats/presence/phoenix_presence_client.ex new file mode 100644 index 0000000..b663840 --- /dev/null +++ b/lib/live_beats/presence/phoenix_presence_client.ex @@ -0,0 +1,85 @@ +defmodule Phoenix.Presence.Client do + use GenServer + + @doc """ + TODO + + ## Options + + * `:pubsub` - The required name of the pubsub server + * `:presence` - The required name of the presence module + * `:client` - The required callback module + """ + def start_link(opts) do + GenServer.start_link(__MODULE__, opts, name: PresenceClient) + end + + def track(topic, key, meta) do + GenServer.call(PresenceClient, {:track, self(), topic, key, meta}) + end + + def untrack(topic, key) do + GenServer.call(PresenceClient, {:untrack, self(), topic, key}) + end + + def init(opts) do + client = Keyword.fetch!(opts, :client) + client_state = client.init(%{}) + + state = %{ + topics: %{}, + client: client, + pubsub: Keyword.fetch!(opts, :pubsub), + presence_mod: Keyword.fetch!(opts, :presence), + client_state: client_state + } + + {:ok, state} + end + + def handle_info(%{topic: topic, event: "presence_diff", payload: diff}, state) do + {:noreply, merge_diff(state, topic, diff)} + end + + def handle_call({:track, pid, topic, key, meta}, _from, state) do + {:reply, :ok, track_pid(state, pid, topic, key, meta)} + end + + def handle_call({:untrack, pid, topic, key}, _from, state) do + {:reply, :ok, untrack_pid(state, pid, topic, key)} + end + + defp track_pid(state, pid, topic, key, meta) do + case Map.fetch(state.topics, topic) do + {:ok, presences} -> + state.presence_mod.track(pid, topic, key, meta) + # update topics state... + # new_state + state + + :error -> + # subscribe to topic we weren't yet tracking + Phoenix.PubSub.subscribe(state.pubsub, topic) + # new_state + state + end + end + + defp untrack_pid(state, pid, topic, key) do + state.presence_mod.untrack(pid, topic, key) + # remove presence from state.topics + # if no more presences for given topic, unsubscribe + # Phoenix.PubSub.unsubscribe(state.pubsub, topic) + # new_state + state + end + + defp merge_diff(state, topic, diff) do + # merge diff into state.topics + # invoke state.client.handle_join|handle_leave + # if no more presences for given topic, unsubscribe + # Phoenix.PubSub.unsubscribe(state.pubsub, topic) + # new_state + state + end +end diff --git a/lib/live_beats/presence/presence_client.ex b/lib/live_beats/presence/presence_client.ex new file mode 100644 index 0000000..0c5cefc --- /dev/null +++ b/lib/live_beats/presence/presence_client.ex @@ -0,0 +1,28 @@ +defmodule LiveBeats.PresenceClient do + @behaviour Phoenix.Presence.Client + + @presence LiveBeats.Presence + + def start_link(opts) do + Phoenix.Presence.Client.start_link(presence: @presence, client: __MODULE__) + end + + def list(topic) do + @presence.list(topic) + end + + def init(_opts) do + # user-land state + {:ok, %{}} + end + + def handle_join(key, presence, state) do + # can local pubsub to LVs about new join + {:ok, state} + end + + def handle_leave(key, presence, state) do + # can local pubsub to LVs about new leave + {:ok, state} + end +end diff --git a/lib/live_beats_web/live/profile_live.ex b/lib/live_beats_web/live/profile_live.ex index 8968407..c206b36 100644 --- a/lib/live_beats_web/live/profile_live.ex +++ b/lib/live_beats_web/live/profile_live.ex @@ -87,11 +87,9 @@ defmodule LiveBeatsWeb.ProfileLive do if connected?(socket) do MediaLibrary.subscribe_to_profile(profile) Accounts.subscribe(current_user.id) - LiveBeatsWeb.Presence.track( - self(), - topic(profile.user_id), + Phoenix.Presence.Client.track(topic(profile.user_id), current_user.id, - current_user + %{} ) end