emqx/apps/emqx_gateway/src/emqx_gateway_sup.erl

183 lines
5.3 KiB
Erlang

%%--------------------------------------------------------------------
%% Copyright (c) 2021-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(emqx_gateway_sup).
-behaviour(supervisor).
-include("emqx_gateway.hrl").
-export([start_link/0]).
%% Gateway APIs
-export([
load_gateway/1,
unload_gateway/1,
lookup_gateway/1,
update_gateway/2,
start_gateway_insta/1,
stop_gateway_insta/1,
list_gateway_insta/0
]).
%% supervisor callbacks
-export([init/1]).
%%--------------------------------------------------------------------
%% APIs
%%--------------------------------------------------------------------
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
-spec load_gateway(gateway()) -> {ok, pid()} | {error, any()}.
load_gateway(Gateway = #{name := GwName}) ->
case emqx_gateway_registry:lookup(GwName) of
undefined ->
{error, {unknown_gateway_name, GwName}};
GwDscrptr ->
{ok, GwSup} = ensure_gateway_suptree_ready(GwName),
emqx_gateway_gw_sup:create_insta(GwSup, Gateway, GwDscrptr)
end.
-spec unload_gateway(gateway_name()) ->
ok
| {error, not_found}
| {error, any()}.
unload_gateway(GwName) ->
case lists:keyfind(GwName, 1, supervisor:which_children(?MODULE)) of
false ->
{error, not_found};
{_Id, Pid, _Type, _Mods} ->
_ = emqx_gateway_gw_sup:remove_insta(Pid, GwName),
_ = supervisor:terminate_child(?MODULE, GwName),
_ = supervisor:delete_child(?MODULE, GwName),
ok
end.
-spec lookup_gateway(gateway_name()) -> gateway() | undefined.
lookup_gateway(GwName) ->
case search_gateway_insta_proc(GwName) of
{ok, {_, GwInstaPid}} ->
emqx_gateway_insta_sup:info(GwInstaPid);
_ ->
undefined
end.
-spec update_gateway(gateway_name(), emqx_config:config()) ->
ok
| {error, any()}.
update_gateway(GwName, Config) ->
case emqx_gateway_utils:find_sup_child(?MODULE, GwName) of
{ok, GwSup} ->
emqx_gateway_gw_sup:update_insta(GwSup, GwName, Config);
_ ->
{error, not_found}
end.
start_gateway_insta(GwName) ->
case search_gateway_insta_proc(GwName) of
{ok, {GwSup, _}} ->
emqx_gateway_gw_sup:start_insta(GwSup, GwName);
_ ->
{error, not_found}
end.
-spec stop_gateway_insta(gateway_name()) -> ok | {error, any()}.
stop_gateway_insta(GwName) ->
case search_gateway_insta_proc(GwName) of
{ok, {GwSup, _}} ->
emqx_gateway_gw_sup:stop_insta(GwSup, GwName);
_ ->
{error, not_found}
end.
-spec list_gateway_insta() -> [gateway()].
list_gateway_insta() ->
lists:append(
lists:map(
fun(SupId) ->
emqx_gateway_gw_sup:list_insta(SupId)
end,
list_started_gateway()
)
).
-spec list_started_gateway() -> [gateway_name()].
list_started_gateway() ->
started_gateway().
%% Supervisor callback
init([]) ->
SupFlags = #{
strategy => one_for_one,
intensity => 10,
period => 60
},
ChildSpecs = [emqx_gateway_utils:childspec(worker, emqx_gateway_registry)],
{ok, {SupFlags, ChildSpecs}}.
%%--------------------------------------------------------------------
%% Internal funcs
%%--------------------------------------------------------------------
ensure_gateway_suptree_ready(GwName) ->
case lists:keyfind(GwName, 1, supervisor:which_children(?MODULE)) of
false ->
ChildSpec = emqx_gateway_utils:childspec(
GwName,
supervisor,
emqx_gateway_gw_sup,
[GwName]
),
emqx_gateway_utils:supervisor_ret(
supervisor:start_child(?MODULE, ChildSpec)
);
{_Id, Pid, _Type, _Mods} ->
{ok, Pid}
end.
search_gateway_insta_proc(InstaId) ->
search_gateway_insta_proc(InstaId, started_gateway_pid()).
search_gateway_insta_proc(_InstaId, []) ->
{error, not_found};
search_gateway_insta_proc(InstaId, [SupPid | More]) ->
case emqx_gateway_utils:find_sup_child(SupPid, InstaId) of
{ok, InstaPid} -> {ok, {SupPid, InstaPid}};
_ -> search_gateway_insta_proc(InstaId, More)
end.
started_gateway() ->
lists:filtermap(
fun({Id, _, _, _}) ->
is_a_gateway_id(Id) andalso {true, Id}
end,
supervisor:which_children(?MODULE)
).
started_gateway_pid() ->
lists:filtermap(
fun({Id, Pid, _, _}) ->
is_a_gateway_id(Id) andalso {true, Pid}
end,
supervisor:which_children(?MODULE)
).
is_a_gateway_id(Id) ->
Id /= emqx_gateway_registry.