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.
72 lines
1.6 KiB
Elixir
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
|