Browse Source

Merge pull request #20 from superscale/feature/gen_server_name

Adds gen_server name registration API
Roberto Ostinelli 8 years ago
parent
commit
ad2d2f2185
4 changed files with 153 additions and 0 deletions
  1. 8 0
      README.md
  2. 32 0
      src/syn.erl
  3. 44 0
      test/syn_registry_SUITE.erl
  4. 69 0
      test/syn_test_gen_server.erl

+ 8 - 0
README.md

@@ -146,6 +146,14 @@ Types:
 > You may re-register a process multiple times, for example if you need to update its metadata.
 > You may re-register a process multiple times, for example if you need to update its metadata.
 > When a process gets registered, Syn will automatically monitor it.
 > When a process gets registered, Syn will automatically monitor it.
 
 
+Processes can also be registered as gen_server names, by usage of via-tuples.
+This way, you can use the gen_server API with these tuples without referring to the Pid directly.
+
+```erlang
+Tuple = {via, syn, <<"your process name">>}.
+gen_server:start_link(Tuple, your_module, []).
+gen_server:call(Tuple, your_message).
+```
 
 
 To retrieve a Pid from a Key:
 To retrieve a Pid from a Key:
 
 

+ 32 - 0
src/syn.erl

@@ -36,6 +36,12 @@
 -export([find_by_pid/1, find_by_pid/2]).
 -export([find_by_pid/1, find_by_pid/2]).
 -export([registry_count/0, registry_count/1]).
 -export([registry_count/0, registry_count/1]).
 
 
+%% registry for gen_server name via-tuples
+-export([register_name/2]).
+-export([unregister_name/1]).
+-export([whereis_name/1]).
+-export([send/2]).
+
 %% groups
 %% groups
 -export([join/2]).
 -export([join/2]).
 -export([leave/2]).
 -export([leave/2]).
@@ -98,6 +104,32 @@ registry_count() ->
 registry_count(Node) ->
 registry_count(Node) ->
     syn_registry:count(Node).
     syn_registry:count(Node).
 
 
+-spec register_name(Name :: term(), Pid :: pid()) -> 'yes' | 'no'.
+register_name(Name, Pid) when is_pid(Pid) ->
+    case syn_registry:register(Name, Pid) of
+      ok -> yes;
+      {error, _} -> no;
+      _ -> no
+    end.
+
+-spec unregister_name(Name :: term()) -> _.
+unregister_name(Name) ->
+    case syn_registry:unregister(Name) of
+      ok -> Name;
+      {error, _} -> nil;
+      _ -> nil
+    end.
+
+-spec whereis_name(Name :: term()) -> pid() | 'undefined'.
+whereis_name(Name) -> syn_registry:find_by_key(Name).
+
+-spec send(Name :: term(), Message :: term()) -> pid().
+send(Name, Message) ->
+    case whereis_name(Name) of
+      undefined -> {badarg, {Name, Message}};
+      Pid -> Pid ! Message, Pid
+    end.
+
 -spec join(Name :: any(), Pid :: pid()) -> ok.
 -spec join(Name :: any(), Pid :: pid()) -> ok.
 join(Name, Pid) ->
 join(Name, Pid) ->
     syn_groups:join(Name, Pid).
     syn_groups:join(Name, Pid).

+ 44 - 0
test/syn_registry_SUITE.erl

@@ -37,6 +37,7 @@
     single_node_when_mnesia_is_ram_find_by_key_with_meta/1,
     single_node_when_mnesia_is_ram_find_by_key_with_meta/1,
     single_node_when_mnesia_is_ram_find_by_pid/1,
     single_node_when_mnesia_is_ram_find_by_pid/1,
     single_node_when_mnesia_is_ram_find_by_pid_with_meta/1,
     single_node_when_mnesia_is_ram_find_by_pid_with_meta/1,
+    single_node_when_mnesia_is_ram_with_gen_server_name/1,
     single_node_when_mnesia_is_ram_re_register_error/1,
     single_node_when_mnesia_is_ram_re_register_error/1,
     single_node_when_mnesia_is_ram_unregister/1,
     single_node_when_mnesia_is_ram_unregister/1,
     single_node_when_mnesia_is_ram_process_count/1,
     single_node_when_mnesia_is_ram_process_count/1,
