Przeglądaj źródła

fix(emqx_mgmt): clients api query params supports epoch(milliseconds).

Jim Moen 4 lat temu
rodzic
commit
294c1a5f69

+ 31 - 23
apps/emqx_management/src/emqx_mgmt_api_clients.erl

@@ -46,8 +46,8 @@
 %% 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
+        , time_string_to_unix_ts_int/1
+        , time_string_to_unix_ts_int/2
         ]).
 
 
@@ -106,9 +106,9 @@ properties(client) ->
         {clean_start,       boolean, <<"Indicate whether the client is using a brand new session">>},
         {clientid,          string , <<"Client identifier">>},
         {connected,         boolean, <<"Whether the client is connected">>},
-        {connected_at,      string , <<"Client connection time">>},
-        {created_at,        string , <<"Session creation time">>},
-        {disconnected_at,   string , <<"Client offline time, This field is only valid and returned when connected is false">>},
+        {connected_at,      string , <<"Client connection time, rfc3339">>},
+        {created_at,        string , <<"Session creation time, rfc3339">>},
+        {disconnected_at,   string , <<"Client offline time, This field is only valid and returned when connected is false, rfc3339">>},
         {expiry_interval,   integer, <<"Session expiration interval, with the unit of second">>},
         {heap_size,         integer, <<"Process heap size with the unit of byte">>},
         {inflight_cnt,      integer, <<"Current length of inflight">>},
@@ -238,28 +238,28 @@ clients_api() ->
                     name => gte_created_at,
                     in => query,
                     required => false,
-                    description => <<"Search client session creation time by greater than or equal method, rfc3339">>,
+                    description => <<"Search client session creation time by greater than or equal method, rfc3339 or timestamp(millisecond)">>,
                     schema => #{type => string}
                 },
                 #{
                     name => lte_created_at,
                     in => query,
                     required => false,
-                    description => <<"Search client session creation time by less than or equal method, rfc3339">>,
+                    description => <<"Search client session creation time by less than or equal method, rfc3339 or timestamp(millisecond)">>,
                     schema => #{type => string}
                 },
                 #{
                     name => gte_connected_at,
                     in => query,
                     required => false,
-                    description => <<"Search client connection creation time by greater than or equal method, rfc3339">>,
+                    description => <<"Search client connection creation time by greater than or equal method, rfc3339 or timestamp(millisecond)">>,
                     schema => #{type => string}
                 },
                 #{
                     name => lte_connected_at,
                     in => query,
                     required => false,
-                    description => <<"Search client connection creation time by less than or equal method, rfc3339">>,
+                    description => <<"Search client connection creation time by less than or equal method, rfc3339 or timestamp(millisecond) ">>,
                     schema => #{type => string}
                 }
             ],
@@ -532,22 +532,25 @@ do_unsubscribe(ClientID, Topic) ->
     end.
 
 %%--------------------------------------------------------------------
-%% QueryString Generation (rfc3339 to timestamp)
+%% QueryString Generation (try rfc3339 to timestamp or keep timestamp)
+
+time_keys() ->
+    [ <<"gte_created_at">>
+    , <<"lte_created_at">>
+    , <<"gte_connected_at">>
+    , <<"lte_connected_at">>].
 
 generate_qs(Qs) ->
-    TimeKeys = [ <<"gte_created_at">>
-               , <<"lte_created_at">>
-               , <<"gte_connected_at">>
-               , <<"lte_connected_at">>],
     Fun =
-        fun
-            (Key, NQs) ->
+        fun (Key, NQs) ->
                 case NQs of
-                    #{Key := Rfc3339Time} -> NQs#{Key => rfc3339_to_unix_ts_int(Rfc3339Time)};
-                    #{}                   -> NQs
+                    %% TimeString likes "2021-01-01T00:00:00.000+08:00" (in rfc3339)
+                    %% or "1609430400000" (in millisecond)
+                    #{Key := TimeString} -> NQs#{Key => time_string_to_unix_ts_int(TimeString)};
+                    #{}                  -> NQs
                 end
         end,
