Current section

Files

Jump to
macula_rpc src macula_rpc_discovery.erl
Raw

src/macula_rpc_discovery.erl

%%%-------------------------------------------------------------------
%%% @doc
%%% DHT integration for finding RPC service providers.
%%% Uses Kademlia DHT to publish and discover RPC registrations.
%%% @end
%%%-------------------------------------------------------------------
-module(macula_rpc_discovery).
%% API
-export([
find_providers/2,
announce_registration/5,
remove_registration/3,
filter_available/2
]).
%% Types
-type uri() :: binary().
-type node_id() :: binary().
-type address() :: {inet:ip_address(), inet:port_number()}.
-type provider_info() :: #{
node_id := node_id(),
address := address(),
metadata := map(),
last_seen := integer()
}.
-type dht_lookup_fun() :: fun((uri()) -> {ok, [provider_info()]} | {error, term()}).
-type dht_publish_fun() :: fun((uri(), node_id(), address(), map()) -> ok | {error, term()}).
-type dht_unpublish_fun() :: fun((uri(), node_id()) -> ok | {error, term()}).
-export_type([
uri/0,
node_id/0,
address/0,
provider_info/0,
dht_lookup_fun/0,
dht_publish_fun/0,
dht_unpublish_fun/0
]).
%%%===================================================================
%%% API Functions
%%%===================================================================
%% @doc Find service providers for a URI via DHT.
-spec find_providers(uri(), dht_lookup_fun()) -> {ok, [provider_info()]} | {error, term()}.
find_providers(Uri, DhtLookupFun) ->
DhtLookupFun(Uri).
%% @doc Announce local registration to DHT.
-spec announce_registration(uri(), node_id(), address(), map(), dht_publish_fun()) ->
ok | {error, term()}.
announce_registration(Uri, LocalNodeId, LocalAddress, Metadata, DhtPublishFun) ->
DhtPublishFun(Uri, LocalNodeId, LocalAddress, Metadata).
%% @doc Remove local registration from DHT.
-spec remove_registration(uri(), node_id(), dht_unpublish_fun()) -> ok | {error, term()}.
remove_registration(Uri, LocalNodeId, DhtUnpublishFun) ->
DhtUnpublishFun(Uri, LocalNodeId).
%% @doc Filter providers to only available ones (based on last_seen TTL).
-spec filter_available([provider_info()], pos_integer()) -> [provider_info()].
filter_available(Providers, TTL) ->
Now = erlang:system_time(millisecond),
MaxAge = TTL * 1000, % TTL in seconds, convert to milliseconds
lists:filter(
fun(Provider) ->
LastSeen = maps:get(last_seen, Provider),
Age = Now - LastSeen,
Age =< MaxAge
end,
Providers
).