0

我的 Phoenix 1.5.8 LiveView 应用程序使用phx_gen_auth进行用户身份验证。

  • 我将当前登录的用户分配给@current_user.
  • 我将当前访问者的数量(无论是否登录)分配给 @current_visitors_count.

现在我想用来@current_users_count显示以用户身份登录的访问者数量。但我不知道如何在handle_info. 计算两个数字的最佳方法是什么?

lib/example_web/live/page_live.ex

defmodule ExampleWeb.PageLive do
  use ExampleWeb, :live_view

  @impl true
  def mount(_params, session, socket) do
    socket =
      socket
      |> assign_current_user(session)
      |> assign_current_visitors_count()

    {:ok, socket}
  end

  @impl true
  def handle_info(
        %{event: "presence_diff", payload: %{joins: joins, leaves: leaves}},
        %{assigns: %{current_visitors_count: count}} = socket
      ) do
    current_visitors_count = count + map_size(joins) - map_size(leaves)

    {:noreply, assign(socket, :current_visitors_count, current_visitors_count)}
  end
end

lib/example_web/live/live_helpers.ex

defmodule ExampleWeb.LiveHelpers do
  import Phoenix.LiveView

  alias Example.Accounts
  alias Example.Presence

  def assign_current_user(socket, session) do
    assign_new(
      socket,
      :current_user,
      fn ->
        case session["user_token"] do
          nil -> nil
          user_token -> Accounts.get_user_by_session_token(user_token)
        end
      end
    )
  end

  def assign_current_visitors_count(socket) do
    topic = "current_visitors"
    initial_count = Presence.list(topic) |> map_size

    ExampleWeb.Endpoint.subscribe(topic)

    Presence.track(
      self(),
      topic,
      socket.id,
      %{}
    )

    assign(socket, :current_visitors_count, initial_count)
  end
end
4

1 回答 1

0

lib/example_web/live/page_live.ex

defmodule ExampleWeb.PageLive do
  use ExampleWeb, :live_view

  alias Example.Presence
  alias Example.Accounts
  alias Phoenix.Socket.Broadcast

  @impl true
  def mount(_params, session, socket) do
    current_user = get_current_user(session)

    [chat_user_id, user_status] =
      case current_user do
        nil -> [UUID.uuid4(), "guest"]
        user -> [user.id, "user"]
      end

    Phoenix.PubSub.subscribe(Example.PubSub, "room:lobby")
    {:ok, _} = Presence.track(self(), "room:lobby", chat_user_id, %{status: user_status})

    socket =
      socket
      |> assign_user_count()
      |> assign(:current_user, current_user)
      |> assign(:chat_user_id, chat_user_id)
      |> assign(:current_users_count, 0)
      |> assign(:guests_count, 0)

    {:ok, socket}
  end

  @impl true
  def handle_info(%Broadcast{event: "presence_diff"}, socket) do
    socket =
      socket
      |> assign(:current_users_count, length(current_user_ids(socket)))
      |> assign(:guests_count, length(current_guests_ids(socket)))

    {:noreply, socket}
  end

  defp current_user_ids(socket) do
    Presence.list("room:lobby")
    |> Enum.filter(fn {id, x} -> hd(x.metas).status == "user" end)
    |> Enum.map(fn {k, _} -> k end)
  end

  defp current_guests_ids(socket) do
    Presence.list("room:lobby")
    |> Enum.filter(fn {id, x} -> hd(x.metas).status == "guest" end)
    |> Enum.map(fn {k, _} -> k end)
  end
end

lib/example_web/live/live_helpers.ex

defmodule ExampleWeb.LiveHelpers do
  import Phoenix.LiveView

  alias Example.Accounts
  alias Example.Repo
  alias Example.Presence
  import Ecto.Query, only: [from: 2]

  def get_current_user(session) do
    case session["user_token"] do
      nil -> nil
      user_token -> Accounts.get_user_by_session_token(user_token)
    end
  end

end
于 2021-03-08T15:11:31.327 回答