-    lists:foldl(Fun, Qs, TimeKeys).
+    lists:foldl(Fun, Qs, time_keys()).
 
 %%--------------------------------------------------------------------
 %% Query Functions
@@ -717,8 +720,13 @@ unix_ts_to_rfc3339_bin(TimeStamp) ->
 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).
+time_string_to_unix_ts_int(DateTime) ->
+    time_string_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}]).
+time_string_to_unix_ts_int(DateTime, Unit) when is_binary(DateTime) ->
+    try binary_to_integer(DateTime) of
+        TimeStamp when is_integer(TimeStamp) -> TimeStamp
+    catch
+        error:badarg ->
+            calendar:rfc3339_to_system_time(binary_to_list(DateTime), [{unit, Unit}])
+    end.

+ 15 - 10
apps/emqx_management/test/emqx_mgmt_clients_api_SUITE.erl

@@ -104,6 +104,7 @@ t_clients(_) ->
 
 t_query_clients_with_time(_) ->
     process_flag(trap_exit, true),
+
     Username1 = <<"user1">>,
     ClientId1 = <<"client1">>,
 
@@ -122,22 +123,26 @@ t_query_clients_with_time(_) ->
     %% get /clients with time(rfc3339)
     NowTimeStampInt = erlang:system_time(millisecond),
     %% Do not uri_encode `=` to `%3D`
-    NowTimeString   = emqx_http_lib:uri_encode(binary:bin_to_list(emqx_mgmt_api_clients:unix_ts_to_rfc3339_bin(NowTimeStampInt))),
-    Parameters      = [Param ++ NowTimeString
-                       || Param <- [ "lte_created_at="
-                                   , "lte_connected_at="
-                                   , "gte_created_at="
-                                   , "gte_connected_at="]],
+    Rfc3339String   = emqx_http_lib:uri_encode(binary:bin_to_list(emqx_mgmt_api_clients:unix_ts_to_rfc3339_bin(NowTimeStampInt))),
+    TimeStampString = emqx_http_lib:uri_encode(integer_to_list(NowTimeStampInt)),
+
+    LteKeys         = ["lte_created_at=", "lte_connected_at="],
+    GteKeys         = ["gte_created_at=", "gte_connected_at="],
+    LteParamRfc3339 = [Param ++ Rfc3339String   || Param <- LteKeys],
+    LteParamStamp   = [Param ++ TimeStampString || Param <- LteKeys],
+    GteParamRfc3339 = [Param ++ Rfc3339String   || Param <- GteKeys],
+    GteParamStamp   = [Param ++ TimeStampString || Param <- GteKeys],
+
     RequestResults  = [emqx_mgmt_api_test_util:request_api(get, ClientsPath, Param, AuthHeader)
-                       || Param <- Parameters],
+                       || Param <- LteParamRfc3339 ++ LteParamStamp ++ GteParamRfc3339 ++ GteParamStamp],
     DecodedResults  = [emqx_json:decode(Response, [return_maps])
                        || {ok, Response} <- RequestResults],
-    {LteResponseDecodeds, GteResponseDecodeds} = lists:split(2, DecodedResults),
+    {LteResponseDecodeds, GteResponseDecodeds} = lists:split(4, DecodedResults),
     %% EachData :: list()
-    [?assert( emqx_mgmt_api_clients:rfc3339_to_unix_ts_int(CreatedAt) < NowTimeStampInt)
+    [?assert( emqx_mgmt_api_clients:time_string_to_unix_ts_int(CreatedAt) < NowTimeStampInt)
      || #{<<"data">> := EachData} <- LteResponseDecodeds,
         #{<<"created_at">> := CreatedAt}     <- EachData],
-    [?assert(emqx_mgmt_api_clients:rfc3339_to_unix_ts_int(ConnectedAt) < NowTimeStampInt)
+    [?assert(emqx_mgmt_api_clients:time_string_to_unix_ts_int(ConnectedAt) < NowTimeStampInt)
      || #{<<"data">> := EachData} <- LteResponseDecodeds,
         #{<<"connected_at">> := ConnectedAt} <- EachData],
     [?assertEqual(EachData, [])