Current section
Files
Jump to
Current section
Files
lib/sailfish/console.ex
defmodule Sailfish.Client.Commands.Console do
use Riptide.Command
def handle_call(%{action: "riptide.connect"}, from, state) do
{:reply, 1, state}
end
def handle_call(%{action: "console.list", body: key}, from, state) do
{:reply, Map.keys(state[:consoles] || %{}), state}
end
def handle_call(%{action: "console.new", body: key}, from, state) do
{:ok, pid} = Sailfish.Client.Console.Supervisor.start_child(key)
Process.monitor(pid)
{:reply, key, Dynamic.put(state, [:consoles, key], pid)}
end
def handle_call(
%{action: "console.exit", body: console},
from,
state
) do
state
|> Dynamic.get([:consoles, console])
|> case do
nil ->
{:error, :not_found, state}
pid ->
true = Process.exit(pid, :kill)
{:reply, :ok, state}
end
end
def handle_call(
%{action: "console.execute", body: %{"console" => key, "code" => code}},
from,
state
) do
state
|> Dynamic.get([:consoles, key])
|> case do
nil ->
{:error, :not_found, state}
pid ->
Task.async(fn ->
reply = GenServer.call(pid, {:execute, code})
{:reply, reply}
end)
end
end
def handle_call(%{action: "console.execute", body: code}, from, state) do
try do
{result, _} = Code.eval_string(code, [])
{:reply, inspect(result, pretty: true), state}
rescue
e -> {:error, inspect(e, pretty: true), state}
end
end
def handle_info(:connect, _from, state) do
{:noreply, state}
end
def handle_info(msg = {:DOWN, _ref, :process, pid, _reason}, _from, state) do
state.consoles
|> Enum.find(fn {k, p} -> p == pid end)
|> case do
{key, _} ->
{:reply, "console.exit", key, Dynamic.delete(state, [:consoles, key])}
_ ->
{:noreply, state}
end
end
end
defmodule Sailfish.Client.Console.Supervisor do
use DynamicSupervisor
def start_link(init_arg) do
DynamicSupervisor.start_link(__MODULE__, [], name: __MODULE__)
end
def init(_) do
DynamicSupervisor.init(strategy: :one_for_one)
end
def start_child(key) do
DynamicSupervisor.start_child(__MODULE__, %{
id: key,
start: {Sailfish.Client.Console.Worker, :start_link, [key]},
restart: :temporary,
type: :worker
})
end
end
defmodule Sailfish.Client.Console.Worker do
use GenServer
def start_link(key) do
GenServer.start_link(__MODULE__, key)
end
def init(key) do
{:ok, %{key: key, vars: []}}
end
def handle_call({:execute, code}, _from, state) do
try do
{result, vars} = Code.eval_string(code, state.vars)
{:reply, inspect(result, pretty: true), Dynamic.put(state, [:vars], vars)}
rescue
e -> {:reply, inspect(e, pretty: true), state}
end
end
def handle_call(:exit, _from, state) do
{:stop, :normal, :ok, state}
end
end