From 0ec176e4120ce33971faea07d3c41094a8c20c13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lui=CC=81s=20Arteiro?= Date: Mon, 13 Feb 2023 12:52:43 +0000 Subject: [PATCH] feat: Adding basic Presence for list of logged in users. #14 --- assets/js/app.js | 9 +++++++ lib/chat/application.ex | 1 + lib/chat_web/channels/room_channel.ex | 38 +++++++++++++++++++++++---- lib/chat_web/presence.ex | 5 ++++ 4 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 lib/chat_web/presence.ex diff --git a/assets/js/app.js b/assets/js/app.js index 8e96f7a..ebb41cb 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -54,6 +54,15 @@ channel.on('shout', function (payload) { render_message(payload) }); +// Listening to presence events +channel.on('presence_diff', function (payload) { + console.log(payload) +}); + +channel.on('presence_state', function (payload) { + console.log(payload) +}); + // Send the message to the server on "shout" channel function sendMessage() { diff --git a/lib/chat/application.ex b/lib/chat/application.ex index 4a96a44..1923c94 100644 --- a/lib/chat/application.ex +++ b/lib/chat/application.ex @@ -14,6 +14,7 @@ defmodule Chat.Application do Chat.Repo, # Start the PubSub system {Phoenix.PubSub, name: Chat.PubSub}, + ChatWeb.Presence, # Start the Endpoint (http/https) ChatWeb.Endpoint # Start a worker by calling: Chat.Worker.start_link(arg) diff --git a/lib/chat_web/channels/room_channel.ex b/lib/chat_web/channels/room_channel.ex index daf6a81..6c10c85 100644 --- a/lib/chat_web/channels/room_channel.ex +++ b/lib/chat_web/channels/room_channel.ex @@ -1,5 +1,6 @@ defmodule ChatWeb.RoomChannel do use ChatWeb, :channel + alias ChatWeb.Presence @impl true def join("room:lobby", payload, socket) do @@ -22,16 +23,23 @@ defmodule ChatWeb.RoomChannel do # broadcast to everyone in the current topic (room:lobby). @impl true def handle_in("shout", payload, socket) do - Chat.Message.changeset(%Chat.Message{}, payload) |> Chat.Repo.insert() - broadcast(socket, "shout", payload) + # Insert message in database + {:ok, msg} = Chat.Message.changeset(%Chat.Message{}, payload) |> Chat.Repo.insert() + + # Assigning username to socket assigns and tracking presence + socket + |> assign(:user_name, msg.name) + |> track_presence() + |> broadcast("shout", Map.put_new(payload, :id, msg.id)) + {:noreply, socket} end @impl true def handle_info(:after_join, socket) do + # Get messages and list them Chat.Message.get_messages() - # revers to display the latest message at the bottom of the page - |> Enum.reverse() + |> Enum.reverse() # reverts the enum to display the latest message at the bottom of the page |> Enum.each(fn msg -> push(socket, "shout", %{ name: msg.name, @@ -40,7 +48,9 @@ defmodule ChatWeb.RoomChannel do }) end) - # :noreply + # Send currently online users in lobby + push(socket, "presence_state", Presence.list("room:lobby")) + {:noreply, socket} end @@ -48,4 +58,22 @@ defmodule ChatWeb.RoomChannel do defp authorized?(_payload) do true end + + + # Add a track in Presence when user joins the channel + # Ideally this should be on joining "room:lobby" but the socket has no info as of now + # to associate with a user. + + defp track_presence(socket) do + case do_track(socket) do + {:ok, _ref} -> socket + {:error, {:already_tracked, _pid, _channel, _user}} -> socket + end + end + + defp do_track(%{assigns: %{user_name: user_name}} = socket) when not is_nil(user_name) do + Presence.track(socket, user_name, %{ + online_at: inspect(System.system_time(:second)) + }) + end end diff --git a/lib/chat_web/presence.ex b/lib/chat_web/presence.ex new file mode 100644 index 0000000..262fa91 --- /dev/null +++ b/lib/chat_web/presence.ex @@ -0,0 +1,5 @@ +defmodule ChatWeb.Presence do + use Phoenix.Presence, + otp_app: :chat, + pubsub_server: Chat.PubSub +end