fix(emqx_mgmt): clients api times using rfc3339.

This commit is contained in:
Jim Moen 2021-09-13 20:07:18 +08:00 committed by JimMoen
parent 1cf84e232e
commit 834a688062
1 changed files with 71 additions and 18 deletions

View File

@ -33,14 +33,24 @@
, authz_cache/2 , authz_cache/2
, subscribe/2 , subscribe/2
, unsubscribe/2 , unsubscribe/2
, subscribe_batch/2]). , subscribe_batch/2
]).
-export([ query/4 -export([ query/4
, format_channel_info/1]). , format_channel_info/1
]).
%% for batch operation %% for batch operation
-export([do_subscribe/3]). -export([do_subscribe/3]).
%% for test suite
-export([ unix_ts_to_rfc3339_bin/1
, unix_ts_to_rfc3339_bin/2
, rfc3339_to_unix_ts_int/1
, rfc3339_to_unix_ts_int/2
]).
-define(CLIENT_QS_SCHEMA, {emqx_channel_info, -define(CLIENT_QS_SCHEMA, {emqx_channel_info,
[ {<<"node">>, atom} [ {<<"node">>, atom}
, {<<"username">>, binary} , {<<"username">>, binary}
@ -228,28 +238,28 @@ clients_api() ->
name => gte_created_at, name => gte_created_at,
in => query, in => query,
required => false, required => false,
description => <<"Search client session creation time by less than or equal method">>, description => <<"Search client session creation time by greater than or equal method, rfc3339">>,
schema => #{type => string} schema => #{type => string}
}, },
#{ #{
name => lte_created_at, name => lte_created_at,
in => query, in => query,
required => false, required => false,
description => <<"Search client session creation time by greater than or equal method">>, description => <<"Search client session creation time by less than or equal method, rfc3339">>,
schema => #{type => string} schema => #{type => string}
}, },
#{ #{
name => gte_connected_at, name => gte_connected_at,
in => query, in => query,
required => false, required => false,
description => <<"Search client connection creation time by less than or equal method">>, description => <<"Search client connection creation time by greater than or equal method, rfc3339">>,
schema => #{type => string} schema => #{type => string}
}, },
#{ #{
name => lte_connected_at, name => lte_connected_at,
in => query, in => query,
required => false, required => false,
description => <<"Search client connection creation time by greater than or equal method">>, description => <<"Search client connection creation time by less than or equal method, rfc3339">>,
schema => #{type => string} schema => #{type => string}
} }
], ],
@ -376,7 +386,7 @@ subscribe_api() ->
%%%============================================================================================== %%%==============================================================================================
%% parameters trans %% parameters trans
clients(get, #{query_string := Qs}) -> clients(get, #{query_string := Qs}) ->
list(Qs). list(generate_qs(Qs)).
client(get, #{bindings := Bindings}) -> client(get, #{bindings := Bindings}) ->
lookup(Bindings); lookup(Bindings);
@ -520,6 +530,25 @@ do_unsubscribe(ClientID, Topic) ->
Res -> Res ->
Res Res
end. end.
%%--------------------------------------------------------------------
%% QueryString Generation (rfc3339 to timestamp)
generate_qs(Qs) ->
TimeKeys = [ <<"gte_created_at">>
, <<"lte_created_at">>
, <<"gte_connected_at">>
, <<"lte_connected_at">>],
Fun =
fun
(Key, NQs) ->
case NQs of
#{Key := Rfc3339Time} -> NQs#{Key => rfc3339_to_unix_ts_int(Rfc3339Time)};
#{} -> NQs
end
end,
lists:foldl(Fun, Qs, TimeKeys).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Query Functions %% Query Functions
@ -613,24 +642,17 @@ run_fuzzy_match(E = {_, #{clientinfo := ClientInfo}, _}, [{Key, _, RE}|Fuzzy]) -
%% format funcs %% format funcs
format_channel_info({_, ClientInfo, ClientStats}) -> 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], StatsMap = maps:without([memory, next_pkt_id, total_heap_size],
maps:from_list(ClientStats)), maps:from_list(ClientStats)),
ClientInfoMap0 = maps:fold(Fun, #{}, ClientInfo), ClientInfoMap0 = maps:fold(fun take_maps_from_inner/3, #{}, ClientInfo),
IpAddress = peer_to_binary(maps:get(peername, ClientInfoMap0)), IpAddress = peer_to_binary(maps:get(peername, ClientInfoMap0)),
Connected = maps:get(conn_state, ClientInfoMap0) =:= connected, Connected = maps:get(conn_state, ClientInfoMap0) =:= connected,
ClientInfoMap1 = maps:merge(StatsMap, ClientInfoMap0), ClientInfoMap1 = maps:merge(StatsMap, ClientInfoMap0),
ClientInfoMap2 = maps:put(node, node(), ClientInfoMap1), ClientInfoMap2 = maps:put(node, node(), ClientInfoMap1),
ClientInfoMap3 = maps:put(ip_address, IpAddress, ClientInfoMap2), ClientInfoMap3 = maps:put(ip_address, IpAddress, ClientInfoMap2),
ClientInfoMap = maps:put(connected, Connected, ClientInfoMap3), ClientInfoMap = maps:put(connected, Connected, ClientInfoMap3),
RemoveList = [ RemoveList =
auth_result [ auth_result
, peername , peername
, sockname , sockname
, peerhost , peerhost
@ -654,7 +676,23 @@ format_channel_info({_, ClientInfo, ClientStats}) ->
, retry_interval , retry_interval
, upgrade_qos , upgrade_qos
], ],
maps:without(RemoveList, ClientInfoMap). TimesKeys = [created_at, connected_at, disconnected_at],
%% format timestamp to rfc3339
lists:foldl(fun result_format_time_fun/2
, maps:without(RemoveList, ClientInfoMap)
, TimesKeys).
%% format func helpers
take_maps_from_inner(_Key, Value, Current) when is_map(Value) ->
maps:merge(Current, Value);
take_maps_from_inner(Key, Value, Current) ->
maps:put(Key, Value, Current).
result_format_time_fun(Key, NClientInfoMap) ->
case NClientInfoMap of
#{Key := TimeStamp} -> NClientInfoMap#{Key => unix_ts_to_rfc3339_bin(TimeStamp)};
#{} -> NClientInfoMap
end.
peer_to_binary({Addr, Port}) -> peer_to_binary({Addr, Port}) ->
AddrBinary = list_to_binary(inet:ntoa(Addr)), AddrBinary = list_to_binary(inet:ntoa(Addr)),
@ -669,3 +707,18 @@ format_authz_cache({{PubSub, Topic}, {AuthzResult, Timestamp}}) ->
result => AuthzResult, result => AuthzResult,
updated_time => Timestamp updated_time => Timestamp
}. }.
%%--------------------------------------------------------------------
%% time format funcs
unix_ts_to_rfc3339_bin(TimeStamp) ->
unix_ts_to_rfc3339_bin(TimeStamp, millisecond).
unix_ts_to_rfc3339_bin(TimeStamp, Unit) when is_integer(TimeStamp) ->
list_to_binary(calendar:system_time_to_rfc3339(TimeStamp, [{unit, Unit}])).
rfc3339_to_unix_ts_int(DateTime) ->
rfc3339_to_unix_ts_int(DateTime, millisecond).
rfc3339_to_unix_ts_int(DateTime, Unit) when is_binary(DateTime) ->
calendar:rfc3339_to_system_time(binary_to_list(DateTime), [{unit, Unit}]).