%% -------------------------------------------------------------------
%%
%% Copyright (c) 2018 Christopher S. Meiklejohn. All Rights Reserved.
%% Copyright (c) 2022 Alejandro M. Ramallo. All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------
-module(partisan_rpc).
-include("partisan.hrl").
-type error_reason() :: timeout | any().
%% API
-export([call/4]).
-export([call/5]).
-export([prepare_opts/1]).
-dialyzer([{nowarn_function, call/4}, no_return]).
-dialyzer([{nowarn_function, call/5}, no_return]).
%% =============================================================================
%% API
%% =============================================================================
%% -----------------------------------------------------------------------------
%% @doc
%% @end
%% -----------------------------------------------------------------------------
-spec call(
Node :: node(),
Module :: module(),
Function :: atom(),
Arguments :: [any()]) -> Reply :: any() | {badrpc, error_reason()}.
call(Node, Module, Function, Arguments) ->
call(Node, Module, Function, Arguments, infinity).
%% -----------------------------------------------------------------------------
%% @doc
%% @end
%% -----------------------------------------------------------------------------
-spec call(
Node :: node(),
Module :: module(),
Function :: atom(),
Arguments :: [any()],
Timeout :: timeout() | partisan_peer_service_manager:forward_opts()) ->
Reply :: any() | {badrpc, error_reason()}.
call(Node, Module, Function, Arguments, Timeout) when ?IS_VALID_TMO(Timeout) ->
call(Node, Module, Function, Arguments, #{timeout => Timeout});
call(Node, Module, Function, Arguments, Opts) when is_list(Opts) ->
call(Node, Module, Function, Arguments, maps:from_list(Opts));
call(Node, Module, Function, Arguments, Opts0) when is_map(Opts0) ->
Self = partisan:self(),
Timeout = maps:get(timeout, Opts0, ?DEFAULT_TIMEOUT),
?IS_VALID_TMO(Timeout) orelse error({?MODULE, badarg}),
Opts = prepare_opts(
partisan_config:get(forward_options, maps:without([timeout], Opts0))
),
Msg = {call, Module, Function, Arguments, Timeout, {origin, Self}},
case partisan:forward_message(Node, partisan_rpc_backend, Msg, Opts) of
ok ->
receive
{rpc_response, Response} ->
Response
after
Timeout ->
{badrpc, timeout}
end;
{error, Reason} ->
{badrpc, Reason}
end.
%% -----------------------------------------------------------------------------
%% @doc
%% @end
%% -----------------------------------------------------------------------------
-spec prepare_opts(list() | map()) -> map().
prepare_opts(L) when is_list(L) ->
prepare_opts(maps:from_list(L));
prepare_opts(#{channel := _} = Opts) ->
Opts;
prepare_opts(Opts) when is_map(Opts) ->
Opts#{channel => ?DEFAULT_CHANNEL}.
%% =============================================================================
%% PRIVATE
%% =============================================================================