【问题标题】:How do I use Phoenix Presence to track the existence of topics/subtopics?如何使用 Phoenix Presence 跟踪主题/子主题的存在?
【发布时间】:2017-10-06 15:40:36
【问题描述】:

我将子主题用作单用户频道,其他人可以使用该频道向特定的其他人发送消息。

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

这是来自我的user_channel.ex的sn-p:

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 phoenix-framework phoenix-channels


【解决方案1】:

感谢 elixir-lang slack 频道中的一些好人,我能够得出这个解决方案(可行):

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

【讨论】:

    猜你喜欢
    • 2018-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-15
    • 1970-01-01
    • 2019-04-24
    • 1970-01-01
    相关资源
    最近更新 更多