Implement handle_leave and handle_join in presence_client

- The profile Liveview is subscribed to active_users topic
- user_joined and user_left events are sent
- Users are added and removed from presences assign
This commit is contained in:
Berenice Medel 2021-12-09 01:29:00 -06:00 committed by Chris McCord
parent 4634d32295
commit 463faafe71
4 changed files with 61 additions and 18 deletions

View file

@ -21,6 +21,10 @@ defmodule LiveBeats.Accounts do
Repo.all(from u in User, limit: ^Keyword.fetch!(opts, :limit)) Repo.all(from u in User, limit: ^Keyword.fetch!(opts, :limit))
end end
def list_users_by_ids(user_ids) when is_list(user_ids) do
Repo.all(from u in User, where: u.id in ^user_ids)
end
def lists_users_by_active_profile(id, opts) do def lists_users_by_active_profile(id, opts) do
Repo.all( Repo.all(
from u in User, where: u.active_profile_user_id == ^id, limit: ^Keyword.fetch!(opts, :limit) from u in User, where: u.active_profile_user_id == ^id, limit: ^Keyword.fetch!(opts, :limit)

View file

@ -1,7 +1,8 @@
defmodule LiveBeats.PresenceClient do defmodule LiveBeats.PresenceClient do
@behaviour Phoenix.Presence.Client @behaviour Phoenix.Presence.Client
@presence LiveBeats.Presence @presence LiveBeatsWeb.Presence
@pubsub LiveBeats.PubSub
def start_link(opts) do def start_link(opts) do
Phoenix.Presence.Client.start_link(presence: @presence, client: __MODULE__) Phoenix.Presence.Client.start_link(presence: @presence, client: __MODULE__)
@ -16,13 +17,33 @@ defmodule LiveBeats.PresenceClient do
{:ok, %{}} {:ok, %{}}
end end
def handle_join(key, presence, state) do def handle_join(topic, key, meta, state) do
# can local pubsub to LVs about new join active_users_topic =
topic
|> profile_identifier()
|> active_users_topic()
Phoenix.PubSub.broadcast!(@pubsub, active_users_topic, {__MODULE__, %{user_joined: key}})
{:ok, state} {:ok, state}
end end
def handle_leave(key, presence, state) do def handle_leave(topic, key, presence, state) do
# can local pubsub to LVs about new leave active_users_topic =
topic
|> profile_identifier()
|> active_users_topic()
Phoenix.PubSub.broadcast!(@pubsub, active_users_topic, {__MODULE__, %{user_left: key}})
{:ok, state} {:ok, state}
end end
defp active_users_topic(user_id) do
"active_users:#{user_id}"
end
defp profile_identifier(topic) do
"active_profile:" <> identifier = topic
identifier
end
end end

View file

@ -10,6 +10,7 @@ defmodule LiveBeatsWeb.Presence do
import Phoenix.LiveView.Helpers import Phoenix.LiveView.Helpers
import LiveBeatsWeb.LiveHelpers import LiveBeatsWeb.LiveHelpers
@pubsub LiveBeats.PubSub
def listening_now(assigns) do def listening_now(assigns) do
~H""" ~H"""
@ -31,4 +32,12 @@ defmodule LiveBeatsWeb.Presence do
</div> </div>
""" """
end end
def subscribe(user_id) do
Phoenix.PubSub.subscribe(@pubsub, topic(user_id))
end
defp topic(profile) do
"active_users:#{profile.user_id}"
end
end end

View file

@ -87,6 +87,7 @@ defmodule LiveBeatsWeb.ProfileLive do
if connected?(socket) do if connected?(socket) do
MediaLibrary.subscribe_to_profile(profile) MediaLibrary.subscribe_to_profile(profile)
Accounts.subscribe(current_user.id) Accounts.subscribe(current_user.id)
LiveBeatsWeb.Presence.subscribe(profile)
Phoenix.Presence.Client.track(topic(profile.user_id), Phoenix.Presence.Client.track(topic(profile.user_id),
current_user.id, current_user.id,
%{} %{}
@ -146,6 +147,22 @@ defmodule LiveBeatsWeb.ProfileLive do
{:noreply, socket} {:noreply, socket}
end end
def handle_info({LiveBeats.PresenceClient, %{user_joined: user_id}}, socket) do
new_user = Accounts.get_user!(user_id)
updated_presences =
if new_user in socket.assigns.presences do
socket.assigns.presences
else
[new_user | socket.assigns.presences]
end
{:noreply, assign(socket, :presences, updated_presences)}
end
def handle_info({LiveBeats.PresenceClient, %{user_left: user_id}}, socket) do
updated_presences = socket.assign.presences |> Enum.reject(fn user -> user.id == user_id end)
{:noreply, assign(socket, :presences, updated_presences)}
end
def handle_info({Accounts, %Accounts.Events.ActiveProfileChanged{} = event}, socket) do def handle_info({Accounts, %Accounts.Events.ActiveProfileChanged{} = event}, socket) do
{:noreply, assign(socket, active_profile_id: event.new_profile_user_id)} {:noreply, assign(socket, active_profile_id: event.new_profile_user_id)}
end end
@ -173,14 +190,6 @@ defmodule LiveBeatsWeb.ProfileLive do
def handle_info({Accounts, _}, socket), do: {:noreply, socket} def handle_info({Accounts, _}, socket), do: {:noreply, socket}
def handle_info(
%{event: "presence_diff", payload: %{joins: _joins, leaves: _leaves}},
%{assigns: %{presences: _users}} = socket
) do
{:noreply, assign_presences(socket)}
end
defp stop_song(socket, song_id) do defp stop_song(socket, song_id) do
SongRowComponent.send_status(song_id, :stopped) SongRowComponent.send_status(song_id, :stopped)
@ -256,11 +265,11 @@ defmodule LiveBeatsWeb.ProfileLive do
defp assign_presences(socket) do defp assign_presences(socket) do
presences = socket.assigns.profile.user_id presences = socket.assigns.profile.user_id
|> topic() |> topic()
|> Presence.list() |> LiveBeats.PresenceClient.list()
|> Enum.map(fn {_user_id, user_data} -> |> Enum.map(fn {user_id, _user_data} ->
user_data[:metas] user_id
|> List.first()
end) end)
|> Accounts.list_users_by_ids()
assign(socket, presences: presences) assign(socket, presences: presences)
end end
@ -272,5 +281,5 @@ defmodule LiveBeatsWeb.ProfileLive do
uri.host <> uri.path uri.host <> uri.path
end end
defp topic(user_id) when is_integer(user_id), do: "profile:#{user_id}" defp topic(user_id) when is_integer(user_id), do: "active_profile:#{user_id}"
end end