blob: 755a6e59faf648139744eff54f29fc0ae54a0898 [file] [log] [blame]
%% @copyright 2014, Takeru Ohta <phjgt308@gmail.com>
%%
%% @doc A Local Name Registration Facility
-module(local).
%%----------------------------------------------------------------------------------------------------------------------
%% Exported API
%%----------------------------------------------------------------------------------------------------------------------
-export([start_name_server/1]).
-export([stop_name_server/1]).
-export([which_name_servers/0]).
-export([register_name/2]).
-export([unregister_name/1]).
-export([whereis_name/1]).
-export([send/2]).
-export([which_processes/1, which_processes/2]).
-export([name_server_child_spec/1, name_server_child_spec/3]).
-export([otp_name/1]).
-export_type([name/0]).
-export_type([name_server_name/0]).
-export_type([process_name/0]).
-export_type([otp_name/0]).
-export_type([otp_ref/0]).
%%----------------------------------------------------------------------------------------------------------------------
%% Macros & Types
%%----------------------------------------------------------------------------------------------------------------------
-type name() :: {name_server_name(), process_name()}.
-type name_server_name() :: atom().
-type process_name() :: term().
-type otp_name() :: {local, Name :: atom()}
| {global, Name :: term()}
| {via, module(), Name :: term()}.
-type otp_ref() :: (Name :: atom())
| {Name :: atom(), node()}
| {global, Name :: term()}
| {via, module(), Name :: term()}
| pid().
%%----------------------------------------------------------------------------------------------------------------------
%% Exported Functions
%%----------------------------------------------------------------------------------------------------------------------
%% @doc Starts a name server process
%%
%% The process is registered locally as `ServerName' using `register/2'.
%%
%% If the process is successfully started the function returns `ok'.
%%
%% If there already exists a process with the specified `ServerName' the function returnes `{error, already_present}'.
-spec start_name_server(name_server_name()) -> ok | {error, Reason} when
Reason :: already_present.
start_name_server(ServerName) when is_atom(ServerName) ->
local_sup:start_name_server(ServerName);
start_name_server(ServerName) -> error(badarg, [ServerName]).
%% @doc Stops the name server `ServerName'
%%
%% If successful, the function returns `ok'.
%% If the name server identified by `ServerName' does not exist, the function returns `{error, not_found}'.
-spec stop_name_server(name_server_name()) -> ok | {error, Reason} when
Reason :: not_found.
stop_name_server(ServerName) when is_atom(ServerName) ->
local_sup:stop_name_server(ServerName);
stop_name_server(ServerName) -> error(badarg, [ServerName]).
%% @doc Returns a list of running name server
-spec which_name_servers() -> [name_server_name()].
which_name_servers() ->
local_sup:which_name_servers().
%% @doc Locally assocates the name `Name' with a pid `Pid'.
%%
%% Let `NameServer' is `element(1, Name)', the registered name is limited to the name server `NameServer' scope.
%%
%% Assumes that the name server is already started, crashes otherwise.
%%
%% The function returns `yes' if successful, `no' if it failes.
%% For example, `no' is returned if an attempt is made to register an already registered process or
%% to register a process with a name that is already in use.
-spec register_name(Name :: name(), Pid :: pid()) -> yes | no.
register_name({NameServer, ProcName}, Pid) when is_atom(NameServer), is_pid(Pid) ->
local_name_server:register_name(NameServer, ProcName, Pid);
register_name(Name, Pid) -> error(badarg, [Name, Pid]).
%% @doc Removes the locally registered name `Name'
-spec unregister_name(Name :: name()) -> ok.
unregister_name({NameServer, ProcName}) when is_atom(NameServer) ->
local_name_server:unregister_name(NameServer, ProcName);
unregister_name(Name) -> error(badarg, [Name]).
%% @doc Returns the pid with the locally registered name `Name'
%%
%% Returns `undefined' if the name is not locally registered.
-spec whereis_name(name()) -> pid() | undefined.
whereis_name({NameServer, ProcName}) when is_atom(NameServer) ->
local_name_server:whereis_name(NameServer, ProcName);
whereis_name(Name) -> error(badarg, [Name]).
%% @doc Sends the message `Msg' to the pid locally registered as `Name'
%%
%% Failure: If `Name' is not a locally registered name, the calling function will exit with reason `{badarg, {Name, Msg}}'
-spec send(name(), term()) -> pid().
send(Name, Msg) ->
case whereis_name(Name) of
undefined -> error({badarg, {Name, Msg}});
Pid -> _ = Pid ! Msg, Pid
end.
%% @doc Returns a list of registered process
-spec which_processes(name_server_name()) -> [{process_name(), pid()}].
which_processes(NameServer) ->
local_name_server:which_processes(NameServer).
%% @doc Returns a list of registered process that has a name which matches the pattern `Pattern'
-spec which_processes(name_server_name(), ets:match_pattern()) -> [{process_name(), pid()}].
which_processes(NameServer, ProcNamePattern) ->
local_name_server:which_processes(NameServer, ProcNamePattern).
%% @equiv name_server_child_spec(Name, Name, 5000)
-spec name_server_child_spec(name_server_name()) -> supervisor:child_spec().
name_server_child_spec(Name) ->
name_server_child_spec(Name, Name, 5000).
%% @doc Returns the child spec for a local name server that is used in embedded mode.
%%
%% To embed a local name server in your application, you can simply add `ChildSpec' to your supervision tree.
-spec name_server_child_spec(ChildId, ServerName, Shutdown) -> ChildSpec when
ChildId :: term(),
ServerName :: name_server_name(),
Shutdown :: brutal_kill | timeout(),
ChildSpec :: supervisor:child_spec().
name_server_child_spec(ChildId, ServerName, Shutdown) when is_atom(ServerName) ->
{ChildId, {local_name_server, start_link, [ServerName]}, permanent, Shutdown, worker, [local_name_server]};
name_server_child_spec(ChildId, ServerName, Shutdown) ->
error(badarg, [ChildId, ServerName, Shutdown]).
%% @doc Returns OTP compatible name
-spec otp_name(name()) -> otp_name().
otp_name(Name) ->
{via, local, Name}.