Packages

macula

0.8.4
7.0.0 6.0.0 5.2.2 5.2.1 5.2.0 5.1.0 5.0.0 4.8.0 4.7.1 4.7.0 4.6.0 4.5.0 4.4.10 4.4.9 4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.1 4.3.0 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.1 4.1.0 4.0.0 3.16.0 3.15.3 3.15.2 3.15.1 3.14.0 3.13.0 3.12.1 3.12.0 3.11.1 3.11.0 3.10.3 3.10.2 3.10.1 3.9.0 3.8.0 3.7.0 3.5.0 3.4.0 3.3.0 3.2.0 3.1.0 3.0.0 2.1.1 2.1.0 2.0.0 1.5.2 1.5.1 1.4.30 1.4.29 1.4.28 1.4.27 1.4.26 1.4.25 1.4.24 1.4.23 1.4.22 1.4.21 1.4.20 1.4.19 1.4.18 1.4.17 1.4.16 1.4.15 1.4.14 1.4.13 1.4.11 1.4.10 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.1 1.3.0 1.2.0 1.1.0 1.0.10 1.0.9 1.0.8 1.0.7 1.0.6 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 1.0.0 0.48.6 0.48.5 0.48.4 0.48.3 0.48.2 0.48.1 0.48.0 0.47.1 0.47.0 0.46.3 0.46.1 0.46.0 0.45.3 0.45.2 0.45.1 0.45.0 0.44.2 0.44.1 0.44.0 0.43.3 0.43.2 0.43.1 0.43.0 0.42.9 0.42.8 0.42.7 0.42.6 0.42.5 0.42.4 0.42.3 0.42.2 0.42.1 0.42.0 0.41.1 0.41.0 0.40.1 0.40.0 0.39.9 0.39.8 0.39.7 0.39.6 0.39.5 0.39.4 0.39.3 0.39.2 0.39.1 0.39.0 0.38.8 0.38.7 0.38.6 0.38.5 0.38.4 0.38.3 0.38.2 0.38.1 0.38.0 0.37.7 0.37.6 0.37.5 0.37.4 0.37.3 0.37.2 0.37.1 0.37.0 0.36.6 0.36.5 0.36.4 0.36.3 0.36.2 0.36.1 0.36.0 0.35.4 0.35.3 0.35.2 0.35.1 0.35.0 0.34.1 0.34.0 0.33.1 0.33.0 0.32.5 0.32.4 0.32.3 0.32.2 0.32.1 0.32.0 0.31.9 0.31.8 0.31.7 0.31.6 0.31.5 0.31.4 0.31.3 0.31.2 0.31.1 0.31.0 0.30.10 0.30.9 0.30.8 0.30.7 0.30.6 0.30.5 0.30.4 0.30.3 0.30.2 0.30.1 0.30.0 0.29.0 0.28.3 0.28.2 0.28.1 0.28.0 0.27.1 0.27.0 0.26.1 0.26.0 0.25.6 0.25.5 0.25.4 0.25.3 0.25.2 0.25.1 0.25.0 0.24.6 0.24.5 0.24.4 0.24.3 0.24.2 0.24.1 0.24.0 0.23.3 0.23.2 0.23.1 0.23.0 0.22.12 0.22.11 0.22.10 0.22.9 0.22.8 0.22.7 0.22.6 0.22.5 0.22.4 0.22.3 0.22.2 0.22.1 0.22.0 0.21.7 0.21.6 0.21.5 0.21.4 0.21.2 0.21.1 0.21.0 0.20.25 0.20.24 0.20.23 0.20.22 0.20.21 0.20.20 0.20.19 0.20.18 0.20.17 0.20.16 0.20.15 0.20.14 0.20.13 0.20.12 0.20.11 0.20.10 0.20.9 0.20.8 0.20.7 0.20.6 0.20.5 0.20.3 0.20.2 0.20.1 0.20.0 0.19.2 0.19.1 0.19.0 0.18.1 0.18.0 0.17.4 0.17.3 0.17.2 0.17.1 0.17.0 0.16.6 0.16.5 0.16.4 0.16.3 0.16.2 0.16.1 0.16.0 0.15.1 0.15.0 0.14.3 0.14.2 0.14.1 0.14.0 0.12.6 0.12.5 0.12.3 0.11.3 0.10.2 0.10.1 0.10.0 0.9.2 0.9.1 0.9.0 0.8.25 0.8.24 0.8.23 0.8.22 0.8.21 0.8.20 0.8.19 0.8.18 0.8.17 0.8.16 0.8.15 0.8.14 0.8.13 0.8.12 0.8.11 0.8.10 0.8.9 0.8.8 0.8.7 0.8.6 0.8.5 0.8.4 0.8.3 0.8.2 0.8.1 0.8.0 0.7.30 0.7.29 0.7.28 0.7.27 0.7.26 0.7.25 0.7.24 0.7.23 0.7.22 0.7.21 0.7.20 0.7.19 0.7.18 0.7.17 0.7.16 0.7.15 0.7.14 0.7.13 0.7.12 0.7.11 0.7.10 0.7.9 0.7.8 0.7.7 0.7.6 0.7.5 0.7.4 0.7.3 0.7.2 0.7.1 0.7.0 0.6.7 0.6.6 0.6.5 0.6.4 0.6.3 0.6.2 0.6.1 0.6.0 0.5.0 0.4.4 0.4.3 0.4.2 0.4.1 0.4.0 0.3.4 0.3.3 0.3.2 0.3.1

