|
@@ -33,6 +33,9 @@
|
|
|
%% API callbacks
|
|
%% API callbacks
|
|
|
-export(['/rule_events'/2, '/rule_test'/2, '/rules'/2, '/rules/:id'/2, '/rules/:id/reset_metrics'/2]).
|
|
-export(['/rule_events'/2, '/rule_test'/2, '/rules'/2, '/rules/:id'/2, '/rules/:id/reset_metrics'/2]).
|
|
|
|
|
|
|
|
|
|
+%% query callback
|
|
|
|
|
+-export([query/4]).
|
|
|
|
|
+
|
|
|
-define(ERR_NO_RULE(ID), list_to_binary(io_lib:format("Rule ~ts Not Found", [(ID)]))).
|
|
-define(ERR_NO_RULE(ID), list_to_binary(io_lib:format("Rule ~ts Not Found", [(ID)]))).
|
|
|
-define(ERR_BADARGS(REASON), begin
|
|
-define(ERR_BADARGS(REASON), begin
|
|
|
R0 = err_msg(REASON),
|
|
R0 = err_msg(REASON),
|
|
@@ -109,6 +112,15 @@ end).
|
|
|
}
|
|
}
|
|
|
).
|
|
).
|
|
|
|
|
|
|
|
|
|
+-define(RULE_QS_SCHEMA, [
|
|
|
|
|
+ {<<"enable">>, atom},
|
|
|
|
|
+ {<<"from">>, binary},
|
|
|
|
|
+ {<<"like_id">>, binary},
|
|
|
|
|
+ {<<"like_from">>, binary},
|
|
|
|
|
+ {<<"match_from">>, binary},
|
|
|
|
|
+ {<<"like_description">>, binary}
|
|
|
|
|
+]).
|
|
|
|
|
+
|
|
|
namespace() -> "rule".
|
|
namespace() -> "rule".
|
|
|
|
|
|
|
|
api_spec() ->
|
|
api_spec() ->
|
|
@@ -134,9 +146,31 @@ schema("/rules") ->
|
|
|
get => #{
|
|
get => #{
|
|
|
tags => [<<"rules">>],
|
|
tags => [<<"rules">>],
|
|
|
description => ?DESC("api1"),
|
|
description => ?DESC("api1"),
|
|
|
|
|
+ parameters => [
|
|
|
|
|
+ {enable,
|
|
|
|
|
+ mk(boolean(), #{desc => ?DESC("api1_enable"), in => query, required => false})},
|
|
|
|
|
+ {from, mk(binary(), #{desc => ?DESC("api1_from"), in => query, required => false})},
|
|
|
|
|
+ {like_id,
|
|
|
|
|
+ mk(binary(), #{desc => ?DESC("api1_like_id"), in => query, required => false})},
|
|
|
|
|
+ {like_from,
|
|
|
|
|
+ mk(binary(), #{desc => ?DESC("api1_like_from"), in => query, required => false})},
|
|
|
|
|
+ {like_description,
|
|
|
|
|
+ mk(binary(), #{
|
|
|
|
|
+ desc => ?DESC("api1_like_description"), in => query, required => false
|
|
|
|
|
+ })},
|
|
|
|
|
+ {match_from,
|
|
|
|
|
+ mk(binary(), #{desc => ?DESC("api1_match_from"), in => query, required => false})},
|
|
|
|
|
+ ref(emqx_dashboard_swagger, page),
|
|
|
|
|
+ ref(emqx_dashboard_swagger, limit)
|
|
|
|
|
+ ],
|
|
|
summary => <<"List Rules">>,
|
|
summary => <<"List Rules">>,
|
|
|
responses => #{
|
|
responses => #{
|
|
|
- 200 => mk(array(rule_info_schema()), #{desc => ?DESC("desc9")})
|
|
|
|
|
|
|
+ 200 =>
|
|
|
|
|
+ [
|
|
|
|
|
+ {data, mk(array(rule_info_schema()), #{desc => ?DESC("desc9")})},
|
|
|
|
|
+ {meta, mk(ref(emqx_dashboard_swagger, meta), #{})}
|
|
|
|
|
+ ],
|
|
|
|
|
+ 400 => error_schema('BAD_REQUEST', "Invalid Parameters")
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
post => #{
|
|
post => #{
|
|
@@ -236,9 +270,21 @@ param_path_id() ->
|
|
|
'/rule_events'(get, _Params) ->
|
|
'/rule_events'(get, _Params) ->
|
|
|
{200, emqx_rule_events:event_info()}.
|
|
{200, emqx_rule_events:event_info()}.
|
|
|
|
|
|
|
|
-'/rules'(get, _Params) ->
|
|
|
|
|
- Records = emqx_rule_engine:get_rules_ordered_by_ts(),
|
|
|
|
|
- {200, format_rule_resp(Records)};
|
|
|
|
|
|
|
+'/rules'(get, #{query_string := QueryString}) ->
|
|
|
|
|
+ case
|
|
|
|
|
+ emqx_mgmt_api:node_query(
|
|
|
|
|
+ node(),
|
|
|
|
|
+ QueryString,
|
|
|
|
|
+ ?RULE_TAB,
|
|
|
|
|
+ ?RULE_QS_SCHEMA,
|
|
|
|
|
+ {?MODULE, query}
|
|
|
|
|
+ )
|
|
|
|
|
+ of
|
|
|
|
|
+ {error, page_limit_invalid} ->
|
|
|
|
|
+ {400, #{code => 'BAD_REQUEST', message => <<"page_limit_invalid">>}};
|
|
|
|
|
+ Result ->
|
|
|
|
|
+ {200, Result}
|
|
|
|
|
+ end;
|
|
|
'/rules'(post, #{body := Params0}) ->
|
|
'/rules'(post, #{body := Params0}) ->
|
|
|
case maps:get(<<"id">>, Params0, list_to_binary(emqx_misc:gen_id(8))) of
|
|
case maps:get(<<"id">>, Params0, list_to_binary(emqx_misc:gen_id(8))) of
|
|
|
<<>> ->
|
|
<<>> ->
|
|
@@ -335,6 +381,8 @@ err_msg(Msg) -> emqx_misc:readable_error_msg(Msg).
|
|
|
|
|
|
|
|
format_rule_resp(Rules) when is_list(Rules) ->
|
|
format_rule_resp(Rules) when is_list(Rules) ->
|
|
|
[format_rule_resp(R) || R <- Rules];
|
|
[format_rule_resp(R) || R <- Rules];
|
|
|
|
|
+format_rule_resp({Id, Rule}) ->
|
|
|
|
|
+ format_rule_resp(Rule#{id => Id});
|
|
|
format_rule_resp(#{
|
|
format_rule_resp(#{
|
|
|
id := Id,
|
|
id := Id,
|
|
|
name := Name,
|
|
name := Name,
|
|
@@ -503,3 +551,51 @@ filter_out_request_body(Conf) ->
|
|
|
<<"node">>
|
|
<<"node">>
|
|
|
],
|
|
],
|
|
|
maps:without(ExtraConfs, Conf).
|
|
maps:without(ExtraConfs, Conf).
|
|
|
|
|
+
|
|
|
|
|
+query(Tab, {Qs, Fuzzy}, Start, Limit) ->
|
|
|
|
|
+ Ms = qs2ms(),
|
|
|
|
|
+ FuzzyFun = fuzzy_match_fun(Qs, Ms, Fuzzy),
|
|
|
|
|
+ emqx_mgmt_api:select_table_with_count(
|
|
|
|
|
+ Tab, {Ms, FuzzyFun}, Start, Limit, fun format_rule_resp/1
|
|
|
|
|
+ ).
|
|
|
|
|
+
|
|
|
|
|
+%% rule is not a record, so everything is fuzzy filter.
|
|
|
|
|
+qs2ms() ->
|
|
|
|
|
+ [{'_', [], ['$_']}].
|
|
|
|
|
+
|
|
|
|
|
+fuzzy_match_fun(Qs, Ms, Fuzzy) ->
|
|
|
|
|
+ MsC = ets:match_spec_compile(Ms),
|
|
|
|
|
+ fun(Rows) ->
|
|
|
|
|
+ Ls = ets:match_spec_run(Rows, MsC),
|
|
|
|
|
+ lists:filter(
|
|
|
|
|
+ fun(E) ->
|
|
|
|
|
+ run_qs_match(E, Qs) andalso
|
|
|
|
|
+ run_fuzzy_match(E, Fuzzy)
|
|
|
|
|
+ end,
|
|
|
|
|
+ Ls
|
|
|
|
|
+ )
|
|
|
|
|
+ end.
|
|
|
|
|
+
|
|
|
|
|
+run_qs_match(_, []) ->
|
|
|
|
|
+ true;
|
|
|
|
|
+run_qs_match(E = {_Id, #{enable := Enable}}, [{enable, '=:=', Pattern} | Qs]) ->
|
|
|
|
|
+ Enable =:= Pattern andalso run_qs_match(E, Qs);
|
|
|
|
|
+run_qs_match(E = {_Id, #{from := From}}, [{from, '=:=', Pattern} | Qs]) ->
|
|
|
|
|
+ lists:member(Pattern, From) andalso run_qs_match(E, Qs);
|
|
|
|
|
+run_qs_match(E, [_ | Qs]) ->
|
|
|
|
|
+ run_qs_match(E, Qs).
|
|
|
|
|
+
|
|
|
|
|
+run_fuzzy_match(_, []) ->
|
|
|
|
|
+ true;
|
|
|
|
|
+run_fuzzy_match(E = {Id, _}, [{id, like, Pattern} | Fuzzy]) ->
|
|
|
|
|
+ binary:match(Id, Pattern) /= nomatch andalso run_fuzzy_match(E, Fuzzy);
|
|
|
|
|
+run_fuzzy_match(E = {_Id, #{description := Desc}}, [{description, like, Pattern} | Fuzzy]) ->
|
|
|
|
|
+ binary:match(Desc, Pattern) /= nomatch andalso run_fuzzy_match(E, Fuzzy);
|
|
|
|
|
+run_fuzzy_match(E = {_Id, #{from := Topics}}, [{from, match, Pattern} | Fuzzy]) ->
|
|
|
|
|
+ lists:any(fun(For) -> emqx_topic:match(For, Pattern) end, Topics) andalso
|
|
|
|
|
+ run_fuzzy_match(E, Fuzzy);
|
|
|
|
|
+run_fuzzy_match(E = {_Id, #{from := Topics}}, [{from, like, Pattern} | Fuzzy]) ->
|
|
|
|
|
+ lists:any(fun(For) -> binary:match(For, Pattern) /= nomatch end, Topics) andalso
|
|
|
|
|
+ run_fuzzy_match(E, Fuzzy);
|
|
|
|
|
+run_fuzzy_match(E, [_ | Fuzzy]) ->
|
|
|
|
|
+ run_fuzzy_match(E, Fuzzy).
|