summaryrefslogtreecommitdiff
path: root/p11p-daemon/src
diff options
context:
space:
mode:
authorLinus Nordberg <linus@sunet.se>2019-06-30 16:05:22 +0200
committerLinus Nordberg <linus@sunet.se>2019-06-30 16:05:22 +0200
commitf0afd846071e20c7a3da7911609e3ba51debd52b (patch)
treeda6552b32d11d5e04023dc242841441d741dcdc1 /p11p-daemon/src
parent9f83e6035743942b58005305f62af9bcceb52341 (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.erl2
-rw-r--r--p11p-daemon/src/p11p_remote_manager.erl89
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]).