Macula HTTP/3 Mesh SDK — connect, subscribe, publish, call, advertise

Current section

Files

Jump to
macula src macula_root.erl
Raw

src/macula_root.erl

%%%-------------------------------------------------------------------
%% @doc Macula Application Root Supervisor.
%%
%% This is the top-level supervisor for the Macula application.
%% It manages core infrastructure and optionally starts gateway services.
%%
%% Supervision Hierarchy:
%% <pre>
%% macula_root (this module - application root)
%% ├── macula_routing_server (core DHT infrastructure)
%% └── macula_gateway_system (optional - gateway subsystem)
%% ├── macula_gateway_health
%% ├── macula_gateway_diagnostics
%% ├── macula_gateway_quic_server
%% ├── macula_gateway
%% └── macula_gateway_workers_sup
%% </pre>
%%
%% Naming Convention (v0.7.10+):
%% - _root: Application root supervisor (one per application)
%% - _system: Subsystem root supervisors (gateway, peer, etc.)
%% - _sup: Worker supervisors (workers_sup)
%%
%% @end
%%%-------------------------------------------------------------------
-module(macula_root).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
-define(SERVER, ?MODULE).
start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
%% sup_flags() = #{strategy => strategy(), % optional
%% intensity => non_neg_integer(), % optional
%% period => pos_integer()} % optional
%% child_spec() = #{id => child_id(), % mandatory
%% start => mfargs(), % mandatory
%% restart => restart(), % optional
%% shutdown => shutdown(), % optional
%% type => worker(), % optional
%% modules => modules()} % optional
init([]) ->
%% Determine deployment mode
Mode = application:get_env(macula, mode, gateway),
validate_mode_config(Mode),
io:format("Starting Macula in ~p mode~n", [Mode]),
SupFlags = #{
strategy => one_for_one,
intensity => 10,
period => 5
},
%% Build child specs based on mode
CoreSpecs = get_core_child_specs(),
BootstrapSpecs = maybe_start_bootstrap(Mode),
GatewaySpecs = maybe_start_gateway(Mode),
ChildSpecs = CoreSpecs ++ BootstrapSpecs ++ GatewaySpecs,
{ok, {SupFlags, ChildSpecs}}.
%% internal functions
%% @private
%% @doc Get core infrastructure child specs (always started, even in embedded mode).
%% The routing server is essential for DHT operations in any mode.
get_core_child_specs() ->
io:format("Starting Macula core infrastructure (routing server)~n"),
[
%% DHT routing server (essential for all DHT operations)
#{
id => macula_routing_server,
start => {macula_routing_server, start_link, [get_node_id(), get_routing_config()]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [macula_routing_server]
}
].
%% @private
%% @doc Conditionally start bootstrap system based on mode.
%% Bootstrap system is started for: bootstrap, hybrid modes.
maybe_start_bootstrap(bootstrap) -> get_bootstrap_specs();
maybe_start_bootstrap(hybrid) -> get_bootstrap_specs();
maybe_start_bootstrap(_) -> [].
%% @private
%% @doc Get bootstrap system child specs.
get_bootstrap_specs() ->
Realm = get_gateway_realm(),
HealthInterval = application:get_env(macula, bootstrap_health_interval, 60000),
io:format("Starting Bootstrap System (realm: ~s, health_interval: ~pms)~n", [Realm, HealthInterval]),
[
#{
id => macula_bootstrap_system,
start => {macula_bootstrap_system, start_link, [#{
realm => Realm,
health_check_interval => HealthInterval
}]},
restart => permanent,
shutdown => infinity, % supervisor shutdown
type => supervisor,
modules => [macula_bootstrap_system]
}
].
%% @private
%% @doc Conditionally start gateway services based on mode and configuration.
%% Gateway required for: gateway, hybrid modes.
%% Can be overridden by: {start_gateway, false}.
maybe_start_gateway(Mode) ->
%% Determine if gateway should start based on mode
DefaultStartGateway = mode_requires_gateway(Mode),
StartGateway = application:get_env(macula, start_gateway, DefaultStartGateway),
case StartGateway of
true ->
%% Read gateway configuration from environment or config
Port = get_gateway_port(),
Realm = get_gateway_realm(),
HealthPort = get_health_port(),
io:format("Starting Macula Gateway on port ~p (realm: ~s)~n", [Port, Realm]),
io:format("Starting health check server on port ~p~n", [HealthPort]),
[
%% Gateway system supervisor (manages all gateway components)
#{
id => macula_gateway_system,
start => {macula_gateway_system, start_link, [[
{port, Port},
{realm, Realm},
{health_port, HealthPort}
]]},
restart => permanent,
shutdown => infinity,
type => supervisor,
modules => [macula_gateway_system]
}
];
false ->
io:format("Gateway disabled for ~p mode~n", [Mode]),
[]
end.
%% @private
%% @doc Determine if mode requires gateway by default.
mode_requires_gateway(gateway) -> true;
mode_requires_gateway(hybrid) -> true;
mode_requires_gateway(bootstrap) -> false; % Bootstrap-only, no gateway
mode_requires_gateway(edge) -> false. % Pure P2P, no gateway
%% @private
%% @doc Validate mode configuration.
%% Crashes on invalid mode to prevent misconfiguration.
validate_mode_config(Mode) ->
ValidModes = [bootstrap, edge, gateway, hybrid],
case lists:member(Mode, ValidModes) of
true -> ok;
false ->
io:format("ERROR: Invalid mode ~p. Valid modes: ~p~n", [Mode, ValidModes]),
erlang:error({invalid_mode, Mode, ValidModes})
end.
%% @private
%% @doc Get gateway port from environment variable or config.
get_gateway_port() ->
case os:getenv("GATEWAY_PORT") of
false ->
application:get_env(macula, gateway_port, 9443);
PortStr ->
list_to_integer(PortStr)
end.
%% @private
%% @doc Get gateway realm from environment variable or config.
get_gateway_realm() ->
case os:getenv("MACULA_REALM") of
false ->
application:get_env(macula, gateway_realm, <<"com.example.realm">>);
RealmStr ->
list_to_binary(RealmStr)
end.
%% @private
%% @doc Get health check port from environment variable or config.
get_health_port() ->
case os:getenv("HEALTH_PORT") of
false ->
application:get_env(macula, health_port, 8080);
PortStr ->
list_to_integer(PortStr)
end.
%% @private
%% @doc Get node ID for DHT routing (32-byte identifier).
get_node_id() ->
%% Try environment variable first, then config, finally generate one
case os:getenv("NODE_ID") of
false ->
case application:get_env(macula, node_id) of
{ok, NodeId} when is_binary(NodeId), byte_size(NodeId) == 32 ->
NodeId;
_ ->
%% Generate a random 32-byte node ID
crypto:strong_rand_bytes(32)
end;
NodeIdStr ->
list_to_binary(NodeIdStr)
end.
%% @private
%% @doc Get DHT routing configuration.
get_routing_config() ->
#{
k => application:get_env(macula, dht_k, 20), %% Kademlia K parameter
alpha => application:get_env(macula, dht_alpha, 3) %% Concurrent queries
}.