defmodule Liaison.NodeHelper do @moduledoc """ NodeHelper aims to make converting between node representations into FQDN nodenames ### Auto Localhost Calculation Ever tried to connect to another local node but your machine name is not fun to enter? Now all you need to do is enter a name for the node and the localhost is automatically appended ### Node Formats The following is a list of valid node formats and how they are expanded * `name` -> `:name@localhost` * `name@host` -> `:name@host` * `name@a.b.c.d` -> `:"name@a.b.c.d"` * `%{name: name}` -> `:name@localhost` * `%{name: :random}` -> random 6 digit name, eg: `:atj2ld@localhost` * `%{name: [random: 3]}` -> random 3 digit name, eg:`:d5h@localhost` * `%{name: name, host: host}` -> `:name@host` * `%{name: name, host: :shortname}` -> `:name@localhost` * `%{name: name, host: :longname}` -> `:name@localhost_ip` """ alias Liaison.IP @type nodename :: atom() @type node_format :: String.t() | atom() | map() @doc """ Expands a node format into a fully qualified nodename """ @spec to_nodename(node_format) :: nodename def to_nodename(format) when is_binary(format) do case String.split(format, "@") do [name] -> "#{name}@#{get_localhost()}" [name, host] -> "#{name}@#{host}" end |> String.to_atom() end def to_nodename(format) when is_atom(format) do Atom.to_string(format) |> to_nodename() end def to_nodename(%{name: :random}) do random_name() |> to_nodename() end def to_nodename(%{name: [random: n]}) do random_name(n) |> to_nodename() end def to_nodename(%{name: name, host: host}) do cond do host == :shortname -> "#{name}" host == :longname -> "#{name}@#{get_localhost_ip()}" true -> "#{name}@#{host}" end |> to_nodename() end def to_nodename(%{name: name}) do to_nodename(name) end @doc """ Returns the localhost name of the machine """ @spec get_localhost() :: charlist() def get_localhost() do elem(:inet.gethostname(), 1) end @doc """ Returns the first ip4 address for the machine """ @spec get_localhost_ip() :: String.t() def get_localhost_ip() do IP.as_string(IP.get_ipv4_addr()) end @doc """ Returns a random alphanumeric localhost name of length `len` """ @spec random_name(integer) :: String.t() def random_name(len \\ 6) do opts = Enum.to_list(?a..?z) ++ Enum.to_list(?A..?Z) ++ Enum.to_list(?1..?9) Enum.map(1..len, fn _ -> Enum.random(opts) end) |> List.to_string() end end