Hi,
I still working through this article and have now reached the phase, where I want to implement the immediate disconnecting of LiveViews on logout.
Sadly, I seem to misunderstand something or did something, so it doesn’t work. In the end, my problem is, that I think that the LiveViews are connected to a PubSub channel on mount. To do so I call in my mount function:
Jocasta.Endpoint.subscribe(@my_pubsub_topic)
I also added a plain handle_info function to my LiveViews, that should just dump out the message for me.
@impl true
def handle_info(msg, socket) do
IO.inspect(msg)
{:noreply, socket}
end
Then I broadcast a message somewhere else.
Jocasta.Endpoint.broadcast_from(
self(),
UserAuth.pubsub_topic(),
"logout_user",
%{
user: user
}
)
Somehow my message never ends up in my handle_info method or better said, this method is never called.
Being rather new to Phoenix, I have some stupid quesions.
- Can I find out which subscribers exist for a given topic?
- Is the assumption correct that subscribe and broadcast belong to the PubSub system?
- Do I totally misunderstand here something?
I thought I replicated everything the author does in his repo. Sadly, I seem to miss something and started to strip his example to the absolute basics of sending and receiving messages via PubSub.
Any help is appreciated.
Best regards
Oliver
Can I find out which subscribers exist for a given topic?
Registry.lookup(Jocasta.PubSub, topic)
the result can contain metadata passed to when calling subscribe (e.g. Phoenix.PubSub.subscribe(Jocasta.PubSub, topic, metadata: %{ip: ip})
)
Is the assumption correct that subscribe and broadcast belong to the PubSub system?
It belongs to pubsub_server configured here
config :fset, JocastaWeb.Endpoint,
...
pubsub_server: Jocasta.PubSub,
live_view: [signing_salt: "abc"]
And that PubSub is usually (or by default, not sure since which phoenix version) started in root supervision tree.
Do I totally misunderstand here something?
Not sure! If that broadcast_from
works, you would want to test it in a separate node to see if it actually works. Or use local_broadcast_from
.
1 Like
Thx @50kudos. This helped me a lot.
-
Registry.lookup/2
indeed showed me what I wanted to know.
- In another post I learned about
iex -S mix phx.server
. Before that, I started my commands manually in a different iex which is stupid, if you want to interact with another os process.
Now I can debug analyse my problem.
Because I didn’t knew about this. This is really helpful. Thanks for pointing this out to me.
1 Like
I have been following this same article and had some concerns about the proposed use of PubSub. The link posted above by @LostKobrakai is a much better approach.
I want to mention this:
I used phx_gen_auth
in my project and that generated this line in the log_in_user
function:
conn
# ...
|> put_session(:live_socket_id, "users_sessions:#{Base.url_encode64(token)}")
So for anyone else like me, you can keep this line and log users out like this:
@doc """
Logs a user out of any and all sessions
"""
def force_logout_user(%User{id: user_id} = user) do
user_tokens = UserToken
|> where(user_id: ^user_id)
|> Repo.all()
Repo.delete_all(UserToken.user_and_contexts_query(user, :all))
user_tokens
|> Enum.each(fn %UserToken{token: token} ->
MyAppWeb.Endpoint.broadcast(
"users_sessions:#{Base.url_encode64(token)}",
"disconnect",
%{}
)
end)
end
Just make sure you change mount
functions in any live views you have that might assume a current_user
on the assigns
.
2 Likes
Hey, thanks a bunch for posting your solution to this. I think I too am following the same article, popular one I guess haha. I am wondering if your approach will trigger the page to “re-render” or the mount function to run again.
From what I was reading it should. However, when I call the force_logout_user function from an iex -S mix
session the page in my browser does not automatically refresh and the mount function does not trigger like I expect it to. I do not see any errors in the output from the Phoenix Server. Any insight would be appreciated. Thanks 
When I call force_logout_user
the logged in user’s browser navigates to the login page.
Are you definitely putting the live socket ID on the sesssion? I have something like this in my log_in
function:
|> put_session(:live_socket_id, "users_sessions:#{Base.url_encode64(token)}")
and that token
is stored in the database.
Take a look at the Network tab in your devtools to investigate the problem.