Packages

macula

0.8.13
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_gateway_system macula_gateway_system.erl
Raw

src/macula_gateway_system/macula_gateway_system.erl

%%%-------------------------------------------------------------------
%%% @doc
%%% Gateway Root Supervisor - top-level supervisor for gateway subsystem.
%%%
%%% Supervision Strategy:
%%% - rest_for_one: Dependency-based restart ordering
%%% - Child order reflects dependencies:
%%% 1. quic_server (owns QUIC listener, no dependencies)
%%% 2. gateway (depends on quic_server PID)
%%% 3. workers_sup (depends on gateway PID)
%%%
%%% Fault Isolation:
%%% - quic_server crash → restart quic_server, gateway, workers_sup
%%% - gateway crash → restart gateway, workers_sup (quic_server continues)
%%% - workers_sup crash → restart workers_sup only (quic_server and gateway continue)
%%%
%%% Architecture:
%%% <pre>
%%% macula_gateway_system (this module)
%%% ├── macula_gateway_health - Health check HTTP server
%%% ├── macula_gateway_diagnostics - Diagnostics service
%%% ├── macula_gateway_quic_server - QUIC transport layer
%%% ├── macula_gateway - Message routing coordinator
%%% └── macula_gateway_workers_sup - Business logic workers
%%% ├── macula_gateway_clients - Client tracking
%%% ├── macula_gateway_pubsub - Pub/Sub routing
%%% ├── macula_gateway_rpc - RPC handling
%%% └── macula_gateway_mesh - Mesh connections
%%% </pre>
%%%
%%% Circular Dependency Resolution:
%%% - quic_server starts first (without gateway PID)
%%% - gateway starts second (receives quic_server PID)
%%% - Supervisor calls quic_server:set_gateway/1 to complete link
%%% - workers_sup starts last (receives gateway PID)
%%%
%%% Created during Phase 2 QUIC refactoring to enable proper OTP supervision.
%%% @end
%%%-------------------------------------------------------------------
-module(macula_gateway_system).
-behaviour(supervisor).
%% API
-export([start_link/1]).
%% Supervisor callbacks
-export([init/1]).
%%%===================================================================
%%% API
%%%===================================================================
%% @doc Start the root gateway supervisor with configuration.
-spec start_link(proplists:proplist()) -> {ok, pid()} | {error, term()}.
start_link(Opts) ->
supervisor:start_link(?MODULE, Opts).
%%%===================================================================
%%% Supervisor callbacks
%%%===================================================================
init(Opts) when is_list(Opts) ->
%% Called with proplist (legacy tests, application startup)
Port = proplists:get_value(port, Opts, 9443),
Realm = proplists:get_value(realm, Opts, <<"macula.default">>),
HealthPort = proplists:get_value(health_port, Opts, 8080),
CertFile = get_cert_file(proplists:get_value(cert_file, Opts)),
KeyFile = get_key_file(proplists:get_value(key_file, Opts)),
init_supervisor(Port, Realm, HealthPort, CertFile, KeyFile);
init(Opts) when is_map(Opts) ->
%% Called with map (new style)
Port = maps:get(port, Opts, 9443),
Realm = maps:get(realm, Opts, <<"macula.default">>),
HealthPort = maps:get(health_port, Opts, 8080),
CertFile = get_cert_file(maps:get(cert_file, Opts, undefined)),
KeyFile = get_key_file(maps:get(key_file, Opts, undefined)),
init_supervisor(Port, Realm, HealthPort, CertFile, KeyFile).
%% @private
%% @doc Initialize the supervisor with extracted configuration.
init_supervisor(Port, Realm, HealthPort, CertFile, KeyFile) ->
io:format("[GatewaySup] Initializing gateway supervisor for realm ~s on port ~p~n",
[Realm, Port]),
io:format("[GatewaySup] Certificate file: ~p~n", [CertFile]),
io:format("[GatewaySup] Key file: ~p~n", [KeyFile]),
%% Supervision strategy: rest_for_one
%% - health fails → restart health, diagnostics, quic_server, gateway, workers_sup
%% - diagnostics fails → restart diagnostics, quic_server, gateway, workers_sup
%% - quic_server fails → restart quic_server, gateway, workers_sup
%% - gateway fails → restart gateway, workers_sup
%% - workers_sup fails → restart workers_sup only
SupFlags = #{
strategy => rest_for_one,
intensity => 10,
period => 60
},
%% Child 1: Health Check Server
HealthSpec = #{
id => macula_gateway_health,
start => {macula_gateway_health, start_link, [[{health_port, HealthPort}]]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [macula_gateway_health]
},
%% Child 2: Diagnostics Service
DiagnosticsSpec = #{
id => macula_gateway_diagnostics,
start => {macula_gateway_diagnostics, start_link, [[{realm, Realm}]]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [macula_gateway_diagnostics]
},
%% Child 3: QUIC Server (starts without gateway PID)
QuicServerSpec = #{
id => macula_gateway_quic_server,
start => {macula_gateway_quic_server, start_link, [[
{port, Port},
{realm, Realm},
{cert_file, CertFile},
{key_file, KeyFile}
%% Note: NO gateway PID yet!
]]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [macula_gateway_quic_server]
},
%% Child 4: Gateway (receives quic_server PID after it starts)
GatewaySpec = #{
id => macula_gateway,
start => {macula_gateway, start_link, [[
{port, Port},
{realm, Realm}
%% Note: Gateway will find quic_server via supervisor
]]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [macula_gateway]
},
%% Child 5: Workers Supervisor (supervises business logic workers)
WorkersSupSpec = #{
id => macula_gateway_workers_sup,
start => {macula_gateway_workers_sup, start_link, [#{
port => Port,
realm => Realm
}]},
restart => permanent,
shutdown => infinity, % supervisor shutdown
type => supervisor,
modules => [macula_gateway_workers_sup]
},
Children = [HealthSpec, DiagnosticsSpec, QuicServerSpec, GatewaySpec, WorkersSupSpec],
{ok, {SupFlags, Children}}.
%%%===================================================================
%%% Private helper functions
%%%===================================================================
%% @private
%% @doc Get certificate file path from opts or OS environment variable.
%% Falls back to TLS_CERT_FILE environment variable when not provided in opts.
get_cert_file(undefined) ->
case os:getenv("TLS_CERT_FILE") of
false -> "/opt/macula/certs/cert.pem"; % Default fallback
CertFile -> CertFile
end;
get_cert_file(CertFile) when is_list(CertFile) ->
CertFile.
%% @private
%% @doc Get key file path from opts or OS environment variable.
%% Falls back to TLS_KEY_FILE environment variable when not provided in opts.
get_key_file(undefined) ->
case os:getenv("TLS_KEY_FILE") of
false -> "/opt/macula/certs/key.pem"; % Default fallback
KeyFile -> KeyFile
end;
get_key_file(KeyFile) when is_list(KeyFile) ->
KeyFile.