You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
asciinema.org/lib/asciinema/vt/worker.ex

72 lines
1.6 KiB
Elixir

defmodule Asciinema.Vt.Worker do
use GenServer
@vt_script_path "vt/main.js"
# Client API
def start_link(_) do
GenServer.start_link(__MODULE__, nil, [])
end
def new(pid, width, height) do
GenServer.cast(pid, {:new, width, height})
end
def feed(pid, data) do
GenServer.cast(pid, {:feed, data})
end
def dump_screen(pid, timeout) do
GenServer.call(pid, :dump_screen, timeout)
end
# Server callbacks
def init(_) do
path = System.find_executable("node")
port = Port.open({:spawn_executable, path}, [:binary, args: [@vt_script_path]])
{:ok, port}
end
def handle_call(:dump_screen, _from, port) do
send_cmd(port, "dump-screen")
case read_stout_line(port) do
{:ok, line} ->
result = line |> Poison.decode! |> Map.get("result")
{:reply, {:ok, result}, port}
{:error, reason} ->
{:reply, {:error, reason}, port}
end
end
defp read_stout_line(port) do
read_stout_line(port, "")
end
defp read_stout_line(port, line) do
receive do
{^port, {:data, data}} ->
if String.ends_with?(data, "\n") do
{:ok, line <> String.trim_trailing(data)}
else
read_stout_line(port, line <> data)
end
end
end
def handle_cast({:new, width, height}, port) do
send_cmd(port, "new", %{width: width, height: height})
{:noreply, port}
end
def handle_cast({:feed, data}, port) do
send_cmd(port, "feed-str", %{str: data})
{:noreply, port}
end
defp send_cmd(port, cmd, data \\ %{}) do
json = data |> Map.put(:cmd, cmd) |> Poison.encode!
true = Port.command(port, "#{json}\n")
end
end