-module(grisp_connect_utils).
%--- Exports -------------------------------------------------------------------
% API functions
-export([retry_delay/1]).
-export([check_inet_ipv4/0]).
%--- API Functions -------------------------------------------------------------
check_inet_ipv4() ->
case get_ip_of_valid_interfaces() of
{ok, {IP1, _, _, _} = IP} when IP1 =/= 127 -> {ok, IP};
_ -> invalid
end.
%--- Internal Functions --------------------------------------------------------
retry_delay(0) ->
0;
retry_delay(RetryCount) ->
%% Calculate the connection delay in milliseconds with exponential backoff.
%% The delay is selected randomly between `1000' and
%% `2 ^ RETRY_COUNT - 1000' with a maximum value of `64000'.
%% Loosely inspired by https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
MinDelay = 1000,
MaxDelay = 64000,
MaxRandomDelay = min(MaxDelay, (1 bsl RetryCount) * 1000) - MinDelay,
MinDelay + rand:uniform(MaxRandomDelay).
get_ipv4_from_opts([]) ->
undefined;
get_ipv4_from_opts([{addr, {_1, _2, _3, _4}} | _]) ->
{ok, {_1, _2, _3, _4}};
get_ipv4_from_opts([_ | TL]) ->
case get_ipv4_from_opts(TL) of
{ok, _IP} = Result -> Result;
Other -> Other
end.
has_ipv4(Opts) ->
get_ipv4_from_opts(Opts) =/= undefined.
flags_are_ok(Flags) ->
lists:member(up, Flags) and
lists:member(running, Flags) and
not lists:member(loopback, Flags).
get_valid_interfaces() ->
case inet:getifaddrs() of
{error, _Reason} = Error -> Error;
{ok, Interfaces} ->
{ok, [Opts || {_Name, [{flags, Flags} | Opts]} <- Interfaces,
flags_are_ok(Flags), has_ipv4(Opts)]}
end.
get_ip_of_valid_interfaces() ->
case get_valid_interfaces() of
{error, _Reason} = Error -> Error;
{ok, [Opts | _]} -> get_ipv4_from_opts(Opts);
_ -> undefined
end.