Documenting one way to “broadcast” a flash message to LiveViews (mostly for fun and learning) using a rather unorthodox method.
Let’s say with no special preparation in your LiveView code – no PubSub, no callback handlers, no intention to send arbitrary flash messages to arbitrary users – you’d like to connect to a running system (e.g. iex -S mix phx.server
or bin/myapp remote
) and push some message onto connected browsers!
iex> search = "MyAppWeb.SomeLiveViewModule.mount"
iex> Phoenix.LiveDashboard.SystemInfo.fetch_processes(node(), search, :reductions, :desc, 10)
|> elem(0)
|> Enum.map(fn process ->
process[:pid]
|> then(fn pid ->
:sys.replace_state(pid, fn state ->
Map.update!(state, :socket, fn socket ->
Phoenix.LiveView.put_flash(socket, :info, "Hello, #{socket.assigns.current_user.name}!")
end)
end) && send(pid, :ok) # Dummy message to trigger a call to `handle_changed/3` to flush new state to client
end)
end)
The main bits:
- There are many ways to introspect processes, including
Process.list/0
+Process.info/1
, but above I went to see how Phoenix LiveDashboard implements search on the Processes tab. Thus, we’re able to find LiveViews based on name. - We could further filter the results, for example using
:sys.get_state/1
to access the socket assigns and looking at the current logged in user to target our flash message to a specific user. Or pick a lucky LiveView process at random! :sys.replace_state/2
is used to update the state of the LiveView, using the fact that it is a GenServer.- So far the
socket
was updated, but nothing happened on the browser… we need somehow to help the LiveView process to realize state has changed and needs to be sent to the client.
There might be better ways to accomplish this, but, when the LiveView in question doesn’t implement its ownhandle_info
callback, sending an arbitrary message works:Phoenix.LiveView.Channel.handle_info
callsview_handle_info/2
which prints a warning, then eventuallyhandle_result/3
callshandle_changed/3
and a diff with the flash message is sent to the client.
Of course, all this was just an exercise to try and demonstrate some of the introspection capabilities we have at our disposal. You should be using PubSub
or other mechanisms to properly distribute messages / events.
I’m curious to learn though if my hacky steps could be improved, particularly the last bit on how to get the new state to be sent to the client. Looking forward to your comments!