119 lines
3.9 KiB
Erlang
119 lines
3.9 KiB
Erlang
%%--------------------------------------------------------------------
|
|
%% Copyright (c) 2020-2021 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_exhook).
|
|
|
|
-include("emqx_exhook.hrl").
|
|
-include_lib("emqx/include/logger.hrl").
|
|
|
|
-logger_header("[ExHook]").
|
|
|
|
-export([ enable/1
|
|
, disable/1
|
|
, list/0
|
|
]).
|
|
|
|
-export([ cast/2
|
|
, call_fold/3
|
|
]).
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% Mgmt APIs
|
|
%%--------------------------------------------------------------------
|
|
|
|
-spec enable(atom()|string()) -> ok | {error, term()}.
|
|
enable(Name) ->
|
|
with_mngr(fun(Pid) -> emqx_exhook_mngr:enable(Pid, Name) end).
|
|
|
|
-spec disable(atom()|string()) -> ok | {error, term()}.
|
|
disable(Name) ->
|
|
with_mngr(fun(Pid) -> emqx_exhook_mngr:disable(Pid, Name) end).
|
|
|
|
-spec list() -> [atom() | string()].
|
|
list() ->
|
|
with_mngr(fun(Pid) -> emqx_exhook_mngr:list(Pid) end).
|
|
|
|
with_mngr(Fun) ->
|
|
case lists:keyfind(emqx_exhook_mngr, 1,
|
|
supervisor:which_children(emqx_exhook_sup)) of
|
|
{_, Pid, _, _} ->
|
|
Fun(Pid);
|
|
_ ->
|
|
{error, no_manager_svr}
|
|
end.
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% Dispatch APIs
|
|
%%--------------------------------------------------------------------
|
|
|
|
-spec cast(atom(), map()) -> ok.
|
|
cast(Hookpoint, Req) ->
|
|
cast(Hookpoint, Req, emqx_exhook_mngr:running()).
|
|
|
|
cast(_, _, []) ->
|
|
ok;
|
|
cast(Hookpoint, Req, [ServerName|More]) ->
|
|
%% XXX: Need a real asynchronous running
|
|
_ = emqx_exhook_server:call(Hookpoint, Req,
|
|
emqx_exhook_mngr:server(ServerName)),
|
|
cast(Hookpoint, Req, More).
|
|
|
|
-spec call_fold(atom(), term(), function())
|
|
-> {ok, term()}
|
|
| {stop, term()}.
|
|
call_fold(Hookpoint, Req, AccFun) ->
|
|
FailedAction = emqx_exhook_mngr:get_request_failed_action(),
|
|
ServerNames = emqx_exhook_mngr:running(),
|
|
case ServerNames == [] andalso FailedAction == deny of
|
|
true ->
|
|
{stop, deny_action_result(Hookpoint, Req)};
|
|
_ ->
|
|
call_fold(Hookpoint, Req, FailedAction, AccFun, ServerNames)
|
|
end.
|
|
|
|
call_fold(_, Req, _, _, []) ->
|
|
{ok, Req};
|
|
call_fold(Hookpoint, Req, FailedAction, AccFun, [ServerName|More]) ->
|
|
Server = emqx_exhook_mngr:server(ServerName),
|
|
case emqx_exhook_server:call(Hookpoint, Req, Server) of
|
|
{ok, Resp} ->
|
|
case AccFun(Req, Resp) of
|
|
{stop, NReq} ->
|
|
{stop, NReq};
|
|
{ok, NReq} ->
|
|
call_fold(Hookpoint, NReq, FailedAction, AccFun, More);
|
|
_ ->
|
|
call_fold(Hookpoint, Req, FailedAction, AccFun, More)
|
|
end;
|
|
_ ->
|
|
case FailedAction of
|
|
deny ->
|
|
{stop, deny_action_result(Hookpoint, Req)};
|
|
_ ->
|
|
call_fold(Hookpoint, Req, FailedAction, AccFun, More)
|
|
end
|
|
end.
|
|
|
|
%% XXX: Hard-coded the deny response
|
|
deny_action_result('client.authenticate', _) ->
|
|
#{result => false};
|
|
deny_action_result('client.check_acl', _) ->
|
|
#{result => false};
|
|
deny_action_result('message.publish', Msg) ->
|
|
%% TODO: Not support to deny a message
|
|
%% maybe we can put the 'allow_publish' into message header
|
|
Msg.
|