1
0
mirror of https://github.com/danbee/chess synced 2025-03-04 08:39:06 +00:00
chess/lib/chess_web/channels/presence.ex
2023-02-04 21:35:56 -06:00

75 lines
2.7 KiB
Elixir

defmodule ChessWeb.Presence do
@moduledoc """
Provides presence tracking to channels and processes.
See the [`Phoenix.Presence`](http://hexdocs.pm/phoenix/Phoenix.Presence.html)
docs for more details.
## Usage
Presences can be tracked in your channel after joining:
defmodule Chess.MyChannel do
use ChessWeb, :channel
alias Chess.Presence
def join("some:topic", _params, socket) do
send(self, :after_join)
{:ok, assign(socket, :user_id, ...)}
end
def handle_info(:after_join, socket) do
push socket, "presence_state", Presence.list(socket)
{:ok, _} = Presence.track(socket, socket.assigns.user_id, %{
online_at: inspect(System.system_time(:second))
})
{:noreply, socket}
end
end
In the example above, `Presence.track` is used to register this
channel's process as a presence for the socket's user ID, with
a map of metadata. Next, the current presence list for
the socket's topic is pushed to the client as a `"presence_state"` event.
Finally, a diff of presence join and leave events will be sent to the
client as they happen in real-time with the "presence_diff" event.
See `Phoenix.Presence.list/2` for details on the presence datastructure.
## Fetching Presence Information
The `fetch/2` callback is triggered when using `list/1`
and serves as a mechanism to fetch presence information a single time,
before broadcasting the information to all channel subscribers.
This prevents N query problems and gives you a single place to group
isolated data fetching to extend presence metadata.
The function receives a topic and map of presences and must return a
map of data matching the Presence datastructure:
%{"123" => %{metas: [%{status: "away", phx_ref: ...}],
"456" => %{metas: [%{status: "online", phx_ref: ...}]}
The `:metas` key must be kept, but you can extend the map of information
to include any additional information. For example:
def fetch(_topic, entries) do
users = entries |> Map.keys() |> Accounts.get_users_map(entries)
# => %{"123" => %{name: "User 123"}, "456" => %{name: nil}}
for {key, %{metas: metas}} <- entries, into: %{} do
{key, %{metas: metas, user: users[key]}}
end
end
The function above fetches all users from the database who
have registered presences for the given topic. The fetched
information is then extended with a `:user` key of the user's
information, while maintaining the required `:metas` field from the
original presence data.
"""
use Phoenix.Presence,
otp_app: :chess,
pubsub_server: Chess.PubSub
end