@@ -94,6 +95,7 @@ groups() ->
             single_node_when_mnesia_is_ram_find_by_key_with_meta,
             single_node_when_mnesia_is_ram_find_by_key_with_meta,
             single_node_when_mnesia_is_ram_find_by_pid,
             single_node_when_mnesia_is_ram_find_by_pid,
             single_node_when_mnesia_is_ram_find_by_pid_with_meta,
             single_node_when_mnesia_is_ram_find_by_pid_with_meta,
+            single_node_when_mnesia_is_ram_with_gen_server_name,
             single_node_when_mnesia_is_ram_re_register_error,
             single_node_when_mnesia_is_ram_re_register_error,
             single_node_when_mnesia_is_ram_unregister,
             single_node_when_mnesia_is_ram_unregister,
             single_node_when_mnesia_is_ram_process_count,
             single_node_when_mnesia_is_ram_process_count,
@@ -206,6 +208,48 @@ single_node_when_mnesia_is_ram_find_by_key(_Config) ->
     %% retrieve
     %% retrieve
     undefined = syn:find_by_key(<<"my proc">>).
     undefined = syn:find_by_key(<<"my proc">>).
 
 
+single_node_when_mnesia_is_ram_with_gen_server_name(_Config) ->
+    %% set schema location
+    application:set_env(mnesia, schema_location, ram),
+    %% start
+    ok = syn:start(),
+    ok = syn:init(),
+    %% retrieve
+    undefined = syn:whereis_name(<<"my proc">>),
+    %% register
+    {ok, Pid} = syn_test_gen_server:start_link(self(), {via, syn, <<"my proc">>}),
+    %% retrieve
+    Pid = syn:whereis_name(<<"my proc">>),
+    %% gen_server call messages
+    call_received = gen_server:call({via, syn, <<"my proc">>}, message_is_ignored),
+    %% gen_server cast messages
+    gen_server:cast({via, syn, <<"my proc">>}, message_is_ignored),
+    ok =
+        receive
+            cast_received -> ok
+        after
+            100 -> error
+        end,
+    %% any other message
+    syn:send(<<"my proc">>, message_is_ignored),
+    ok =
+        receive
+            info_received -> ok
+        after
+            100 -> error
+        end,
+    %% stop process
+    syn_test_gen_server:stop({via, syn, <<"my proc">>}),
+    ok =
+        receive
+            stop_received -> ok
+        after
+            100 -> error
+        end,
+    timer:sleep(100),
+    %% retrieve
+    undefined = syn:find_by_key(<<"my proc">>).
+
 single_node_when_mnesia_is_ram_find_by_key_with_meta(_Config) ->
 single_node_when_mnesia_is_ram_find_by_key_with_meta(_Config) ->
     %% set schema location
     %% set schema location
     application:set_env(mnesia, schema_location, ram),
     application:set_env(mnesia, schema_location, ram),

+ 69 - 0
test/syn_test_gen_server.erl

@@ -0,0 +1,69 @@
+%% ==========================================================================================================
+%% Syn - A global Process Registry and Process Group manager.
+%%
+%% The MIT License (MIT)
+%%
+%% Copyright (c) 2015 Roberto Ostinelli <roberto@ostinelli.net> and Neato Robotics, Inc.
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% ==========================================================================================================
+-module(syn_test_gen_server).
+
+-behaviour(gen_server).
+
+-export([start_link/2,
+         stop/1]).
+
+%% gen_server callbacks
+-export([init/1,
+         handle_call/3,
+         handle_cast/2,
+         handle_info/2,
+         terminate/2,
+         code_change/3]).
+
+start_link(Parent, Name) ->
+    gen_server:start_link(Name, ?MODULE, Parent, []).
+
+stop(Server) ->
+    gen_server:cast(Server, stop).
+
+init(State) ->
+    {ok, State}.
+
+handle_call(_Request, _From, State) ->
+    {reply, call_received, State}.
+
+handle_cast(stop, State) ->
+    State ! stop_received,
+    {stop, normal, State};
+
+handle_cast(_Msg, State) ->
+    State ! cast_received,
+    {noreply, State}.
+
+handle_info(_Info, State) ->
+    State ! info_received,
+    {noreply, State}.
+
+terminate(_Reason, _State) ->
+    ok.
+
+code_change(_OldVsn, State, _Extra) ->
+    {ok, State}.