Skip to content

Commit

Permalink
Merge 6dd214f into fb44ad1
Browse files Browse the repository at this point in the history
  • Loading branch information
alde103 committed Jun 2, 2021
2 parents fb44ad1 + 6dd214f commit 4854c60
Show file tree
Hide file tree
Showing 6 changed files with 652 additions and 9 deletions.
71 changes: 62 additions & 9 deletions lib/muontrap/daemon.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,33 @@ defmodule MuonTrap.Daemon do
is a list of options. The same options as `MuonTrap.cmd/3` are available with
the following additions:
* `:name` - Name the Daemon GenServer
* `:log_output` - When set, send output from the command to the Logger. Specify the log level (e.g., `:debug`)
* `:log_prefix` - Prefix each log message with this string (defaults to the program's path)
* `:name` - Name the Daemon GenServer.
* `:controlling_process` - when set, it notifies the output from the command to the process by sending a message.
* `:msg_callback` - When set, it sends the output from the command to the callback. Only funtions with /1 arity are allowed.
* `:log_output` - When set, it sends the output from the command to the Logger. Specify the log level (e.g., `:debug`).
* `:log_prefix` - Prefix each log message with this string (defaults to the program's path).
* `:stderr_to_stdout` - When set to `true`, redirect stderr to stdout. Defaults to `false`.
If you want to run multiple `MuonTrap.Daemon`s under one supervisor, they'll
all need unique IDs. Use `Supervisor.child_spec/2` like this:
```elixir
Supervisor.child_spec({MuonTrap.Daemon, ["my_server"), []]}, id: :server1)
Supervisor.child_spec({MuonTrap.Daemon, ["my_server", []]}, id: :server1)
```
"""

defmodule State do
@moduledoc false

defstruct [:command, :port, :cgroup_path, :log_output, :log_prefix]
defstruct [
:command,
:port,
:cgroup_path,
:log_output,
:log_prefix,
:msg_callback,
:controlling_process
]
end

def child_spec([command, args]) do
Expand Down Expand Up @@ -107,6 +117,8 @@ defmodule MuonTrap.Daemon do
command: command,
port: port,
cgroup_path: Map.get(options, :cgroup_path),
controlling_process: Map.get(options, :controlling_process),
msg_callback: Map.get(options, :msg_callback),
log_output: Map.get(options, :log_output),
log_prefix: Map.get(options, :log_prefix, command <> ": ")
}}
Expand Down Expand Up @@ -139,22 +151,42 @@ defmodule MuonTrap.Daemon do
end

@impl true
def handle_info({_port, {:data, _}}, %State{log_output: nil} = state) do
# Ignore output
def handle_info(
{port, {:data, {_, message}}},
%State{
port: port,
log_output: nil,
msg_callback: msg_callback,
controlling_process: c_pid
} = state
) do
notify_msg_to_controlling_process(c_pid, message)
dispatch_message(msg_callback, message)
{:noreply, state}
end

@impl true
def handle_info(
{port, {:data, {_, message}}},
%State{port: port, log_output: log_level, log_prefix: prefix} = state
%State{
port: port,
log_output: log_level,
log_prefix: prefix,
msg_callback: msg_callback,
controlling_process: c_pid
} = state
) do
Logger.log(log_level, [prefix, message])
notify_msg_to_controlling_process(c_pid, message)
dispatch_message(msg_callback, message)
{:noreply, state}
end

@impl true
def handle_info({port, {:exit_status, status}}, %State{port: port} = state) do
def handle_info(
{port, {:exit_status, status}},
%State{port: port, controlling_process: c_pid} = state
) do
reason =
case status do
0 ->
Expand All @@ -166,6 +198,27 @@ defmodule MuonTrap.Daemon do
:error_exit_status
end

notify_exit_to_controlling_process(c_pid, reason, status)

{:stop, reason, state}
end

@impl true
def handle_info(unhandled_msg, state) do
Logger.warn("Unhandled message: #{inspect(unhandled_msg)}")
{:noreply, state}
end

defp dispatch_message(nil, _message), do: :ok
defp dispatch_message(msg_callback, message), do: msg_callback.(message)

defp notify_msg_to_controlling_process(nil, _message), do: :ok

defp notify_msg_to_controlling_process(controlling_process_pid, message),
do: send(controlling_process_pid, {:daemon_output, message})

defp notify_exit_to_controlling_process(nil, _reason, _status), do: :ok

defp notify_exit_to_controlling_process(controlling_process_pid, reason, status),
do: send(controlling_process_pid, {:daemon_exit, reason, status})
end

0 comments on commit 4854c60

Please sign in to comment.