我正试图将Phoenix Channels用作一个非常简单的游戏服务器。对于原型,它的唯一目的是同步玩家的位置。然而,在这之前,每个客户都必须意识到所有其他客户的存在。
当一个新客户加入会议室时,我从RoomChannel
:向所有现有客户广播
@impl true
def join("room:main", _payload, socket) do
send(self(), :after_join)
{:ok, socket}
end
@impl true
def handle_info(:after_join, socket) do
broadcast_from!(socket, "user_join", %{user_id: socket.assigns.user_id})
{:noreply, socket}
end
这些现有客户端对消息作出反应,并生成一个新的玩家对象。然而,新用户不知道房间里还有谁和他们在一起,因为他们是最后一个加入的,没有收到任何此类信息。我正在努力纠正这一点。
我的计划是修改我的代码如下:
@impl true
def join("room:main", _payload, socket) do
Agent.update(active_users_agent, fn(list) -> [list | socket.assigns.user_id] end, 5000)
send(self(), :after_join)
{:ok, socket}
end
@impl true
def handle_info(:after_join, socket) do
push(socket, "room_data", Agent.get(active_users_agent, fn(list) -> list end))
broadcast_from!(socket, "user_join", %{user_id: socket.assigns.user_id})
{:noreply, socket}
end
换句话说,我想维护一个已加入用户的列表,并在加入时将其发送给新用户(并将他们添加到其中(。无论我使用的是Agent、GenServer还是其他什么都无关紧要。
问题是,我不知道在哪里可以初始化该Agent,因为我的RoomChannel
没有init()
回调;也不知道如何将其传递给CCD_ 4和CCD_。什么是有效的——或者更好的是,惯用的——方法来做到这一点?
p.S.值得注意的是,我希望将其存储在内存中,而不是数据库中。
您可能可以使用Phoenix.Presence
来处理所有这些头痛问题。
当用户加入websocket时,您可以将用户的状态数据存储在套接字连接本身中。
示例:
@impl true
def join("room:main", _payload, socket) do
user_info = %{
something1: "something1....",
something2: "something2....",
...
}
send(self(), :after_join)
{:ok, assign(socket, user_info: user_info)}
end
然后确保Phoenix.Presence
记录这些数据。你需要做一些类似的事情
示例:
@impl true
def handle_info(:after_join, socket) do
%{user_info: user_info} = socket.assigns
{:ok, _} = Presence.track(socket, "room:main", %{user_info: user_info})
push(socket, "presence_state", Presence.list(socket))
{:noreply, socket}
end
"presence_state"
频道将广播订阅该频道的用户列表。
但假设你想做一些更具体的事情,比如只显示频道中的人数。所以你可能也可以在handle_info(:after_join..
中做这样的事情
示例:
@impl true
def handle_info(:after_join, socket) do
%{user_info: user_info} = socket.assigns
{:ok, _} = Presence.track(socket, "room:main", %{user_info: user_info})
total_users =
Presence.list(socket)["room:main"].metas
|> Enum.count()
broadcast!(socket, "room:main:total_users", %{total_users: total_users})
push(socket, "presence_state", Presence.list(socket))
{:noreply, socket}
end
您需要确保您的客户端也在收听"room:main:total_users"
频道,以便获得广播的数据。
希望它能有所帮助。干杯