我需要当用户离开一个频道来执行一些动作(在他们自愿关闭的标签大多数情况下,但也可能是连接丢失/超时等)
根据像https://elixirforum.com/t/phoenix-presence-run-some-code-when-user-leaves-the-channel/17739和How to detect if a user left a Phoenix channel due to a network disconnect?职位,拦截从"presence_diff"
的Presence
事件似乎是要走一个万无一失的方法,因为它也应该覆盖了连接异常终止的情况。
奇怪的是,presence_diff
事件似乎当我通过Presence.track
跟踪用户只被触发,而不是当用户离开。
同时,在我的频道添加terminate(reason, socket)
回调正确捕获假事件。
我不知道什么可能是错误的,我的配置。还是我没有正确理解运用存在的?
示例代码:
def join("participant:" <> participant_id, _payload, socket) do
if socket.assigns.participant_id == participant_id do
send(self(), :after_participant_join)
{:ok, socket}
else
{:error, %{reason: "unauthorized"}}
end
end
def handle_info(:after_participant_join, socket) do
experiment_id = socket.assigns.experiment_id
Presence.track(socket, experiment_id, %{
# keys to track
})
# Broadcast something
# broadcast(socket, ...)
{:noreply, socket}
end
intercept(["presence_diff"])
def handle_out("presence_diff", payload, socket) do
# Only gets triggered at Presence.track, but not when the connection is closed.
IO.puts("presence_diff triggered, payload is #{inspect(payload)}")
leaves = payload.leaves
for {experiment_id, meta} <- leaves do
IO.puts("Leave information: #{meta}")
# Do stuffs
end
end
# This works, however.
def terminate(reason, socket) do
IO.puts("terminated. #{inspect(reason)}")
# Do stuffs.
end
好吧,我想我知道发生了什么事:每个"participant:" <> participant_id
话题是,正如其名,只能由一个参与者订阅。因此,当参与者退出,过程中也死了,没人能作用于presence_diff
消息。
仍然需要一个单独的过程。人们可以从过程调用MyApp.Endpoint.subscribe
订阅"participant:" <> participant_id
主题,并作用于presence_diff
消息。
或者,一个可以建立一个外部显示器。见How to detect if a user left a Phoenix channel due to a network disconnect?