%% A remote manager is a gen_server for coordination of remotes for %% all tokens. %% Spawn one remote per configured p11p module per configured virtual %% token. Provide a lookup service for servers that need a remote to %% send a request to, by keeping track of which module is current for %% a given vtoken. -module(p11p_remote_manager). -behaviour(gen_server). %% API. -export([start_link/0]). -export([port_for_token/1]). % For servers. -export([p11init_done/1, timeout/0]). % For remotes. %% Genserver callbacks. -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). %% Records and types. -record(token, { p11init_done = false :: boolean(), remotes :: [port()] % Active remote in hd(). }). -record(state, { tokens :: #{string() => #token{}} }). -define(P11KITREMOTE_PATH, "/home/linus/usr/libexec/p11-kit/p11-kit-remote"). %% API implementation. -spec start_link() -> {ok, pid()} | {error, term()}. start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). port_for_token(_Token) -> todo. p11init_done(_Done) -> todo. timeout() -> todo. %% Genserver callbacks. init([]) -> {ok, #state{tokens = init_tokens(p11p_config:tokens())}}. handle_call(Request, _From, State) -> lager:debug("Unhandled call: ~p~n", [Request]), {reply, unhandled, State}. handle_cast(Request, State) -> lager:debug("Unhandled cast: ~p~n", [Request]), {noreply, State}. handle_info({Port, {exit_status, Status}}, State) -> lager:info("~p: process exited with ~p", [Port, Status]), {stop, child_exit, State}; handle_info(Info, State) -> lager:debug("Unhandled info: ~p~n", [Info]), {noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVersion, State, _Extra) -> {ok, State}. %% Private functions -spec init_tokens([any()]) -> #{string() => #token{}}. init_tokens(ConfTokens) -> init_tokens(ConfTokens, #{}). init_tokens([], Acc)-> Acc; init_tokens([H|T], Acc)-> init_tokens(T, Acc#{p11p_config:nameof(H) => new_token(H)}). new_token(ConfToken) -> Remotes = start_remotes(p11p_config:modules_for_token(p11p_config:nameof(ConfToken))), #token{remotes = Remotes}. start_remotes(ConfModules) -> start_remotes(ConfModules, []). start_remotes([], Acc) -> lists:reverse(Acc); start_remotes([H|T], Acc) -> ModPath = p11p_config:module_path(H), Port = start_remote(ModPath), start_remotes(T, [Port | Acc]). start_remote(ModPath) -> Port = open_port({spawn_executable, ?P11KITREMOTE_PATH}, [stream, exit_status, {args, [ModPath, "-v"]}]), lager:debug("~s: New port: ~p", [?P11KITREMOTE_PATH, Port]), Port.