Skip to content

Instantly share code, notes, and snippets.

@benhamill
Last active September 4, 2016 14:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benhamill/88ea21885c584df10bd5 to your computer and use it in GitHub Desktop.
Save benhamill/88ea21885c584df10bd5 to your computer and use it in GitHub Desktop.
#!/usr/bin/env elixir
defmodule Listen do
use GenServer
## Client
def start_link(command, opts \\ []) do
GenServer.start_link(__MODULE__, command, opts)
end
def handle_input(server, input) do
GenServer.call(server, input)
end
## Server
def init(command) do
{:ok, %{port: start_port(command), waiting: nil, exit_status: nil}}
end
def handle_call(input, from, state) do
if state.exit_status do
{:reply, {:exit_status, state.exit_status}, %{state | exit_status: nil}}
else
Port.command(state.port, input)
{:noreply, %{state | waiting: from}}
end
end
def handle_info({_port, {:data, response}}, state) do
case state.waiting do
nil -> {:stop, "Got unexpected data: #{response}", state}
caller ->
GenServer.reply(caller, {:ok, response})
{:noreply, %{state | waiting: nil}}
end
end
def handle_info({_port, {:exit_status, status}}, state) do
case state.waiting do
nil -> {:noreply, %{state | exit_status: status}}
caller ->
GenServer.reply(caller, {:exit_status, status})
{:noreply, %{state | waiting: nil, exit_status: nil}}
end
end
def handle_info(info, state) do
{:stop, "Weird message: #{inspect info}", state}
end
defp start_port(command) do
Port.open({:spawn, command}, [:binary, :exit_status])
end
end
{options, _, _} = OptionParser.parse(
System.argv,
strict: [
ruby: :boolean,
elixir: :boolean,
bash: :boolean,
]
)
command = cond do
options[:elixir] -> ~S"""
elixir -e "
IO.read(:line)
|> String.strip
|> IO.puts
"
"""
options[:ruby] -> ~S"""
ruby -e "
STDOUT.sync = true
puts gets.strip
"
"""
true -> "head -n1"
end
{:ok, server} = Listen.start_link(command, debug: [:trace])
Enum.each [
~s(Yeah\n),
~s(Yep\n),
~s(Uh-huh\n),
], fn out->
case Listen.handle_input(server, out) do
{:exit_status, status} ->
IO.puts "Process exited, #{status}."
exit :normal
{:ok, response} -> IO.inspect response
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment