In the docs there is this example but it only works for disconnects https://hexdocs.pm/phoenix/Phoenix.Socket.html#module-examples
use Phoenix.Socket
channel "room:*", MyAppWeb.RoomChannel
def connect(params, socket, _connect_info) do
{:ok, assign(socket, :user_id, params["user_id"])}
end
def id(socket), do: "users_socket:#{socket.assigns.user_id}"
end
# Disconnect all user's socket connections and their multiplexed channels
MyAppWeb.Endpoint.broadcast("users_socket:" <> user.id, "disconnect", %{})
I have tried that and it only works for disconnects.
I've read in places that you can create a topic specific for that user but I could use a practical example. I am having trouble grokking the complexity and could use a practical example.
Thank you.
I was thinking if you could get the underlying socket in the ets table you can just push/4
to that socket but I don't know how to do that.
You need to actually subscribe to a topic in order to receive the broadcast.
The "disconnect" message is special because it doesn't require subscription.
Inside the Phoenix.Socket
source code, there exists these three lines:
def __info__(%Broadcast{event: "disconnect"}, state) do
{:stop, {:shutdown, :disconnected}, state}
end
and they are the reason the socket state changes when the "disconnect" broadcast is received.
The "fallback" function looks like this:
def __info__(_, state) do
{:ok, state}
end
which means for any and all "other" topics, the socket state is unchanged.
You need to manually subscribe to "other" topics.
It should look something like this:
socket.endpoint.subscribe("some_topic:" <> socket.assigns.user_id)
Then you can broadcast messages like this:
MyAppWeb.Endpoint.broadcast("some_topic:" <> user.id, "some_event", %{foo: bar})
If you are doing this with LiveView then the easiest way to get started is to put this in your mount function:
if connected?(socket) do
socket.endpoint.subscribe("some_topic:" <> socket.assigns.user_id)
end
and to then have a handle_info
like this:
@impl true
def handle_info(%{event: "some_event"} = info, socket) do
IO.inspect info, label: "INFO"
{:noreply, socket}
end