aboutsummaryrefslogtreecommitdiffstats
path: root/src/ranch_server.erl
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2012-07-24 12:58:54 +0200
committerLoïc Hoguin <[email protected]>2012-07-25 10:05:15 +0200
commitb72fe3e67e65c66d979a9651ebc815bdc553601c (patch)
treeb6014dcc9ed930c885851d0c56b200612dc77738 /src/ranch_server.erl
parented50a5556a788a9780b5a8f85764b509338c1073 (diff)
downloadranch-b72fe3e67e65c66d979a9651ebc815bdc553601c.tar.gz
ranch-b72fe3e67e65c66d979a9651ebc815bdc553601c.tar.bz2
ranch-b72fe3e67e65c66d979a9651ebc815bdc553601c.zip
Introduce the ranch_server registry, make it handle listeners
Diffstat (limited to 'src/ranch_server.erl')
-rw-r--r--src/ranch_server.erl92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/ranch_server.erl b/src/ranch_server.erl
new file mode 100644
index 0000000..bafdeb5
--- /dev/null
+++ b/src/ranch_server.erl
@@ -0,0 +1,92 @@
+%% Copyright (c) 2012, Loïc Hoguin <[email protected]>
+%%
+%% Permission to use, copy, modify, and/or distribute this software for any
+%% purpose with or without fee is hereby granted, provided that the above
+%% copyright notice and this permission notice appear in all copies.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+%% @private
+-module(ranch_server).
+-behaviour(gen_server).
+
+%% API.
+-export([start_link/0]).
+-export([insert_listener/2]).
+-export([lookup_listener/1]).
+
+%% gen_server.
+-export([init/1]).
+-export([handle_call/3]).
+-export([handle_cast/2]).
+-export([handle_info/2]).
+-export([terminate/2]).
+-export([code_change/3]).
+
+-define(TAB, ?MODULE).
+
+-type key() :: {listener, any()}.
+-record(state, {
+ monitors = [] :: [{{reference(), pid()}, key()}]
+}).
+
+%% API.
+
+%% @doc Start the ranch_server gen_server.
+-spec start_link() -> {ok, pid()}.
+start_link() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+%% @doc Insert a listener into the database.
+-spec insert_listener(any(), pid()) -> ok.
+insert_listener(Ref, Pid) ->
+ true = ets:insert_new(?TAB, {{listener, Ref}, Pid}),
+ gen_server:cast(?MODULE, {insert_listener, Ref, Pid}).
+
+%% @doc Lookup a listener in the database.
+-spec lookup_listener(any()) -> pid().
+lookup_listener(Ref) ->
+ ets:lookup_element(?TAB, {listener, Ref}, 2).
+
+%% gen_server.
+
+%% @private
+init([]) ->
+ ?TAB = ets:new(?TAB, [
+ ordered_set, public, named_table, {read_concurrency, true}]),
+ {ok, #state{}}.
+
+%% @private
+handle_call(_Request, _From, State) ->
+ {reply, ignore, State}.
+
+%% @private
+handle_cast({insert_listener, Ref, Pid}, State=#state{monitors=Monitors}) ->
+ MonitorRef = erlang:monitor(process, Pid),
+ {noreply, State#state{
+ monitors=[{{MonitorRef, Pid}, {listener, Ref}}|Monitors]}};
+handle_cast(_Request, State) ->
+ {noreply, State}.
+
+%% @private
+handle_info({'DOWN', Ref, process, Pid, _}, State=#state{monitors=Monitors}) ->
+ {_, Key} = lists:keyfind({Ref, Pid}, 1, Monitors),
+ true = ets:delete(?TAB, Key),
+ Monitors2 = lists:keydelete({Ref, Pid}, 1, Monitors),
+ {noreply, State#state{monitors=Monitors2}};
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+%% @private
+terminate(_Reason, _State) ->
+ ok.
+
+%% @private
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.