defmodule ProxmoxAgent.Config do @moduledoc "Loads and validates the TOML agent config." defstruct [ :server_url, :token, :host_id, :dump_dir, fast_seconds: 30, medium_seconds: 300, slow_seconds: 1800 ] @type t :: %__MODULE__{ server_url: String.t(), token: String.t(), host_id: String.t(), dump_dir: String.t() | nil, fast_seconds: pos_integer(), medium_seconds: pos_integer(), slow_seconds: pos_integer() } @required ~w(server_url token)a @spec load(Path.t()) :: {:ok, t()} | {:error, {:file_read, term()} | {:parse, term()} | {:missing_key, atom()}} def load(path) do with {:ok, body} <- read_file(path), {:ok, parsed} <- parse_toml(body), :ok <- validate_required(parsed) do {:ok, build(parsed)} end end defp read_file(path) do case File.read(path) do {:ok, body} -> {:ok, body} {:error, reason} -> {:error, {:file_read, reason}} end end defp parse_toml(body) do case Toml.decode(body) do {:ok, map} -> {:ok, map} {:error, reason} -> {:error, {:parse, reason}} end end defp validate_required(map) do Enum.find_value(@required, :ok, fn key -> case Map.get(map, Atom.to_string(key)) do v when is_binary(v) and v != "" -> nil _ -> {:error, {:missing_key, key}} end end) end defp build(map) do intervals = Map.get(map, "intervals", %{}) debug = Map.get(map, "debug", %{}) %__MODULE__{ server_url: map["server_url"], token: map["token"], host_id: map["host_id"] || hostname(), dump_dir: normalize_dump_dir(Map.get(debug, "dump_dir")), fast_seconds: Map.get(intervals, "fast_seconds", 30), medium_seconds: Map.get(intervals, "medium_seconds", 300), slow_seconds: Map.get(intervals, "slow_seconds", 1800) } end defp normalize_dump_dir(nil), do: nil defp normalize_dump_dir(""), do: nil defp normalize_dump_dir(s) when is_binary(s), do: s defp normalize_dump_dir(_), do: nil defp hostname do case :inet.gethostname() do {:ok, name} -> List.to_string(name) _ -> "unknown-host" end end end