|
@@ -18,11 +18,16 @@
|
|
|
|
|
|
%% API.
|
|
|
-export([start_link/0]).
|
|
|
--export([insert_listener/2]).
|
|
|
--export([lookup_listener/1]).
|
|
|
+-export([set_new_listener_opts/3]).
|
|
|
+-export([cleanup_listener_opts/1]).
|
|
|
-export([set_connections_sup/2]).
|
|
|
--export([lookup_connections_sup/1]).
|
|
|
--export([find_connections_sup/1]).
|
|
|
+-export([get_connections_sup/1]).
|
|
|
+-export([set_port/2]).
|
|
|
+-export([get_port/1]).
|
|
|
+-export([set_max_connections/2]).
|
|
|
+-export([get_max_connections/1]).
|
|
|
+-export([set_protocol_options/2]).
|
|
|
+-export([get_protocol_options/1]).
|
|
|
-export([count_connections/1]).
|
|
|
|
|
|
%% gen_server.
|
|
@@ -47,38 +52,63 @@
|
|
|
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, undefined}),
|
|
|
- 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).
|
|
|
+%% @private
|
|
|
+-spec set_new_listener_opts(any(), ranch:max_conns(), any()) -> ok.
|
|
|
+set_new_listener_opts(Ref, MaxConns, Opts) ->
|
|
|
+ gen_server:call(?MODULE, {set_new_listener_opts, Ref, MaxConns, Opts}).
|
|
|
+
|
|
|
+%% @doc Cleanup listener options after it has been stopped.
|
|
|
+-spec cleanup_listener_opts(any()) -> ok.
|
|
|
+cleanup_listener_opts(Ref) ->
|
|
|
+ _ = ets:delete(?TAB, {port, Ref}),
|
|
|
+ _ = ets:delete(?TAB, {max_conns, Ref}),
|
|
|
+ _ = ets:delete(?TAB, {opts, Ref}),
|
|
|
+ ok.
|
|
|
|
|
|
%% @doc Set a connection supervisor associated with specific listener.
|
|
|
-spec set_connections_sup(any(), pid()) -> ok.
|
|
|
set_connections_sup(Ref, Pid) ->
|
|
|
- true = ets:update_element(?TAB, {listener, Ref}, {3, Pid}),
|
|
|
- true = ets:insert_new(?TAB, {{conns_sup, lookup_listener(Ref)}, Pid}),
|
|
|
- ok.
|
|
|
+ gen_server:call(?MODULE, {set_connections_sup, Ref, Pid}).
|
|
|
|
|
|
-%% @doc Lookup a connection supervisor used by specific listener.
|
|
|
--spec lookup_connections_sup(any()) -> pid() | undefined.
|
|
|
-lookup_connections_sup(Ref) ->
|
|
|
- ets:lookup_element(?TAB, {listener, Ref}, 3).
|
|
|
+%% @doc Return the connection supervisor used by specific listener.
|
|
|
+-spec get_connections_sup(any()) -> pid().
|
|
|
+get_connections_sup(Ref) ->
|
|
|
+ ets:lookup_element(?TAB, {conns_sup, Ref}, 2).
|
|
|
|
|
|
-%% @doc Find a connection supervisor using the listener pid.
|
|
|
--spec find_connections_sup(pid()) -> pid().
|
|
|
-find_connections_sup(Pid) ->
|
|
|
- ets:lookup_element(?TAB, {conns_sup, Pid}, 2).
|
|
|
+%% @private
|
|
|
+-spec set_port(any(), inet:port_number()) -> ok.
|
|
|
+set_port(Ref, Port) ->
|
|
|
+ gen_server:call(?MODULE, {set_port, Ref, Port}).
|
|
|
+
|
|
|
+%% @doc Return the listener's port.
|
|
|
+-spec get_port(any()) -> inet:port_number().
|
|
|
+get_port(Ref) ->
|
|
|
+ ets:lookup_element(?TAB, {port, Ref}, 2).
|
|
|
+
|
|
|
+%% @doc Set the max number of connections allowed concurrently.
|
|
|
+-spec set_max_connections(any(), ranch:max_conns()) -> ok.
|
|
|
+set_max_connections(Ref, MaxConnections) ->
|
|
|
+ gen_server:call(?MODULE, {set_max_conns, Ref, MaxConnections}).
|
|
|
+
|
|
|
+%% @doc Return the max number of connections allowed concurrently.
|
|
|
+-spec get_max_connections(any()) -> ranch:max_conns().
|
|
|
+get_max_connections(Ref) ->
|
|
|
+ ets:lookup_element(?TAB, {max_conns, Ref}, 2).
|
|
|
+
|
|
|
+%% @doc Upgrade the protocol options.
|
|
|
+-spec set_protocol_options(any(), any()) -> ok.
|
|
|
+set_protocol_options(Ref, ProtoOpts) ->
|
|
|
+ gen_server:call(?MODULE, {set_opts, Ref, ProtoOpts}).
|
|
|
+
|
|
|
+%% @doc Return the current protocol options.
|
|
|
+-spec get_protocol_options(any()) -> any().
|
|
|
+get_protocol_options(Ref) ->
|
|
|
+ ets:lookup_element(?TAB, {opts, Ref}, 2).
|
|
|
|
|
|
%% @doc Count the number of connections in the connection pool.
|
|
|
-spec count_connections(any()) -> non_neg_integer().
|
|
|
count_connections(Ref) ->
|
|
|
- ranch_conns_sup:active_connections(lookup_connections_sup(Ref)).
|
|
|
+ ranch_conns_sup:active_connections(get_connections_sup(Ref)).
|
|
|
|
|
|
%% gen_server.
|
|
|
|
|
@@ -87,14 +117,33 @@ init([]) ->
|
|
|
{ok, #state{}}.
|
|
|
|
|
|
%% @private
|
|
|
+handle_call({set_new_listener_opts, Ref, MaxConns, Opts}, _, State) ->
|
|
|
+ ets:insert(?TAB, {{max_conns, Ref}, MaxConns}),
|
|
|
+ ets:insert(?TAB, {{opts, Ref}, Opts}),
|
|
|
+ {reply, ok, State};
|
|
|
+handle_call({set_connections_sup, Ref, Pid}, _,
|
|
|
+ State=#state{monitors=Monitors}) ->
|
|
|
+ true = ets:insert_new(?TAB, {{conns_sup, Ref}, Pid}),
|
|
|
+ MonitorRef = erlang:monitor(process, Pid),
|
|
|
+ {reply, ok, State#state{
|
|
|
+ monitors=[{{MonitorRef, Pid}, Ref}|Monitors]}};
|
|
|
+handle_call({set_port, Ref, Port}, _, State) ->
|
|
|
+ true = ets:insert(?TAB, {{port, Ref}, Port}),
|
|
|
+ {reply, ok, State};
|
|
|
+handle_call({set_max_conns, Ref, MaxConns}, _, State) ->
|
|
|
+ ets:insert(?TAB, {{max_conns, Ref}, MaxConns}),
|
|
|
+ ConnsSup = get_connections_sup(Ref),
|
|
|
+ ConnsSup ! {set_max_conns, MaxConns},
|
|
|
+ {reply, ok, State};
|
|
|
+handle_call({set_opts, Ref, Opts}, _, State) ->
|
|
|
+ ets:insert(?TAB, {{opts, Ref}, Opts}),
|
|
|
+ ConnsSup = get_connections_sup(Ref),
|
|
|
+ ConnsSup ! {set_opts, Opts},
|
|
|
+ {reply, ok, State};
|
|
|
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}, Ref}|Monitors]}};
|
|
|
handle_cast(_Request, State) ->
|
|
|
{noreply, State}.
|
|
|
|
|
@@ -102,7 +151,7 @@ handle_cast(_Request, State) ->
|
|
|
handle_info({'DOWN', MonitorRef, process, Pid, _},
|
|
|
State=#state{monitors=Monitors}) ->
|
|
|
{_, Ref} = lists:keyfind({MonitorRef, Pid}, 1, Monitors),
|
|
|
- true = ets:delete(?TAB, {listener, Ref}),
|
|
|
+ true = ets:delete(?TAB, {conns_sup, Ref}),
|
|
|
Monitors2 = lists:keydelete({MonitorRef, Pid}, 1, Monitors),
|
|
|
{noreply, State#state{monitors=Monitors2}};
|
|
|
handle_info(_Info, State) ->
|