跟踪UserSocket上的状态

时间:2018-01-29 21:15:29

标签: elixir phoenix-framework phoenix-channels

我正在尝试使用UserSocker跟踪Phoenix.Presence上用户的存在,而无需客户端出现在特定频道上。

稍后我想订阅用户的存在 在不同的渠道中了解用户的存在。

我的工作正常,但在用户断开连接时收到presence_diff。我正在做的是跟踪UserSocket对每个用户的不同主题的存在:

defmodule MyAppWeb.UserSocket do

  # ...

  def connect(%{"user_id" => user_id, "password" => password}, socket) do
    case Accounts.authenticate(user_id, password) do
      {:ok, user} ->
        track_user_presence(socket.transport_pid, user)
        {:ok, assign(socket, :user, user)}
      _error -> :error
    end
  end

  defp user_presence_topic(user_id) do
    "user_presence:#{user_id}"
  end

  defp track_user_presence(pid, user) do
    MyApp.Presence.track(pid, user_presence_topic(user.id), user.id, %{
      online_at: inspect(System.system_time(:seconds))
    })
  end
end

在我的频道中,我订阅了用户不同的在线主题:

defmodule MyAppWeb.RoomChannel do
  # ...

  def join("room:" <> room_id, payload, socket) do
    send(self(), :after_join)
    {:ok, assign(socket, :room_id, room_id)}
  end

  def handle_info(:after_join, socket) do
    user_ids = ~w(1 2)
    presence_state = get_and_subscribe_to_user_presence(socket, user_ids)
    push(socket, "presence_state", presence_state)
    {:noreply, socket}
  end

  def get_and_subscribe_to_user_presence(socket, user_ids) do
    user_ids
    |> Enum.map(&user_presence_topic/1)
    |> Enum.map(fn topic ->
      Phoenix.PubSub.subscribe(
        socket.pubsub_server,
        topic,
        fastlane: {socket.transport_pid, socket.serializer, []}
      )
      Presence.list(topic)
    end)
    |> Enum.reduce(%{}, fn map, acc -> Map.merge(acc, map) end)
  end

  defp user_presence_topic(user_id) do
    "user_presence:#{user_id}"
  end
end

我得出的结论是,我以某种方式需要监视套接字transport_pid并在套接字终止时自己发送存在差异。

另一个想法是将客户端加入UserSocket.connect/2函数的单独状态通道,但到目前为止我还没有找到如何归档的信息。

我将一个简单的凤凰应用程序与测试概述问题一起攻击:https://github.com/kbredemeier/socket_presence

对此有任何建议将不胜感激。

1 个答案:

答案 0 :(得分:0)

想出来。而不是使用PubSub.subscribe/3我最终使用 MyApp.Endpoint.subscribe/1包含我想订阅的主题,并在我的订阅频道上实施handle_info/2handle_info/2然后会从订阅频道收到广播,在我的情况下是presence_diff s。

克里斯麦考德松懈地向我指出,fastlane的{​​{1}}选项允许在广播时向订阅者发送与订阅者不同的进程。在我的情况下,这导致我的客户收到Phoenix.PubSub.subscribe/3而不是我期望的频道。