-module(cabal_transport_sup).
-behaviour(supervisor).
-export([start_link/1, get_transport_pid/1]).
-export([init/1]).
%% Retrieve the transport worker PID from the supervisor
get_transport_pid(SupPid) ->
Children = supervisor:which_children(SupPid),
case lists:keyfind(cabal_transport, 1, Children) of
{cabal_transport, Pid, _, _} when is_pid(Pid) -> {ok, Pid};
_ -> {error, not_found}
end.
%% Start the transport supervisor with configuration
%% This uses a two-phase approach:
%% 1. Start supervisor with transport child
%% 2. Dynamically add cabal_accept_worker once we have transport PID
start_link(Args) ->
case supervisor:start_link(?MODULE, {phase1, Args}) of
{ok, SupPid} ->
%% Get the transport PID from the supervisor's children
Children = supervisor:which_children(SupPid),
Transport = lists:keyfind(cabal_transport, 1, Children),
{cabal_transport, TransportPid, worker, [cabal_transport]} = Transport,
%% Now start cabal_accept_worker with the transport PID
AcceptWorkerSpec = #{
id => cabal_accept_worker,
start => {
cabal_accept_worker,
start_link,
[
[{transport_pid, TransportPid}]
]
},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [cabal_accept_worker]
},
{ok, _AcceptWorkerPid} = supervisor:start_child(SupPid, AcceptWorkerSpec),
{ok, SupPid};
Error ->
Error
end.
%% Supervisor callback
init({phase1, Args}) ->
%% Phase 1: Start only transport
%% Accept worker will be added dynamically once we have transport PID
%% Extract configuration
ListenAddr = proplists:get_value(listen_addr, Args),
KeyPair = proplists:get_value(key_pair, Args),
EventHandler = proplists:get_value(event_handler, Args),
%% rest_for_one strategy:
%% - Transport starts first
%% - Accept worker starts second (depends on transport for listener info)
%% - If transport crashes, cabal_accept_worker restarts too (correct: listener is gone)
%% - If cabal_accept_worker crashes, transport keeps running (correct: just restart accept loop)
SupFlags = #{
strategy => rest_for_one,
intensity => 5,
period => 10
},
%% Start transport first
TransportSpec = #{
id => cabal_transport,
start =>
{cabal_transport, start_link, [
[
{listen_addr, ListenAddr},
{key_pair, KeyPair},
{event_handler, EventHandler}
]
]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [cabal_transport]
},
{ok, {SupFlags, [TransportSpec]}}.