如何使用凤凰状态来跟踪主题/子主题的存在



我正在使用子主题作为单用户通道,其他人可以使用它向特定的其他人发送消息。

例如: - 我是用户 1,我想向用户 2 发送消息。 - 我发送了一条带有有效载荷{ to: 2, message: 'hi' }的消息,handle_in确实App.Endpoint.broadcast("user:2", "hi")

这是我user_channel.ex的片段:

def handle_in("chat", incoming_payload, socket) do
  from_uid = socket.assigns.uid
  uid = incoming_payload["to"]
  message = incoming_payload["message"]
  topic = "user:#{uid}"
  payload = %{uid: from_uid, message: message}
  # Send to the topic based of the incoming_payload's 
  # 'to' param.
  App.Endpoint.broadcast(topic, "chat", payload)
  {:reply, :ok, socket}
end

对于任何好奇的人:代码是开源的

https://github.com/NullVoxPopuli/mesh-relay-phoenix/tree/feature/presence-tracking

感谢 elixir-lang 松弛频道中的一些很棒的人,我能够得出这个解决方案(有效(:

defmodule MeshRelay.UserChannel do
  use Phoenix.Channel, :channel
  alias MeshRelay.Presence
  require Logger
  defp uids_present(to_uid, from_uid) do
    to_uid && from_uid
  end
  defp has_valid_payload(payload) do
    uid = payload["to"]
    message = payload["message"]
    uid && message
  end
  # uid is the member's channel that
  # he/she receives their messages on.
  # no messages not intended to be received by
  # this member should be sent on this channel / subtopic
  #
  # socket.assigns.uid is the uid from the connect
  def join("user:" <> uid, _params, socket) do
    has_uids = uids_present(uid, socket.assigns.uid)
    if has_uids do
      send(self(), :after_join)
      # Logger.debug Presence.list(socket)
      {:ok, socket}
    else
      # kick him out he is not allowed here
      {:error,
        %{reason: "in order to receive messages, you must join a channel using your own uid"},
        socket
      }
    end
  end
  def handle_in("chat", incoming_payload, socket) do
    if has_valid_payload(incoming_payload) do
      from_uid = socket.assigns.uid
      uid = incoming_payload["to"]
      message = incoming_payload["message"]
      topic = "user:#{uid}"
      payload = %{uid: from_uid, message: message}
      if is_member_online?(uid) do
        MeshRelay.Endpoint.broadcast(topic, "chat", payload)
        # broadcast! socket, "chat", payload
        {:reply, :ok, socket}
      else
        reply_with_error_message(socket, %{
          reason: "member not found",
          to_uid: uid,
          from_uid: from_uid
        })
      end
    else
      reply_with_error_message(socket, %{
        reason: "please format your message: { "to": "uidstring", "message": "encrypted message" }"
      })
    end
  end
  def reply_with_error_message(socket, error) do
    {:reply, {:error, error}, socket }
  end
  def handle_info(:after_join, socket) do
    Presence.track(socket.channel_pid, "connected_members", socket.assigns.uid, %{
      online_at: inspect(System.system_time(:milli_seconds))
    })
    {:noreply, socket}
  end
  def is_member_online?(uid) do
    Presence.list("connected_members")
    |> Map.keys
    |> Enum.any?(fn key -> key == uid end)
  end

end

相关内容

  • 没有找到相关文章

最新更新