diff options
author | Linus Nordberg <linus@sunet.se> | 2019-06-30 16:05:22 +0200 |
---|---|---|
committer | Linus Nordberg <linus@sunet.se> | 2019-06-30 16:05:22 +0200 |
commit | f0afd846071e20c7a3da7911609e3ba51debd52b (patch) | |
tree | da6552b32d11d5e04023dc242841441d741dcdc1 /p11p-daemon/src | |
parent | 9f83e6035743942b58005305f62af9bcceb52341 (diff) |
start remotes on demand rather than at manager startup
Also, rotate list of remotes on remote timeout.
Still missing: When a remote times out, switch remote under the feet
of the client.
Diffstat (limited to 'p11p-daemon/src')
-rw-r--r-- | p11p-daemon/src/p11p_remote.erl | 2 | ||||
-rw-r--r-- | p11p-daemon/src/p11p_remote_manager.erl | 89 |
2 files changed, 55 insertions, 36 deletions
diff --git a/p11p-daemon/src/p11p_remote.erl b/p11p-daemon/src/p11p_remote.erl index f7bdcab..e40e2e2 100644 --- a/p11p-daemon/src/p11p_remote.erl +++ b/p11p-daemon/src/p11p_remote.erl @@ -78,7 +78,7 @@ handle_info({Port, {data, Data}}, #state{msg = Msg} = State) when Port == State# {noreply, handle_remote_data(State, Msg, Data)}; handle_info({timeout, Timer, Port}, #state{token = TokName} = State) when Port == State#state.port, Timer == State#state.timer -> lager:info("~p: rpc request timed out, exiting", [self()]), - fixme = p11p_remote_manager:timeout(TokName), + ok = p11p_remote_manager:timeout(TokName), NewState = State#state{timer = undefined}, {stop, normal, NewState}; handle_info(Info, State) -> diff --git a/p11p-daemon/src/p11p_remote_manager.erl b/p11p-daemon/src/p11p_remote_manager.erl index f5dc233..03d43e4 100644 --- a/p11p-daemon/src/p11p_remote_manager.erl +++ b/p11p-daemon/src/p11p_remote_manager.erl @@ -13,17 +13,23 @@ %% API. -export([start_link/0]). -export([remote_for_token/1]). % For servers. --export([p11init_done/1, timeout/1]). % For remotes. --export([send/2]). % Experiment +-export([timeout/1]). % 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(remote, { + tokname :: string(), + servid :: atom(), + modpath :: string(), % FIXME: filename + pid = undefined :: pid() | undefined + }). + -record(token, { - p11init_done = false :: boolean(), - remotes :: [pid()] % Active remote in hd(). + remotes :: [#remote{}], % Active remote in hd(). + replay = <<>> :: binary() }). -record(state, { @@ -38,32 +44,44 @@ start_link() -> -spec remote_for_token(string()) -> pid(). remote_for_token(TokName) -> gen_server:call(?MODULE, {remote_for_token, TokName}). -p11init_done(_Done) -> - todo. -timeout(_TokName) -> - fixme. % TODO: shift remotes - -send(TokName, Data) -> - gen_server:cast(?MODULE, {send, TokName, Data}). +timeout(TokName) -> + gen_server:call(?MODULE, {timeout, TokName}). %% Genserver callbacks. init([]) -> {ok, #state{tokens = init_tokens(p11p_config:tokens())}}. -handle_call({remote_for_token, TokName}, _From, State) -> - #{TokName := Token} = State#state.tokens, - {reply, hd(Token#token.remotes), State}; -handle_call(Request, _From, State) -> - lager:debug("Unhandled call: ~p~n", [Request]), +handle_call({remote_for_token, TokName}, _From, #state{tokens = Tokens} = State) -> + #{TokName := Token} = Tokens, + Remotes = Token#token.remotes, + #remote{tokname = TokName, servid = ServId, modpath = ModPath, pid = Pid} = Remote = hd(Remotes), + case Pid of + undefined -> + {ok, NewPid} = p11p_remote:start_link(ServId, TokName, ModPath), + NewRemote = Remote#remote{pid = NewPid}, + NewToken = Token#token{remotes = [NewRemote | tl(Remotes)]}, + NewState = State#state{tokens = Tokens#{TokName := NewToken}}, + {reply, NewPid, NewState}; + _ -> + {reply, Pid, State} + end; +handle_call({timeout, TokName}, _From, #state{tokens = Tokens} = State) -> + lager:debug("~p: ~s: timed out", [self(), TokName]), + %% TODO: do some code dedup with remote_for_token? + #{TokName := Token} = Tokens, + Remotes = Token#token.remotes, + Remote = hd(Remotes), + NewRemote = Remote#remote{pid = undefined}, + NewToken = Token#token{remotes = tl(Remotes) ++ [NewRemote]}, + NewState = State#state{tokens = Tokens#{TokName := NewToken}}, + lager:debug("~p: ~s: updated token: ~p", [self(), TokName, NewToken]), + {reply, ok, NewState}; +handle_call(Call, _From, State) -> + lager:debug("Unhandled call: ~p~n", [Call]), {reply, unhandled, State}. -handle_cast({send, TokName, Data}, State) -> - #{TokName := Token} = State#state.tokens, - ServerPort = hd(Token#token.remotes), - ServerPort ! {self(), {command, Data}}, % TODO: Use synchronous port_command()? - {noreply, State}; -handle_cast(Request, State) -> - lager:debug("Unhandled cast: ~p~n", [Request]), +handle_cast(Cast, State) -> + lager:debug("Unhandled cast: ~p~n", [Cast]), {noreply, State}. handle_info({Port, {exit_status, Status}}, State) -> @@ -84,25 +102,26 @@ code_change(_OldVersion, State, _Extra) -> init_tokens(ConfTokens) -> init_tokens(ConfTokens, #{}). init_tokens([], Acc)-> + lager:debug("~p: created tokens from config: ~p", [self(), Acc]), Acc; init_tokens([H|T], Acc)-> TokName = p11p_config:nameof(H), init_tokens(T, Acc#{TokName => new_token(TokName, H)}). new_token(TokName, ConfToken) -> - %% TODO: This approach is too static. Instead of storing pids - %% here, let remote genservers register with us in their init/1. - Remotes = start_remotes(TokName, p11p_config:modules_for_token(p11p_config:nameof(ConfToken))), - #token{remotes = Remotes}. - -start_remotes(TokName, ConfModules) -> - start_remotes(TokName, ConfModules, []). -start_remotes(_, [], Acc) -> - %%lists:reverse(Acc); + #token{remotes = remotes(TokName, p11p_config:modules_for_token(p11p_config:nameof(ConfToken)))}. + +remotes(TokName, ConfModules) -> + remotes(TokName, ConfModules, []). +remotes(_, [], Acc) -> Acc; -start_remotes(TokName, [H|T], Acc) -> +remotes(TokName, [H|T], Acc) -> ModName = p11p_config:nameof(H), ServName = "p11p_remote:" ++ TokName ++ ":" ++ ModName, ModPath = p11p_config:module_path(H), - {ok, Pid} = p11p_remote:start_link(list_to_atom(ServName), TokName, ModPath), - start_remotes(TokName, T, [Pid | Acc]). + remotes(TokName, T, [#remote{ + tokname = TokName, + servid = list_to_atom(ServName), + modpath = ModPath, + pid = undefined + } | Acc]). |