Packages
drab
0.10.2
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.3
0.8.2
0.8.1
0.8.0
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.6.0-pre.1
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.1
0.1.0
Remote controlled frontend framework for Phoenix.
Current section
Files
Jump to
Current section
Files
lib/drab/channel.ex
defmodule Drab.Channel do
@moduledoc false
require Logger
use Phoenix.Channel, Drab.Config.get(:phoenix_channel_options)
@spec join(String.t(), any, Phoenix.Socket.t()) :: {:ok, Phoenix.Socket.t()}
def join("__drab:" <> _broadcast_topic, _, socket) do
# socket already contains controller and action
{:ok, pid} = Drab.start_link(socket)
socket_with_pid = assign(socket, :__drab_pid, pid)
{:ok, socket_with_pid}
# {:ok, assign(socket_with_pid, :topics, [])}
end
@spec handle_in(String.t(), map, Phoenix.Socket.t()) :: {:noreply, Phoenix.Socket.t()}
def handle_in("execjs", %{"ok" => [sender_encrypted, reply]}, socket) do
# sender contains PID of the process which sent the query
# sender is waiting for the result
{sender, ref} = sender(socket, sender_encrypted)
send(sender, {:got_results_from_client, :ok, ref, reply})
{:noreply, socket}
end
def handle_in("execjs", %{"error" => [sender_encrypted, reply]}, socket) do
{sender, ref} = sender(socket, sender_encrypted)
send(sender, {:got_results_from_client, :error, ref, reply})
{:noreply, socket}
end
def handle_in("modal", %{"ok" => [sender_encrypted, reply]}, socket) do
{sender, ref} = sender(socket, sender_encrypted)
send(sender, {
:got_results_from_client,
:ok,
ref,
{
String.to_existing_atom(reply["button_clicked"]),
Map.delete(reply["params"], "__drab_modal_hidden_input")
}
})
{:noreply, socket}
end
def handle_in("waiter", %{"drab_waiter_token" => waiter_token, "sender" => sender}, socket) do
{pid, ref} = Drab.Waiter.detokenize_waiter(socket, waiter_token)
send(pid, {:waiter, ref, sender})
{:noreply, socket}
end
def handle_in("onload", payload, socket) do
verify_and_cast(:onload, [payload], socket)
end
def handle_in("onconnect", payload, socket) do
# for debugging
Logger.debug(fn ->
commander = Drab.get_commander(socket)
modules = DrabModule.all_modules_for(commander.__drab__().modules)
grouped =
modules
|> Enum.map(fn module ->
[_ | rest] = Module.split(module)
Enum.join(rest, ".")
end)
|> Enum.join(", ")
live_example = %{Drab.Live => "socket |> poke(text: \"This assign has been drabbed!\")"}
other_examples = %{
Drab.Element => "socket |> set_style(\"body\", backgroundColor: \"red\")",
Drab.Query => "socket |> select(:htmls, from: \"h4\")",
Drab.Modal =>
"socket |> alert(\"Title\", \"Sure?\", buttons: [ok: \"Azaliż\", cancel: \"Poniechaj\"])",
Drab.Core => "socket |> exec_js(\"alert('hello from IEx!')\")"
}
module_examples = Map.merge(live_example, other_examples)
examples =
modules
|> Enum.map(fn module -> module_examples[module] end)
|> Enum.filter(fn x -> !is_nil(x) end)
p = inspect(socket.assigns.__drab_pid)
pid_string = ~r/#PID<(?<pid>.*)>/ |> Regex.named_captures(p) |> Map.get("pid")
"""
Started Drab for #{socket.topic}, handling events in #{inspect(commander)}
You may debug Drab functions in IEx by copy/paste the following:
import Drab.{#{grouped}}
socket = Drab.get_socket(pid("#{pid_string}"))
Examples:
#{Enum.join(examples, "\n")}
"""
end)
session = Drab.Core.detokenize_store(socket, payload["drab_session_token"])
socket = assign(socket, :__session, session)
store = Drab.Core.detokenize_store(socket, payload["drab_store_token"])
socket = assign(socket, :__store, store)
Drab.set_socket(socket.assigns.__drab_pid, socket)
verify_and_cast(:onconnect, [payload], socket)
end
def handle_in(
"event",
%{
# "event" => event_name,
"payload" => payload,
"event_handler_function" => event_handler_function,
"reply_to" => reply_to
},
socket
) do
verify_and_cast(:event, [payload, event_handler_function, reply_to], socket)
end
def handle_info({:subscribe, %{topic: topic, endpoint: endpoint}}, state) do
:ok = endpoint.subscribe(topic)
{:noreply, state}
end
def handle_info({:unsubscribe, %{topic: topic, endpoint: endpoint}}, state) do
:ok = endpoint.unsubscribe(topic)
{:noreply, state}
end
def handle_info(%Phoenix.Socket.Broadcast{topic: _, event: ev, payload: payload}, socket) do
push(socket, ev, payload)
{:noreply, socket}
end
@spec verify_and_cast(atom, list, Phoenix.Socket.t()) :: {:noreply, Phoenix.Socket.t()}
defp verify_and_cast(event_name, params, socket) do
p = [event_name, socket] ++ params
GenServer.cast(socket.assigns.__drab_pid, List.to_tuple(p))
{:noreply, socket}
end
@spec sender(Phoenix.Socket.t(), String.t()) :: {pid, reference}
defp sender(socket, sender_encrypted) do
Drab.detokenize(socket, sender_encrypted)
end
end