Skip to content

Commit

Permalink
Part 4: Make it real-time with Phoenix.PubSub
Browse files Browse the repository at this point in the history
  • Loading branch information
hubertlepicki committed Sep 27, 2020
1 parent e450d12 commit 4aad6db
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 16 deletions.
2 changes: 0 additions & 2 deletions lib/backdoor/helpers/live_helpers.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
defmodule Backdoor.LiveHelpers do
@moduledoc false

import Phoenix.LiveView.Helpers
end
66 changes: 54 additions & 12 deletions lib/backdoor/live/backdoor_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@ defmodule Backdoor.BackdoorLive do

use Backdoor.Web, :live_view

@topic_name "backdoor_events"

@impl true
def mount(_params, _session, socket) do
Phoenix.PubSub.subscribe(find_pubsub_server(socket.endpoint), @topic_name)

{:ok,
socket
|> assign(current_session_id: nil, session_ids: Backdoor.Session.session_ids(), logs: [])}
|> assign(
input_value: "",
current_session_id: nil,
session_ids: Backdoor.Session.session_ids(),
logs: []
)}
end

@impl true
Expand Down Expand Up @@ -51,8 +60,8 @@ defmodule Backdoor.BackdoorLive do
<span class="text-xl text-grey border-r-0 border-grey p-2 px-0">
backdoor&gt;
</span>
<%= form_tag "#", [phx_submit: :execute, class: "flex w-full"] %>
<%= text_input :command, :text, [placeholer: "Write Elixir code to execute and hit 'Enter'...", value: "", class: "w-full px-1 outline-none"] %>
<%= form_tag "#", [phx_change: :set_input_value, phx_submit: :execute, class: "flex w-full"] %>
<%= text_input :command, :text, [placeholer: "Write Elixir code to execute and hit 'Enter'...", value: @input_value, class: "w-full px-1 outline-none"] %>
</form>
</div>
</div>
Expand All @@ -63,19 +72,40 @@ defmodule Backdoor.BackdoorLive do
end

@impl true
def handle_event("execute", %{"command" => %{"text" => command}}, socket) do
logs = Backdoor.Session.execute(socket.assigns.current_session_id, command)

def handle_info({:put_log, session_id, log}, %{assigns: %{current_session_id: sid}} = socket)
when session_id == sid do
{:noreply,
socket
|> push_event("command", %{text: ""})
|> assign(logs: socket.assigns.logs ++ logs)}
|> assign(logs: socket.assigns.logs ++ [log])}
end

def handle_info({:put_log, _session_id, _log}, socket) do
{:noreply, socket}
end

def handle_info({:session_ids, session_ids}, socket) do
if Enum.member?(session_ids, socket.assigns.current_session_id) do
{:noreply, socket |> assign(session_ids: session_ids)}
else
{:noreply, socket |> assign(session_ids: session_ids, current_session_id: nil)}
end
end

@impl true
def handle_event("set_input_value", %{"command" => %{"text" => command}}, socket) do
{:noreply, socket |> assign(:input_value, command)}
end

def handle_event("execute", %{"command" => %{"text" => command}}, socket) do
Backdoor.Session.execute(socket.assigns.current_session_id, command)

{:noreply, socket |> assign(:input_value, "")}
end

def handle_event("start_session", %{}, socket) do
{:ok, session_id} = Backdoor.Session.start_session()
{:ok, _session_id} = Backdoor.Session.start_session()

{:noreply, socket |> assign(session_ids: Backdoor.Session.session_ids())}
{:noreply, socket}
end

def handle_event("stop_session", %{"session-id" => sid}, socket) do
Expand All @@ -85,9 +115,9 @@ defmodule Backdoor.BackdoorLive do
if socket.assigns.current_session_id == session_id do
{:noreply,
socket
|> assign(current_session_id: nil, logs: [], session_ids: Backdoor.Session.session_ids())}
|> assign(current_session_id: nil, logs: [])}
else
{:noreply, socket |> assign(session_ids: Backdoor.Session.session_ids())}
{:noreply, socket}
end
end

Expand All @@ -109,4 +139,16 @@ defmodule Backdoor.BackdoorLive do
defp format({:result, value}) do
inspect(value)
end

defp find_pubsub_server(endpoint) do
case Application.get_env(:backdoor, :pubsub_server) do
nil ->
server = endpoint.config(:pubsub_server) || endpoint.__pubsub_server__()
Application.put_env(:backdoor, :pubsub_server, server)
server

server ->
server
end
end
end
2 changes: 1 addition & 1 deletion lib/backdoor/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ defmodule Backdoor.Router do
end

@doc false
def __session__(conn) do
def __session__(_conn) do
%{}
end
end
17 changes: 16 additions & 1 deletion lib/backdoor/session.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule Backdoor.Session do
import Backdoor.Session.ViaTuple

# Public API

#
def start_session() do
with session_id <- Backdoor.Session.Counter.next_id(),
spec <- %{
Expand All @@ -12,6 +12,7 @@ defmodule Backdoor.Session do
type: :supervisor
},
{:ok, _pid} <- DynamicSupervisor.start_child(Backdoor.Session.DynamicSupervisor, spec) do
broadcast_session_ids()
{:ok, session_id}
end
end
Expand All @@ -20,11 +21,15 @@ defmodule Backdoor.Session do
with [{supervisor_pid, _}] <-
Registry.lookup(Backdoor.Session.Registry, {Backdoor.Session.Supervisor, session_id}) do
Supervisor.stop(supervisor_pid, :normal)
broadcast_session_ids()
:ok
else
[] ->
broadcast_session_ids()
{:error, :not_found}

err ->
broadcast_session_ids()
err
end
end
Expand All @@ -43,4 +48,14 @@ defmodule Backdoor.Session do
def get_logs(session_id) do
Backdoor.Session.Log.get_logs(via_tuple(Backdoor.Session.Log, session_id))
end

@topic_name "backdoor_events"

defp broadcast_session_ids() do
Phoenix.PubSub.broadcast(pubsub_server(), @topic_name, {:session_ids, session_ids()})
end

defp pubsub_server() do
Application.get_env(:backdoor, :pubsub_server)
end
end
7 changes: 7 additions & 0 deletions lib/backdoor/session/code_runner.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,14 @@ defmodule Backdoor.Session.CodeRunner do
:elixir.env_for_eval(file: "backdoor")
end

@topic_name "backdoor_events"

defp log(session_id, value) do
Phoenix.PubSub.broadcast(pubsub_server(), @topic_name, {:put_log, session_id, value})
Backdoor.Session.Log.put_log(via_tuple(Backdoor.Session.Log, session_id), value)
end

defp pubsub_server() do
Application.get_env(:backdoor, :pubsub_server)
end
end

0 comments on commit 4aad6db

Please sign in to comment.