|
|
@@ -35,7 +35,7 @@
|
|
|
, unsubscribe/2
|
|
|
, subscribe_batch/2]).
|
|
|
|
|
|
--export([ query/3
|
|
|
+-export([ query/4
|
|
|
, format_channel_info/1]).
|
|
|
|
|
|
%% for batch operation
|
|
|
@@ -420,14 +420,17 @@ subscriptions(get, #{bindings := #{clientid := ClientID}}) ->
|
|
|
%% api apply
|
|
|
|
|
|
list(Params) ->
|
|
|
+ {Tab, QuerySchema} = ?CLIENT_QS_SCHEMA,
|
|
|
case maps:get(<<"node">>, Params, undefined) of
|
|
|
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};
|
|
|
Node1 ->
|
|
|
Node = binary_to_atom(Node1, utf8),
|
|
|
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}
|
|
|
end.
|
|
|
|
|
|
@@ -492,66 +495,8 @@ subscribe_batch(#{clientid := ClientID, topics := Topics}) ->
|
|
|
ArgList = [[ClientID, Topic, Qos]|| #{topic := Topic, qos := Qos} <- Topics],
|
|
|
emqx_mgmt_util:batch_operation(?MODULE, do_subscribe, ArgList).
|
|
|
|
|
|
-%%%==============================================================================================
|
|
|
+%%--------------------------------------------------------------------
|
|
|
%% internal function
|
|
|
-format_channel_info({_, ClientInfo, ClientStats}) ->
|
|
|
- Fun =
|
|
|
- fun
|
|
|
- (_Key, Value, Current) when is_map(Value) ->
|
|
|
- maps:merge(Current, Value);
|
|
|
- (Key, Value, Current) ->
|
|
|
- maps:put(Key, Value, Current)
|
|
|
- end,
|
|
|
- StatsMap = maps:without([memory, next_pkt_id, total_heap_size],
|
|
|
- maps:from_list(ClientStats)),
|
|
|
- ClientInfoMap0 = maps:fold(Fun, #{}, ClientInfo),
|
|
|
- IpAddress = peer_to_binary(maps:get(peername, ClientInfoMap0)),
|
|
|
- Connected = maps:get(conn_state, ClientInfoMap0) =:= connected,
|
|
|
- ClientInfoMap1 = maps:merge(StatsMap, ClientInfoMap0),
|
|
|
- ClientInfoMap2 = maps:put(node, node(), ClientInfoMap1),
|
|
|
- ClientInfoMap3 = maps:put(ip_address, IpAddress, ClientInfoMap2),
|
|
|
- ClientInfoMap = maps:put(connected, Connected, ClientInfoMap3),
|
|
|
- RemoveList = [
|
|
|
- auth_result
|
|
|
- , peername
|
|
|
- , sockname
|
|
|
- , peerhost
|
|
|
- , conn_state
|
|
|
- , send_pend
|
|
|
- , conn_props
|
|
|
- , peercert
|
|
|
- , sockstate
|
|
|
- , subscriptions
|
|
|
- , receive_maximum
|
|
|
- , protocol
|
|
|
- , is_superuser
|
|
|
- , sockport
|
|
|
- , anonymous
|
|
|
- , mountpoint
|
|
|
- , socktype
|
|
|
- , active_n
|
|
|
- , await_rel_timeout
|
|
|
- , conn_mod
|
|
|
- , sockname
|
|
|
- , retry_interval
|
|
|
- , upgrade_qos
|
|
|
- ],
|
|
|
- maps:without(RemoveList, ClientInfoMap).
|
|
|
-
|
|
|
-peer_to_binary({Addr, Port}) ->
|
|
|
- AddrBinary = list_to_binary(inet:ntoa(Addr)),
|
|
|
- PortBinary = integer_to_binary(Port),
|
|
|
- <<AddrBinary/binary, ":", PortBinary/binary>>;
|
|
|
-peer_to_binary(Addr) ->
|
|
|
- list_to_binary(inet:ntoa(Addr)).
|
|
|
-
|
|
|
-format_authz_cache({{PubSub, Topic}, {AuthzResult, Timestamp}}) ->
|
|
|
- #{
|
|
|
- access => PubSub,
|
|
|
- topic => Topic,
|
|
|
- result => AuthzResult,
|
|
|
- updated_time => Timestamp
|
|
|
- }.
|
|
|
|
|
|
do_subscribe(ClientID, Topic0, Qos) ->
|
|
|
{Topic, Opts} = emqx_topic:parse(Topic0),
|
|
|
@@ -575,20 +520,23 @@ do_unsubscribe(ClientID, Topic) ->
|
|
|
Res ->
|
|
|
Res
|
|
|
end.
|
|
|
-%%%==============================================================================================
|
|
|
+%%--------------------------------------------------------------------
|
|
|
%% Query Functions
|
|
|
|
|
|
-query({Qs, []}, Start, Limit) ->
|
|
|
+query(Tab, {Qs, []}, Start, Limit) ->
|
|
|
Ms = qs2ms(Qs),
|
|
|
- emqx_mgmt_api:select_table(emqx_channel_info, Ms, Start, Limit, fun format_channel_info/1);
|
|
|
+ emqx_mgmt_api:select_table(Tab, Ms, Start, Limit,
|
|
|
+ fun format_channel_info/1);
|
|
|
|
|
|
-query({Qs, Fuzzy}, Start, Limit) ->
|
|
|
+query(Tab, {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).
|
|
|
+ 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, {#{}, []}),
|
|
|
@@ -633,8 +581,9 @@ ms(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}) ->
|
|
|
@@ -659,3 +608,64 @@ run_fuzzy_match(E = {_, #{clientinfo := ClientInfo}, _}, [{Key, _, RE}|Fuzzy]) -
|
|
|
V -> V
|
|
|
end,
|
|
|
re:run(Val, RE, [{capture, none}]) == match andalso run_fuzzy_match(E, Fuzzy).
|
|
|
+
|
|
|
+%%--------------------------------------------------------------------
|
|
|
+%% format funcs
|
|
|
+
|
|
|
+format_channel_info({_, ClientInfo, ClientStats}) ->
|
|
|
+ Fun =
|
|
|
+ fun
|
|
|
+ (_Key, Value, Current) when is_map(Value) ->
|
|
|
+ maps:merge(Current, Value);
|
|
|
+ (Key, Value, Current) ->
|
|
|
+ maps:put(Key, Value, Current)
|
|
|
+ end,
|
|
|
+ StatsMap = maps:without([memory, next_pkt_id, total_heap_size],
|
|
|
+ maps:from_list(ClientStats)),
|
|
|
+ ClientInfoMap0 = maps:fold(Fun, #{}, ClientInfo),
|
|
|
+ IpAddress = peer_to_binary(maps:get(peername, ClientInfoMap0)),
|
|
|
+ Connected = maps:get(conn_state, ClientInfoMap0) =:= connected,
|
|
|
+ ClientInfoMap1 = maps:merge(StatsMap, ClientInfoMap0),
|
|
|
+ ClientInfoMap2 = maps:put(node, node(), ClientInfoMap1),
|
|
|
+ ClientInfoMap3 = maps:put(ip_address, IpAddress, ClientInfoMap2),
|
|
|
+ ClientInfoMap = maps:put(connected, Connected, ClientInfoMap3),
|
|
|
+ RemoveList = [
|
|
|
+ auth_result
|
|
|
+ , peername
|
|
|
+ , sockname
|
|
|
+ , peerhost
|
|
|
+ , conn_state
|
|
|
+ , send_pend
|
|
|
+ , conn_props
|
|
|
+ , peercert
|
|
|
+ , sockstate
|
|
|
+ , subscriptions
|
|
|
+ , receive_maximum
|
|
|
+ , protocol
|
|
|
+ , is_superuser
|
|
|
+ , sockport
|
|
|
+ , anonymous
|
|
|
+ , mountpoint
|
|
|
+ , socktype
|
|
|
+ , active_n
|
|
|
+ , await_rel_timeout
|
|
|
+ , conn_mod
|
|
|
+ , sockname
|
|
|
+ , retry_interval
|
|
|
+ , upgrade_qos
|
|
|
+ ],
|
|
|
+ maps:without(RemoveList, ClientInfoMap).
|
|
|
+
|
|
|
+peer_to_binary({Addr, Port}) ->
|
|
|
+ AddrBinary = list_to_binary(inet:ntoa(Addr)),
|
|
|
+ PortBinary = integer_to_binary(Port),
|
|
|
+ <<AddrBinary/binary, ":", PortBinary/binary>>;
|
|
|
+peer_to_binary(Addr) ->
|
|
|
+ list_to_binary(inet:ntoa(Addr)).
|
|
|
+
|
|
|
+format_authz_cache({{PubSub, Topic}, {AuthzResult, Timestamp}}) ->
|
|
|
+ #{ access => PubSub,
|
|
|
+ topic => Topic,
|
|
|
+ result => AuthzResult,
|
|
|
+ updated_time => Timestamp
|
|
|
+ }.
|