Skip to main content

lib/systemd/unit_object.ex

defmodule Systemd.UnitObject do
  @moduledoc """
  D-Bus object for a loaded systemd unit.
  """

  alias Systemd.{Error, Properties, ServiceState, SocketState, TimerState, UnitState}

  @interface "org.freedesktop.systemd1.Unit"

  @enforce_keys [:object_path]
  @type t :: %__MODULE__{name: String.t() | nil, object_path: String.t()}

  defstruct [:name, :object_path]

  @doc false
  @spec new(String.t(), String.t() | nil) :: t()
  def new(object_path, name \\ nil) when is_binary(object_path) do
    %__MODULE__{name: name, object_path: object_path}
  end

  @doc """
  Reads one property from the unit object.
  """
  @spec property(pid(), t(), String.t()) :: {:ok, term()} | {:error, Error.t()}
  def property(conn, %__MODULE__{object_path: path}, property) do
    Properties.get(conn, path, @interface, property)
  end

  @doc """
  Reads common unit state properties.
  """
  @spec state(pid(), t()) :: {:ok, UnitState.t()} | {:error, Error.t()}
  def state(conn, %__MODULE__{} = unit) do
    typed_state(conn, unit, @interface, UnitState)
  end

  @doc """
  Reads common service-specific properties.
  """
  @spec service_state(pid(), t()) :: {:ok, ServiceState.t()} | {:error, Error.t()}
  def service_state(conn, %__MODULE__{} = unit) do
    typed_state(conn, unit, "org.freedesktop.systemd1.Service", ServiceState)
  end

  @doc """
  Reads common socket-specific properties.
  """
  @spec socket_state(pid(), t()) :: {:ok, SocketState.t()} | {:error, Error.t()}
  def socket_state(conn, %__MODULE__{} = unit) do
    typed_state(conn, unit, "org.freedesktop.systemd1.Socket", SocketState)
  end

  @doc """
  Reads common timer-specific properties.
  """
  @spec timer_state(pid(), t()) :: {:ok, TimerState.t()} | {:error, Error.t()}
  def timer_state(conn, %__MODULE__{} = unit) do
    typed_state(conn, unit, "org.freedesktop.systemd1.Timer", TimerState)
  end

  defp typed_state(conn, unit, interface, module) do
    with {:ok, properties} <- Properties.get_all(conn, unit.object_path, interface) do
      {:ok, module.from_properties(properties)}
    end
  end
end