Packages

Typed distributed messaging for Gleam on the BEAM.

Retired package: Deprecated - The project needs to be redesigned around a much smaller and clearer core.

Current section

Files

Jump to
distribute src distribute@node_builder.erl
Raw

src/distribute@node_builder.erl

-module(distribute@node_builder).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/distribute/node_builder.gleam").
-export([new/0, with_name/2, with_cookie/2, connect_to/2, with_auto_register/1, start/1]).
-export_type([node_builder/0, node_result/0, valid_config/0, startup_result/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type node_builder() :: {node_builder,
gleam@option:option(binary()),
gleam@option:option(binary()),
list(binary()),
boolean()}.
-type node_result() :: {node_result,
boolean(),
list(binary()),
list(binary()),
list(binary())}.
-type valid_config() :: {valid_config,
binary(),
binary(),
list(binary()),
boolean()}.
-type startup_result() :: {startup_result,
boolean(),
list(binary()),
list(binary())}.
-file("src/distribute/node_builder.gleam", 41).
?DOC(" Create a new node builder with default settings\n").
-spec new() -> node_builder().
new() ->
{node_builder, none, none, [], false}.
-file("src/distribute/node_builder.gleam", 51).
?DOC(" Set the node name\n").
-spec with_name(node_builder(), binary()) -> node_builder().
with_name(Builder, Name) ->
{node_builder,
{some, Name},
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder)}.
-file("src/distribute/node_builder.gleam", 56).
?DOC(" Set the cookie\n").
-spec with_cookie(node_builder(), binary()) -> node_builder().
with_cookie(Builder, Cookie) ->
{node_builder,
erlang:element(2, Builder),
{some, Cookie},
erlang:element(4, Builder),
erlang:element(5, Builder)}.
-file("src/distribute/node_builder.gleam", 61).
?DOC(" Add peers to connect to\n").
-spec connect_to(node_builder(), list(binary())) -> node_builder().
connect_to(Builder, Peers) ->
{node_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
lists:append(erlang:element(4, Builder), Peers),
erlang:element(5, Builder)}.
-file("src/distribute/node_builder.gleam", 66).
?DOC(" Enable auto-registration of common services\n").
-spec with_auto_register(node_builder()) -> node_builder().
with_auto_register(Builder) ->
{node_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
true}.
-file("src/distribute/node_builder.gleam", 144).
?DOC(" Validate builder configuration\n").
-spec validate_config(node_builder()) -> {ok, valid_config()} |
{error, binary()}.
validate_config(Builder) ->
case erlang:element(2, Builder) of
none ->
{error, <<"Node name is required"/utf8>>};
{some, Name} ->
case erlang:element(3, Builder) of
none ->
{error, <<"Cookie is required"/utf8>>};
{some, Cookie} ->
{ok,
{valid_config,
Name,
Cookie,
erlang:element(4, Builder),
erlang:element(5, Builder)}}
end
end.
-file("src/distribute/node_builder.gleam", 174).
?DOC(" Start the node\n").
-spec start_node(valid_config()) -> startup_result().
start_node(Config) ->
case distribute@cluster:start_node(
erlang:element(2, Config),
erlang:element(3, Config)
) of
{ok, nil} ->
{startup_result, true, [], []};
{error, Error} ->
Error_str = case Error of
{invalid_node_name, Msg} ->
<<"Invalid node name: "/utf8, Msg/binary>>;
already_started ->
<<"Node already started"/utf8>>;
cookie_too_long ->
<<"Cookie too long"/utf8>>;
{network_error, Msg@1} ->
<<"Network error: "/utf8, Msg@1/binary>>;
{system_error, Msg@2} ->
<<"System error: "/utf8, Msg@2/binary>>;
{start_failed, Msg@3} ->
<<"Start failed: "/utf8, Msg@3/binary>>
end,
{startup_result, false, [Error_str], []}
end.
-file("src/distribute/node_builder.gleam", 201).
?DOC(" Connect to peer nodes\n").
-spec connect_peers(list(binary())) -> list(binary()).
connect_peers(Peers) ->
gleam@list:fold(
Peers,
[],
fun(Acc, Peer) -> case distribute@cluster:connect(Peer) of
{ok, _} ->
distribute@log:debug(
<<"Connected to peer"/utf8>>,
[{<<"peer"/utf8>>, Peer}]
),
[Peer | Acc];
{error, _} ->
distribute@log:warn(
<<"Failed to connect to peer"/utf8>>,
[{<<"peer"/utf8>>, Peer}]
),
Acc
end end
).
-file("src/distribute/node_builder.gleam", 217).
?DOC(" Register common services\n").
-spec register_common_services() -> list(binary()).
register_common_services() ->
Services = [{<<"logger"/utf8>>, <<"log_service"/utf8>>},
{<<"monitor"/utf8>>, <<"monitor_service"/utf8>>},
{<<"election"/utf8>>, <<"election_service"/utf8>>}],
gleam@list:fold(
Services,
[],
fun(Acc, Service_pair) ->
{Module, Name} = Service_pair,
distribute@log:debug(
<<"Auto-registered service"/utf8>>,
[{<<"name"/utf8>>, Name}, {<<"module"/utf8>>, Module}]
),
[Name | Acc]
end
).
-file("src/distribute/node_builder.gleam", 236).
-spec bool_to_string(boolean()) -> binary().
bool_to_string(B) ->
case B of
true ->
<<"true"/utf8>>;
false ->
<<"false"/utf8>>
end.
-file("src/distribute/node_builder.gleam", 243).
-spec int_to_string(integer()) -> binary().
int_to_string(I) ->
case I of
0 ->
<<"0"/utf8>>;
1 ->
<<"1"/utf8>>;
2 ->
<<"2"/utf8>>;
3 ->
<<"3"/utf8>>;
4 ->
<<"4"/utf8>>;
5 ->
<<"5"/utf8>>;
_ ->
<<"N"/utf8>>
end.
-file("src/distribute/node_builder.gleam", 71).
?DOC(" Start the node with the configured settings\n").
-spec start(node_builder()) -> {ok, node_result()} |
{error, distribute@cluster:start_error()}.
start(Builder) ->
distribute@log:info(
<<"Starting distributed node with builder"/utf8>>,
[{<<"has_name"/utf8>>,
bool_to_string(gleam@option:is_some(erlang:element(2, Builder)))},
{<<"peer_count"/utf8>>,
int_to_string(erlang:length(erlang:element(4, Builder)))},
{<<"auto_register"/utf8>>,
bool_to_string(erlang:element(5, Builder))}]
),
case validate_config(Builder) of
{ok, Valid_config} ->
Start_result = start_node(Valid_config),
case erlang:element(2, Start_result) of
true ->
distribute@log:info(
<<"Node started successfully"/utf8>>,
[{<<"node"/utf8>>, erlang:element(2, Valid_config)},
{<<"connections"/utf8>>,
int_to_string(
erlang:length(
erlang:element(4, Start_result)
)
)}]
),
case distribute@transport:start_link() of
{ok, _} ->
distribute@log:info(
<<"Transport layer started"/utf8>>,
[]
);
{error, E} ->
distribute@log:error(
<<"Failed to start transport layer"/utf8>>,
[{<<"error"/utf8>>, gleam@string:inspect(E)}]
)
end,
Connect_result = connect_peers(
erlang:element(4, Valid_config)
),
Register_result = case erlang:element(5, Valid_config) of
true ->
register_common_services();
false ->
[]
end,
Final_result = {node_result,
true,
Connect_result,
Register_result,
erlang:element(3, Start_result)},
{ok, Final_result};
false ->
distribute@log:error(
<<"Failed to start node"/utf8>>,
[{<<"errors"/utf8>>,
gleam@string:join(
erlang:element(3, Start_result),
<<", "/utf8>>
)}]
),
{error,
{start_failed,
gleam@string:join(
erlang:element(3, Start_result),
<<", "/utf8>>
)}}
end;
{error, Error} ->
distribute@log:error(
<<"Configuration validation failed"/utf8>>,
[{<<"error"/utf8>>, Error}]
),
{error, {invalid_node_name, Error}}
end.