chore(mgmt): callback query function with table name param
This commit is contained in:
parent
3f0ef7efa8
commit
0a7a14f4cd
|
@ -22,13 +22,13 @@
|
||||||
|
|
||||||
%% first_next query APIs
|
%% first_next query APIs
|
||||||
-export([ params2qs/2
|
-export([ params2qs/2
|
||||||
, node_query/4
|
, node_query/5
|
||||||
, cluster_query/3
|
, cluster_query/4
|
||||||
, traverse_table/5
|
, traverse_table/5
|
||||||
, select_table/5
|
, select_table/5
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([do_query/5]).
|
-export([do_query/6]).
|
||||||
|
|
||||||
paginate(Tables, Params, RowFun) ->
|
paginate(Tables, Params, RowFun) ->
|
||||||
Qh = query_handle(Tables),
|
Qh = query_handle(Tables),
|
||||||
|
@ -78,14 +78,14 @@ limit(Params) ->
|
||||||
%% Node Query
|
%% Node Query
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
node_query(Node, Params, {Tab, QsSchema}, QueryFun) ->
|
node_query(Node, Params, Tab, QsSchema, QueryFun) ->
|
||||||
{CodCnt, Qs} = params2qs(Params, QsSchema),
|
{CodCnt, Qs} = params2qs(Params, QsSchema),
|
||||||
Limit = b2i(limit(Params)),
|
Limit = b2i(limit(Params)),
|
||||||
Page = b2i(page(Params)),
|
Page = b2i(page(Params)),
|
||||||
Start = if Page > 1 -> (Page-1) * Limit;
|
Start = if Page > 1 -> (Page-1) * Limit;
|
||||||
true -> 0
|
true -> 0
|
||||||
end,
|
end,
|
||||||
{_, Rows} = do_query(Node, Qs, QueryFun, Start, Limit+1),
|
{_, Rows} = do_query(Node, Tab, Qs, QueryFun, Start, Limit+1),
|
||||||
Meta = #{page => Page, limit => Limit},
|
Meta = #{page => Page, limit => Limit},
|
||||||
NMeta = case CodCnt =:= 0 of
|
NMeta = case CodCnt =:= 0 of
|
||||||
true -> Meta#{count => count(Tab)};
|
true -> Meta#{count => count(Tab)};
|
||||||
|
@ -94,10 +94,11 @@ node_query(Node, Params, {Tab, QsSchema}, QueryFun) ->
|
||||||
#{meta => NMeta, data => lists:sublist(Rows, Limit)}.
|
#{meta => NMeta, data => lists:sublist(Rows, Limit)}.
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
do_query(Node, Qs, {M,F}, Start, Limit) when Node =:= node() ->
|
do_query(Node, Tab, Qs, {M,F}, Start, Limit) when Node =:= node() ->
|
||||||
M:F(Qs, Start, Limit);
|
M:F(Tab, Qs, Start, Limit);
|
||||||
do_query(Node, Qs, QueryFun, Start, Limit) ->
|
do_query(Node, Tab, Qs, QueryFun, Start, Limit) ->
|
||||||
rpc_call(Node, ?MODULE, do_query, [Node, Qs, QueryFun, Start, Limit], 50000).
|
rpc_call(Node, ?MODULE, do_query,
|
||||||
|
[Node, Tab, Qs, QueryFun, Start, Limit], 50000).
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
rpc_call(Node, M, F, A, T) ->
|
rpc_call(Node, M, F, A, T) ->
|
||||||
|
@ -110,7 +111,7 @@ rpc_call(Node, M, F, A, T) ->
|
||||||
%% Cluster Query
|
%% Cluster Query
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
cluster_query(Params, {Tab, QsSchema}, QueryFun) ->
|
cluster_query(Params, Tab, QsSchema, QueryFun) ->
|
||||||
{CodCnt, Qs} = params2qs(Params, QsSchema),
|
{CodCnt, Qs} = params2qs(Params, QsSchema),
|
||||||
Limit = b2i(limit(Params)),
|
Limit = b2i(limit(Params)),
|
||||||
Page = b2i(page(Params)),
|
Page = b2i(page(Params)),
|
||||||
|
@ -118,7 +119,7 @@ cluster_query(Params, {Tab, QsSchema}, QueryFun) ->
|
||||||
true -> 0
|
true -> 0
|
||||||
end,
|
end,
|
||||||
Nodes = ekka_mnesia:running_nodes(),
|
Nodes = ekka_mnesia:running_nodes(),
|
||||||
Rows = do_cluster_query(Nodes, Qs, QueryFun, Start, Limit+1, []),
|
Rows = do_cluster_query(Nodes, Tab, Qs, QueryFun, Start, Limit+1, []),
|
||||||
Meta = #{page => Page, limit => Limit},
|
Meta = #{page => Page, limit => Limit},
|
||||||
NMeta = case CodCnt =:= 0 of
|
NMeta = case CodCnt =:= 0 of
|
||||||
true -> Meta#{count => count(Tab, Nodes)};
|
true -> Meta#{count => count(Tab, Nodes)};
|
||||||
|
@ -127,13 +128,13 @@ cluster_query(Params, {Tab, QsSchema}, QueryFun) ->
|
||||||
#{meta => NMeta, data => lists:sublist(Rows, Limit)}.
|
#{meta => NMeta, data => lists:sublist(Rows, Limit)}.
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
do_cluster_query([], _, _, _, _, Acc) ->
|
do_cluster_query([], _, _, _, _, _, Acc) ->
|
||||||
lists:append(lists:reverse(Acc));
|
lists:append(lists:reverse(Acc));
|
||||||
do_cluster_query([Node|Nodes], Qs, QueryFun, Start, Limit, Acc) ->
|
do_cluster_query([Node|Nodes], Tab, Qs, QueryFun, Start, Limit, Acc) ->
|
||||||
{NStart, Rows} = do_query(Node, Qs, QueryFun, Start, Limit),
|
{NStart, Rows} = do_query(Node, Tab, Qs, QueryFun, Start, Limit),
|
||||||
case Limit - length(Rows) of
|
case Limit - length(Rows) of
|
||||||
Rest when Rest > 0 ->
|
Rest when Rest > 0 ->
|
||||||
do_cluster_query(Nodes, Qs, QueryFun, NStart, Limit, [Rows|Acc]);
|
do_cluster_query(Nodes, Tab, Qs, QueryFun, NStart, Limit, [Rows|Acc]);
|
||||||
0 ->
|
0 ->
|
||||||
lists:append(lists:reverse([Rows|Acc]))
|
lists:append(lists:reverse([Rows|Acc]))
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -22,8 +22,10 @@
|
||||||
|
|
||||||
-export([alarms/2]).
|
-export([alarms/2]).
|
||||||
|
|
||||||
-export([ query_activated/3
|
%% internal export (for query)
|
||||||
, query_deactivated/3]).
|
-export([ query/4
|
||||||
|
]).
|
||||||
|
|
||||||
%% notice: from emqx_alarms
|
%% notice: from emqx_alarms
|
||||||
-define(ACTIVATED_ALARM, emqx_activated_alarm).
|
-define(ACTIVATED_ALARM, emqx_activated_alarm).
|
||||||
-define(DEACTIVATED_ALARM, emqx_deactivated_alarm).
|
-define(DEACTIVATED_ALARM, emqx_deactivated_alarm).
|
||||||
|
@ -71,14 +73,12 @@ alarms_api() ->
|
||||||
%%%==============================================================================================
|
%%%==============================================================================================
|
||||||
%% parameters trans
|
%% parameters trans
|
||||||
alarms(get, #{query_string := Qs}) ->
|
alarms(get, #{query_string := Qs}) ->
|
||||||
{Table, Function} =
|
Table =
|
||||||
case maps:get(<<"activated">>, Qs, <<"true">>) of
|
case maps:get(<<"activated">>, Qs, <<"true">>) of
|
||||||
<<"true">> ->
|
<<"true">> -> ?ACTIVATED_ALARM;
|
||||||
{?ACTIVATED_ALARM, query_activated};
|
<<"false">> -> ?DEACTIVATED_ALARM
|
||||||
<<"false">> ->
|
|
||||||
{?DEACTIVATED_ALARM, query_deactivated}
|
|
||||||
end,
|
end,
|
||||||
Response = emqx_mgmt_api:cluster_query(Qs, {Table, []}, {?MODULE, Function}),
|
Response = emqx_mgmt_api:cluster_query(Qs, Table, [], {?MODULE, query}),
|
||||||
{200, Response};
|
{200, Response};
|
||||||
|
|
||||||
alarms(delete, _Params) ->
|
alarms(delete, _Params) ->
|
||||||
|
@ -87,13 +87,8 @@ alarms(delete, _Params) ->
|
||||||
|
|
||||||
%%%==============================================================================================
|
%%%==============================================================================================
|
||||||
%% internal
|
%% internal
|
||||||
query_activated(_, Start, Limit) ->
|
|
||||||
query(?ACTIVATED_ALARM, Start, Limit).
|
|
||||||
|
|
||||||
query_deactivated(_, Start, Limit) ->
|
query(Table, _QsSpec, Start, Limit) ->
|
||||||
query(?DEACTIVATED_ALARM, Start, Limit).
|
|
||||||
|
|
||||||
query(Table, Start, Limit) ->
|
|
||||||
Ms = [{'$1',[],['$1']}],
|
Ms = [{'$1',[],['$1']}],
|
||||||
emqx_mgmt_api:select_table(Table, Ms, Start, Limit, fun format_alarm/1).
|
emqx_mgmt_api:select_table(Table, Ms, Start, Limit, fun format_alarm/1).
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
, unsubscribe/2
|
, unsubscribe/2
|
||||||
, subscribe_batch/2]).
|
, subscribe_batch/2]).
|
||||||
|
|
||||||
-export([ query/3
|
-export([ query/4
|
||||||
, format_channel_info/1]).
|
, format_channel_info/1]).
|
||||||
|
|
||||||
%% for batch operation
|
%% for batch operation
|
||||||
|
@ -420,14 +420,17 @@ subscriptions(get, #{bindings := #{clientid := ClientID}}) ->
|
||||||
%% api apply
|
%% api apply
|
||||||
|
|
||||||
list(Params) ->
|
list(Params) ->
|
||||||
|
{Tab, QuerySchema} = ?CLIENT_QS_SCHEMA,
|
||||||
case maps:get(<<"node">>, Params, undefined) of
|
case maps:get(<<"node">>, Params, undefined) of
|
||||||
undefined ->
|
undefined ->
|
||||||
Response = emqx_mgmt_api:cluster_query(Params, ?CLIENT_QS_SCHEMA, ?query_fun),
|
Response = emqx_mgmt_api:cluster_query(Params, Tab,
|
||||||
|
QuerySchema, ?query_fun),
|
||||||
{200, Response};
|
{200, Response};
|
||||||
Node1 ->
|
Node1 ->
|
||||||
Node = binary_to_atom(Node1, utf8),
|
Node = binary_to_atom(Node1, utf8),
|
||||||
ParamsWithoutNode = maps:without([<<"node">>], Params),
|
ParamsWithoutNode = maps:without([<<"node">>], Params),
|
||||||
Response = emqx_mgmt_api:node_query(Node, ParamsWithoutNode, ?CLIENT_QS_SCHEMA, ?query_fun),
|
Response = emqx_mgmt_api:node_query(Node, ParamsWithoutNode,
|
||||||
|
Tab, QuerySchema, ?query_fun),
|
||||||
{200, Response}
|
{200, Response}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -492,8 +495,123 @@ subscribe_batch(#{clientid := ClientID, topics := Topics}) ->
|
||||||
ArgList = [[ClientID, Topic, Qos]|| #{topic := Topic, qos := Qos} <- Topics],
|
ArgList = [[ClientID, Topic, Qos]|| #{topic := Topic, qos := Qos} <- Topics],
|
||||||
emqx_mgmt_util:batch_operation(?MODULE, do_subscribe, ArgList).
|
emqx_mgmt_util:batch_operation(?MODULE, do_subscribe, ArgList).
|
||||||
|
|
||||||
%%%==============================================================================================
|
%%--------------------------------------------------------------------
|
||||||
%% internal function
|
%% internal function
|
||||||
|
|
||||||
|
do_subscribe(ClientID, Topic0, Qos) ->
|
||||||
|
{Topic, Opts} = emqx_topic:parse(Topic0),
|
||||||
|
TopicTable = [{Topic, Opts#{qos => Qos}}],
|
||||||
|
case emqx_mgmt:subscribe(ClientID, TopicTable) of
|
||||||
|
{error, Reason} ->
|
||||||
|
{error, Reason};
|
||||||
|
{subscribe, Subscriptions} ->
|
||||||
|
case proplists:is_defined(Topic, Subscriptions) of
|
||||||
|
true ->
|
||||||
|
ok;
|
||||||
|
false ->
|
||||||
|
{error, unknow_error}
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
do_unsubscribe(ClientID, Topic) ->
|
||||||
|
case emqx_mgmt:unsubscribe(ClientID, Topic) of
|
||||||
|
{error, Reason} ->
|
||||||
|
{error, Reason};
|
||||||
|
Res ->
|
||||||
|
Res
|
||||||
|
end.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Query Functions
|
||||||
|
|
||||||
|
query(Tab, {Qs, []}, Start, Limit) ->
|
||||||
|
Ms = qs2ms(Qs),
|
||||||
|
emqx_mgmt_api:select_table(Tab, Ms, Start, Limit,
|
||||||
|
fun format_channel_info/1);
|
||||||
|
|
||||||
|
query(Tab, {Qs, Fuzzy}, Start, Limit) ->
|
||||||
|
Ms = qs2ms(Qs),
|
||||||
|
MatchFun = match_fun(Ms, Fuzzy),
|
||||||
|
emqx_mgmt_api:traverse_table(Tab, MatchFun, Start, Limit,
|
||||||
|
fun format_channel_info/1).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% QueryString to Match Spec
|
||||||
|
|
||||||
|
-spec qs2ms(list()) -> ets:match_spec().
|
||||||
|
qs2ms(Qs) ->
|
||||||
|
{MtchHead, Conds} = qs2ms(Qs, 2, {#{}, []}),
|
||||||
|
[{{'$1', MtchHead, '_'}, Conds, ['$_']}].
|
||||||
|
|
||||||
|
qs2ms([], _, {MtchHead, Conds}) ->
|
||||||
|
{MtchHead, lists:reverse(Conds)};
|
||||||
|
|
||||||
|
qs2ms([{Key, '=:=', Value} | Rest], N, {MtchHead, Conds}) ->
|
||||||
|
NMtchHead = emqx_mgmt_util:merge_maps(MtchHead, ms(Key, Value)),
|
||||||
|
qs2ms(Rest, N, {NMtchHead, Conds});
|
||||||
|
qs2ms([Qs | Rest], N, {MtchHead, Conds}) ->
|
||||||
|
Holder = binary_to_atom(iolist_to_binary(["$", integer_to_list(N)]), utf8),
|
||||||
|
NMtchHead = emqx_mgmt_util:merge_maps(MtchHead, ms(element(1, Qs), Holder)),
|
||||||
|
NConds = put_conds(Qs, Holder, Conds),
|
||||||
|
qs2ms(Rest, N+1, {NMtchHead, NConds}).
|
||||||
|
|
||||||
|
put_conds({_, Op, V}, Holder, Conds) ->
|
||||||
|
[{Op, Holder, V} | Conds];
|
||||||
|
put_conds({_, Op1, V1, Op2, V2}, Holder, Conds) ->
|
||||||
|
[{Op2, Holder, V2},
|
||||||
|
{Op1, Holder, V1} | Conds].
|
||||||
|
|
||||||
|
ms(clientid, X) ->
|
||||||
|
#{clientinfo => #{clientid => X}};
|
||||||
|
ms(username, X) ->
|
||||||
|
#{clientinfo => #{username => X}};
|
||||||
|
ms(zone, X) ->
|
||||||
|
#{clientinfo => #{zone => X}};
|
||||||
|
ms(ip_address, X) ->
|
||||||
|
#{clientinfo => #{peerhost => X}};
|
||||||
|
ms(conn_state, X) ->
|
||||||
|
#{conn_state => X};
|
||||||
|
ms(clean_start, X) ->
|
||||||
|
#{conninfo => #{clean_start => X}};
|
||||||
|
ms(proto_name, X) ->
|
||||||
|
#{conninfo => #{proto_name => X}};
|
||||||
|
ms(proto_ver, X) ->
|
||||||
|
#{conninfo => #{proto_ver => X}};
|
||||||
|
ms(connected_at, X) ->
|
||||||
|
#{conninfo => #{connected_at => X}};
|
||||||
|
ms(created_at, X) ->
|
||||||
|
#{session => #{created_at => X}}.
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Match funcs
|
||||||
|
|
||||||
|
match_fun(Ms, Fuzzy) ->
|
||||||
|
MsC = ets:match_spec_compile(Ms),
|
||||||
|
REFuzzy = lists:map(fun({K, like, S}) ->
|
||||||
|
{ok, RE} = re:compile(S),
|
||||||
|
{K, like, RE}
|
||||||
|
end, Fuzzy),
|
||||||
|
fun(Rows) ->
|
||||||
|
case ets:match_spec_run(Rows, MsC) of
|
||||||
|
[] -> [];
|
||||||
|
Ls ->
|
||||||
|
lists:filter(fun(E) ->
|
||||||
|
run_fuzzy_match(E, REFuzzy)
|
||||||
|
end, Ls)
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
run_fuzzy_match(_, []) ->
|
||||||
|
true;
|
||||||
|
run_fuzzy_match(E = {_, #{clientinfo := ClientInfo}, _}, [{Key, _, RE}|Fuzzy]) ->
|
||||||
|
Val = case maps:get(Key, ClientInfo, "") of
|
||||||
|
undefined -> "";
|
||||||
|
V -> V
|
||||||
|
end,
|
||||||
|
re:run(Val, RE, [{capture, none}]) == match andalso run_fuzzy_match(E, Fuzzy).
|
||||||
|
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% format funcs
|
||||||
|
|
||||||
format_channel_info({_, ClientInfo, ClientStats}) ->
|
format_channel_info({_, ClientInfo, ClientStats}) ->
|
||||||
Fun =
|
Fun =
|
||||||
fun
|
fun
|
||||||
|
@ -546,116 +664,8 @@ peer_to_binary(Addr) ->
|
||||||
list_to_binary(inet:ntoa(Addr)).
|
list_to_binary(inet:ntoa(Addr)).
|
||||||
|
|
||||||
format_authz_cache({{PubSub, Topic}, {AuthzResult, Timestamp}}) ->
|
format_authz_cache({{PubSub, Topic}, {AuthzResult, Timestamp}}) ->
|
||||||
#{
|
#{ access => PubSub,
|
||||||
access => PubSub,
|
|
||||||
topic => Topic,
|
topic => Topic,
|
||||||
result => AuthzResult,
|
result => AuthzResult,
|
||||||
updated_time => Timestamp
|
updated_time => Timestamp
|
||||||
}.
|
}.
|
||||||
|
|
||||||
do_subscribe(ClientID, Topic0, Qos) ->
|
|
||||||
{Topic, Opts} = emqx_topic:parse(Topic0),
|
|
||||||
TopicTable = [{Topic, Opts#{qos => Qos}}],
|
|
||||||
case emqx_mgmt:subscribe(ClientID, TopicTable) of
|
|
||||||
{error, Reason} ->
|
|
||||||
{error, Reason};
|
|
||||||
{subscribe, Subscriptions} ->
|
|
||||||
case proplists:is_defined(Topic, Subscriptions) of
|
|
||||||
true ->
|
|
||||||
ok;
|
|
||||||
false ->
|
|
||||||
{error, unknow_error}
|
|
||||||
end
|
|
||||||
end.
|
|
||||||
|
|
||||||
do_unsubscribe(ClientID, Topic) ->
|
|
||||||
case emqx_mgmt:unsubscribe(ClientID, Topic) of
|
|
||||||
{error, Reason} ->
|
|
||||||
{error, Reason};
|
|
||||||
Res ->
|
|
||||||
Res
|
|
||||||
end.
|
|
||||||
%%%==============================================================================================
|
|
||||||
%% Query Functions
|
|
||||||
|
|
||||||
query({Qs, []}, Start, Limit) ->
|
|
||||||
Ms = qs2ms(Qs),
|
|
||||||
emqx_mgmt_api:select_table(emqx_channel_info, Ms, Start, Limit, fun format_channel_info/1);
|
|
||||||
|
|
||||||
query({Qs, Fuzzy}, Start, Limit) ->
|
|
||||||
Ms = qs2ms(Qs),
|
|
||||||
MatchFun = match_fun(Ms, Fuzzy),
|
|
||||||
emqx_mgmt_api:traverse_table(emqx_channel_info, MatchFun, Start, Limit, fun format_channel_info/1).
|
|
||||||
|
|
||||||
%%%==============================================================================================
|
|
||||||
%% QueryString to Match Spec
|
|
||||||
-spec qs2ms(list()) -> ets:match_spec().
|
|
||||||
qs2ms(Qs) ->
|
|
||||||
{MtchHead, Conds} = qs2ms(Qs, 2, {#{}, []}),
|
|
||||||
[{{'$1', MtchHead, '_'}, Conds, ['$_']}].
|
|
||||||
|
|
||||||
qs2ms([], _, {MtchHead, Conds}) ->
|
|
||||||
{MtchHead, lists:reverse(Conds)};
|
|
||||||
|
|
||||||
qs2ms([{Key, '=:=', Value} | Rest], N, {MtchHead, Conds}) ->
|
|
||||||
NMtchHead = emqx_mgmt_util:merge_maps(MtchHead, ms(Key, Value)),
|
|
||||||
qs2ms(Rest, N, {NMtchHead, Conds});
|
|
||||||
qs2ms([Qs | Rest], N, {MtchHead, Conds}) ->
|
|
||||||
Holder = binary_to_atom(iolist_to_binary(["$", integer_to_list(N)]), utf8),
|
|
||||||
NMtchHead = emqx_mgmt_util:merge_maps(MtchHead, ms(element(1, Qs), Holder)),
|
|
||||||
NConds = put_conds(Qs, Holder, Conds),
|
|
||||||
qs2ms(Rest, N+1, {NMtchHead, NConds}).
|
|
||||||
|
|
||||||
put_conds({_, Op, V}, Holder, Conds) ->
|
|
||||||
[{Op, Holder, V} | Conds];
|
|
||||||
put_conds({_, Op1, V1, Op2, V2}, Holder, Conds) ->
|
|
||||||
[{Op2, Holder, V2},
|
|
||||||
{Op1, Holder, V1} | Conds].
|
|
||||||
|
|
||||||
ms(clientid, X) ->
|
|
||||||
#{clientinfo => #{clientid => X}};
|
|
||||||
ms(username, X) ->
|
|
||||||
#{clientinfo => #{username => X}};
|
|
||||||
ms(zone, X) ->
|
|
||||||
#{clientinfo => #{zone => X}};
|
|
||||||
ms(ip_address, X) ->
|
|
||||||
#{clientinfo => #{peerhost => X}};
|
|
||||||
ms(conn_state, X) ->
|
|
||||||
#{conn_state => X};
|
|
||||||
ms(clean_start, X) ->
|
|
||||||
#{conninfo => #{clean_start => X}};
|
|
||||||
ms(proto_name, X) ->
|
|
||||||
#{conninfo => #{proto_name => X}};
|
|
||||||
ms(proto_ver, X) ->
|
|
||||||
#{conninfo => #{proto_ver => X}};
|
|
||||||
ms(connected_at, X) ->
|
|
||||||
#{conninfo => #{connected_at => X}};
|
|
||||||
ms(created_at, X) ->
|
|
||||||
#{session => #{created_at => X}}.
|
|
||||||
|
|
||||||
%%%==============================================================================================
|
|
||||||
%% Match funcs
|
|
||||||
match_fun(Ms, Fuzzy) ->
|
|
||||||
MsC = ets:match_spec_compile(Ms),
|
|
||||||
REFuzzy = lists:map(fun({K, like, S}) ->
|
|
||||||
{ok, RE} = re:compile(S),
|
|
||||||
{K, like, RE}
|
|
||||||
end, Fuzzy),
|
|
||||||
fun(Rows) ->
|
|
||||||
case ets:match_spec_run(Rows, MsC) of
|
|
||||||
[] -> [];
|
|
||||||
Ls ->
|
|
||||||
lists:filter(fun(E) ->
|
|
||||||
run_fuzzy_match(E, REFuzzy)
|
|
||||||
end, Ls)
|
|
||||||
end
|
|
||||||
end.
|
|
||||||
|
|
||||||
run_fuzzy_match(_, []) ->
|
|
||||||
true;
|
|
||||||
run_fuzzy_match(E = {_, #{clientinfo := ClientInfo}, _}, [{Key, _, RE}|Fuzzy]) ->
|
|
||||||
Val = case maps:get(Key, ClientInfo, "") of
|
|
||||||
undefined -> "";
|
|
||||||
V -> V
|
|
||||||
end,
|
|
||||||
re:run(Val, RE, [{capture, none}]) == match andalso run_fuzzy_match(E, Fuzzy).
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
-export([subscriptions/2]).
|
-export([subscriptions/2]).
|
||||||
|
|
||||||
-export([ query/3
|
-export([ query/4
|
||||||
, format/1
|
, format/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
@ -111,11 +111,14 @@ subscriptions(get, #{query_string := Params}) ->
|
||||||
list(Params).
|
list(Params).
|
||||||
|
|
||||||
list(Params) ->
|
list(Params) ->
|
||||||
|
{Tab, QuerySchema} = ?SUBS_QS_SCHEMA,
|
||||||
case maps:get(<<"node">>, Params, undefined) of
|
case maps:get(<<"node">>, Params, undefined) of
|
||||||
undefined ->
|
undefined ->
|
||||||
{200, emqx_mgmt_api:cluster_query(Params, ?SUBS_QS_SCHEMA, ?query_fun)};
|
{200, emqx_mgmt_api:cluster_query(Params, Tab,
|
||||||
|
QuerySchema, ?query_fun)};
|
||||||
Node ->
|
Node ->
|
||||||
{200, emqx_mgmt_api:node_query(binary_to_atom(Node, utf8), Params, ?SUBS_QS_SCHEMA, ?query_fun)}
|
{200, emqx_mgmt_api:node_query(binary_to_atom(Node, utf8), Params,
|
||||||
|
Tab, QuerySchema, ?query_fun)}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
format(Items) when is_list(Items) ->
|
format(Items) when is_list(Items) ->
|
||||||
|
@ -145,14 +148,14 @@ format({_Subscriber, Topic, Options}) ->
|
||||||
%% Query Function
|
%% Query Function
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
query({Qs, []}, Start, Limit) ->
|
query(Tab, {Qs, []}, Start, Limit) ->
|
||||||
Ms = qs2ms(Qs),
|
Ms = qs2ms(Qs),
|
||||||
emqx_mgmt_api:select_table(emqx_suboption, Ms, Start, Limit, fun format/1);
|
emqx_mgmt_api:select_table(Tab, Ms, Start, Limit, fun format/1);
|
||||||
|
|
||||||
query({Qs, Fuzzy}, Start, Limit) ->
|
query(Tab, {Qs, Fuzzy}, Start, Limit) ->
|
||||||
Ms = qs2ms(Qs),
|
Ms = qs2ms(Qs),
|
||||||
MatchFun = match_fun(Ms, Fuzzy),
|
MatchFun = match_fun(Ms, Fuzzy),
|
||||||
emqx_mgmt_api:traverse_table(emqx_suboption, MatchFun, Start, Limit, fun format/1).
|
emqx_mgmt_api:traverse_table(Tab, MatchFun, Start, Limit, fun format/1).
|
||||||
|
|
||||||
match_fun(Ms, Fuzzy) ->
|
match_fun(Ms, Fuzzy) ->
|
||||||
MsC = ets:match_spec_compile(Ms),
|
MsC = ets:match_spec_compile(Ms),
|
||||||
|
|
Loading…
Reference in New Issue