Packages

Porter provides an OTP application that runs the specified system command using the Erlang Port library and then streams the results back to you.

Current section

Files

Jump to
porter lib porter.ex
Raw

lib/porter.ex

defmodule Porter do
use GenServer
alias Porter.Notifier
def start_link do
GenServer.start_link(__MODULE__, [Notifier.manager])
end
def init([pid]), do: {:ok, %{events_pid: pid}}
def run(cmd, callbacks) do
{:ok, pid} = start_link
GenServer.cast(pid, {:run, cmd, callbacks})
end
def handle_cast({:add_callback, callback}, state) do
Notifier.subscribe(state.events_pid, callback)
{:noreply, state}
end
def handle_cast({:run, cmd}, state) do
do_run(cmd, state.events_pid)
{:noreply, state}
end
def handle_cast({:run, cmd, callbacks}, state) do
for callback <- callbacks, do: Notifier.subscribe(state.events_pid, callback)
handle_cast({:run, cmd}, state)
end
def handle_cast(request, state) do
super(request, state)
end
defp do_run(cmd, pid) do
port = Port.open({:spawn, cmd}, [:stream, :binary, :exit_status])
loop(port, pid)
end
defp loop(port, pid) do
receive do
{port, data} -> handle_data(port, pid, data)
end
end
defp handle_data(port, pid, data) do
case data do
{:data, msg} ->
notify(pid, {:ok, {:data, msg}})
loop(port, pid)
{:exit_status, 0} ->
notify(pid, {:ok, {:exit_status, 0}})
{:exit_status, code} ->
notify(pid, {:error, {:exit_status, code}})
end
end
defp notify(pid, message), do: Notifier.notify(pid, message)
end