Packages

SuperWorker is a powerful Elixir library for working with supervisors and background jobs. It provides a much simpler approach than traditional supervisors. This library is currently under development and is unstable, so it is not recommended for production use.

Current section

Files

Jump to
super_worker lib supervisor utils.ex
Raw

lib/supervisor/utils.ex

defmodule SuperWorker.Supervisor.Utils do
@moduledoc false
require Logger
# convert specified keyword to a tuple.
@spec get_keyword(atom()) :: {:type, atom()} | {:error, atom()}
def get_keyword(:group) do
{:type, :group}
end
def get_keyword(:chain) do
{:type, :chain}
end
def get_keyword(:standalone) do
{:type, :standalone}
end
def get_keyword(_) do
{:error, :invalid_options}
end
@spec generic_default_sup_opts(map()) :: map()
def generic_default_sup_opts(opts) do
if Map.has_key?(opts, :owner) do
opts
else
Map.put(opts, :owner, self())
end
end
@spec normalize_opts([atom() | keyword()], list(atom())) :: {:ok, map()} | {:error, atom()|{atom(), any()}}
def normalize_opts(opts, params) do
do_normalize_opts(opts, params, %{}, [])
end
@spec get_item(map(), any()) :: {:ok, any()} | {:error, atom()}
def get_item(map, key) do
case Map.get(map, key) do
nil -> {:error, {:not_found, key}}
value -> {:ok, value}
end
end
@spec get_hash_order(term(), non_neg_integer()) :: non_neg_integer()
def get_hash_order(term, num) do
:erlang.phash2(term, num)
end
@spec get_default_schedulers() :: non_neg_integer()
def get_default_schedulers() do
System.schedulers_online()
end
@spec count_msgs(pid()) :: non_neg_integer()
def count_msgs(pid) do
case Process.info(pid, :message_queue_len) do
{:message_queue_len, n} -> n
nil -> 0
end
end
@spec check_type(map(), atom(), (any() -> boolean())) :: {:ok, map()} | {:error, atom()}
def check_type(opts, key, fun) do
case Map.get(opts, key) do
nil ->
Logger.warning("SuperWorker, Utils, option #{inspect key} is not found")
{:error, :invalid_type}
value ->
if fun.(value) do
{:ok, opts}
else
Logger.warning("SuperWorker, Utils, option #{inspect key} is invalid")
{:error, :invalid_type}
end
end
end
@spec random_id() :: binary()
def random_id() do
:crypto.strong_rand_bytes(16) |> Base.encode16()
end
@spec response_ref() :: {pid(), reference()}
def response_ref() do
{self(), make_ref()}
end
@spec api_receiver({pid(), reference()}, integer() | :infinity) :: any()
def api_receiver({_from, ref}, timeout) do
receive do
{^ref, result} ->
result
after timeout ->
{:error, :api_timeout}
end
end
@spec api_response({pid(), reference()}, any()) :: any()
def api_response({from, ref}, result) do
send(from, {ref, result})
end
@spec call_api(atom() | pid(), atom(), any(), integer() | :infinity) :: any()
def call_api(target, api, params, timeout) when is_atom(target) or is_pid(target) do
Logger.debug("SuperWorker, Utils, call API: #{inspect api}, #{inspect params}, target: #{inspect target}")
ref = response_ref()
send(target, {api, ref, params})
api_receiver(ref, timeout)
end
@spec call_api_no_reply(atom() | pid(), atom(), any()) :: any()
def call_api_no_reply(target, api, params) when is_atom(target) or is_pid(target) do
{_, ref} = response_ref() # ref is just for tracking, adds more in the future.
send(target, {api, ref, params})
end
## Private functions
@spec do_normalize_opts([keyword() | atom()], list(atom()), map(), list(keyword() | atom()))
:: {:ok, map()} | {:error, {atom()|{atom(), list(keyword() | atom())}}}
defp do_normalize_opts([], _params, valid, invalid) do
if Enum.empty?(invalid) do
{:ok, valid}
else
{:error, {:invalid_options, invalid}}
end
end
defp do_normalize_opts([{key, value}|rest], params, valid, invalid) do
if key in params do
do_normalize_opts(rest, params, Map.put(valid, key, value), invalid)
else
do_normalize_opts(rest, params, valid, [key | invalid])
end
end
defp do_normalize_opts([short_opt|rest], params, valid, invalid) when is_atom(short_opt) do
if short_opt in params do
{key, value} = get_keyword(short_opt)
do_normalize_opts(rest, params, Map.put(valid, key, value), invalid)
else
do_normalize_opts(rest, params, valid, [short_opt | invalid])
end
end
defp do_normalize_opts([opt|rest], params, valid, invalid) do
do_normalize_opts(rest, params, valid, [opt | invalid])
end
end