Merge pull request #6953 from DDDHuang/api_hocon
part1: clients & subscriptions api hocon support
This commit is contained in:
commit
50859bbd83
|
@ -38,7 +38,7 @@
|
||||||
-type ip_port() :: tuple().
|
-type ip_port() :: tuple().
|
||||||
-type cipher() :: map().
|
-type cipher() :: map().
|
||||||
-type rfc3339_system_time() :: integer().
|
-type rfc3339_system_time() :: integer().
|
||||||
-type qos():: integer().
|
-type qos() :: integer().
|
||||||
|
|
||||||
-typerefl_from_string({qos/0, emqx_schema, to_qos}).
|
-typerefl_from_string({qos/0, emqx_schema, to_qos}).
|
||||||
-typerefl_from_string({duration/0, emqx_schema, to_duration}).
|
-typerefl_from_string({duration/0, emqx_schema, to_duration}).
|
||||||
|
|
|
@ -389,7 +389,8 @@ subscribe(ClientId, TopicTables) ->
|
||||||
subscribe([Node | Nodes], ClientId, TopicTables) ->
|
subscribe([Node | Nodes], ClientId, TopicTables) ->
|
||||||
case wrap_rpc(emqx_management_proto_v1:subscribe(Node, ClientId, TopicTables)) of
|
case wrap_rpc(emqx_management_proto_v1:subscribe(Node, ClientId, TopicTables)) of
|
||||||
{error, _} -> subscribe(Nodes, ClientId, TopicTables);
|
{error, _} -> subscribe(Nodes, ClientId, TopicTables);
|
||||||
Re -> Re
|
{subscribe, Res} ->
|
||||||
|
{subscribe, Res, Node}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
subscribe([], _ClientId, _TopicTables) ->
|
subscribe([], _ClientId, _TopicTables) ->
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
-behaviour(minirest_api).
|
-behaviour(minirest_api).
|
||||||
|
|
||||||
|
-include_lib("typerefl/include/types.hrl").
|
||||||
-include_lib("emqx/include/emqx.hrl").
|
-include_lib("emqx/include/emqx.hrl").
|
||||||
|
|
||||||
-include_lib("emqx/include/logger.hrl").
|
-include_lib("emqx/include/logger.hrl").
|
||||||
|
@ -25,7 +26,10 @@
|
||||||
-include("emqx_mgmt.hrl").
|
-include("emqx_mgmt.hrl").
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([api_spec/0]).
|
-export([ api_spec/0
|
||||||
|
, paths/0
|
||||||
|
, schema/1
|
||||||
|
, fields/1]).
|
||||||
|
|
||||||
-export([ clients/2
|
-export([ clients/2
|
||||||
, client/2
|
, client/2
|
||||||
|
@ -67,419 +71,322 @@
|
||||||
<<"{\"code\": \"RESOURCE_NOT_FOUND\", \"reason\": \"Client id not found\"}">>).
|
<<"{\"code\": \"RESOURCE_NOT_FOUND\", \"reason\": \"Client id not found\"}">>).
|
||||||
|
|
||||||
api_spec() ->
|
api_spec() ->
|
||||||
{apis(), schemas()}.
|
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
|
||||||
|
|
||||||
apis() ->
|
paths() ->
|
||||||
[ clients_api()
|
[ "/clients"
|
||||||
, client_api()
|
, "/clients/:clientid"
|
||||||
, clients_authz_cache_api()
|
, "/clients/:clientid/authz_cache"
|
||||||
, clients_subscriptions_api()
|
, "/clients/:clientid/subscriptions"
|
||||||
, subscribe_api()
|
, "/clients/:clientid/subscribe"
|
||||||
, unsubscribe_api()
|
, "/clients/:clientid/unsubscribe"
|
||||||
, keepalive_api()
|
, "/clients/:clientid/keepalive"
|
||||||
].
|
].
|
||||||
|
|
||||||
schemas() ->
|
schema("/clients") ->
|
||||||
Client = #{
|
#{
|
||||||
client => #{
|
'operationId' => clients,
|
||||||
type => object,
|
|
||||||
properties => emqx_mgmt_util:properties(properties(client))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
AuthzCache = #{
|
|
||||||
authz_cache => #{
|
|
||||||
type => object,
|
|
||||||
properties => emqx_mgmt_util:properties(properties(authz_cache))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[Client, AuthzCache].
|
|
||||||
|
|
||||||
properties(client) ->
|
|
||||||
[
|
|
||||||
{awaiting_rel_cnt, integer,
|
|
||||||
<<"v4 api name [awaiting_rel] Number of awaiting PUBREC packet">>},
|
|
||||||
{awaiting_rel_max, integer,
|
|
||||||
<<"v4 api name [max_awaiting_rel]. Maximum allowed number of awaiting PUBREC packet">>},
|
|
||||||
{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, rfc3339">>},
|
|
||||||
{created_at, string ,
|
|
||||||
<<"Session creation time, rfc3339">>},
|
|
||||||
{disconnected_at, string ,
|
|
||||||
<<"Client offline time. It's 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">>},
|
|
||||||
{inflight_max, integer,
|
|
||||||
<<"v4 api name [max_inflight]. Maximum length of inflight">>},
|
|
||||||
{ip_address, string ,
|
|
||||||
<<"Client's IP address">>},
|
|
||||||
{port, integer,
|
|
||||||
<<"Client's port">>},
|
|
||||||
{is_bridge, boolean,
|
|
||||||
<<"Indicates whether the client is connectedvia bridge">>},
|
|
||||||
{keepalive, integer,
|
|
||||||
<<"keepalive time, with the unit of second">>},
|
|
||||||
{mailbox_len, integer,
|
|
||||||
<<"Process mailbox size">>},
|
|
||||||
{mqueue_dropped, integer,
|
|
||||||
<<"Number of messages dropped by the message queue due to exceeding the length">>},
|
|
||||||
{mqueue_len, integer,
|
|
||||||
<<"Current length of message queue">>},
|
|
||||||
{mqueue_max, integer,
|
|
||||||
<<"v4 api name [max_mqueue]. Maximum length of message queue">>},
|
|
||||||
{node, string ,
|
|
||||||
<<"Name of the node to which the client is connected">>},
|
|
||||||
{proto_name, string ,
|
|
||||||
<<"Client protocol name">>},
|
|
||||||
{proto_ver, integer,
|
|
||||||
<<"Protocol version used by the client">>},
|
|
||||||
{recv_cnt, integer,
|
|
||||||
<<"Number of TCP packets received">>},
|
|
||||||
{recv_msg, integer,
|
|
||||||
<<"Number of PUBLISH packets received">>},
|
|
||||||
{'recv_msg.qos0', integer,
|
|
||||||
<<"Number of PUBLISH QoS0 packets received">>},
|
|
||||||
{'recv_msg.qos1', integer,
|
|
||||||
<<"Number of PUBLISH QoS1 packets received">>},
|
|
||||||
{'recv_msg.qos2', integer,
|
|
||||||
<<"Number of PUBLISH QoS2 packets received">>},
|
|
||||||
{'recv_msg.dropped', integer,
|
|
||||||
<<"Number of dropped PUBLISH messages">>},
|
|
||||||
{'recv_msg.dropped.await_pubrel_timeout', integer,
|
|
||||||
<<"Number of dropped PUBLISH messages due to waiting PUBREL timeout">>},
|
|
||||||
{recv_oct, integer,
|
|
||||||
<<"Number of bytes received by EMQ X Broker (the same below)">>},
|
|
||||||
{recv_pkt, integer,
|
|
||||||
<<"Number of MQTT packets received">>},
|
|
||||||
{reductions, integer,
|
|
||||||
<<"Erlang reduction">>},
|
|
||||||
{send_cnt, integer,
|
|
||||||
<<"Number of TCP packets sent">>},
|
|
||||||
{send_msg, integer,
|
|
||||||
<<"Number of PUBLISH messages sent">>},
|
|
||||||
{'send_msg.qos0', integer,
|
|
||||||
<<"Number of PUBLISH QoS0 messages sent">>},
|
|
||||||
{'send_msg.qos1', integer,
|
|
||||||
<<"Number of PUBLISH QoS1 messages sent">>},
|
|
||||||
{'send_msg.qos2', integer,
|
|
||||||
<<"Number of PUBLISH QoS2 messages sent">>},
|
|
||||||
{'send_msg.dropped', integer,
|
|
||||||
<<"Number of dropped PUBLISH messages">>},
|
|
||||||
{'send_msg.dropped.expired', integer,
|
|
||||||
<<"Number of dropped PUBLISH messages due to expired">>},
|
|
||||||
{'send_msg.dropped.queue_full', integer,
|
|
||||||
<<"Number of dropped PUBLISH messages due to queue full">>},
|
|
||||||
{'send_msg.dropped.too_large', integer,
|
|
||||||
<<"Number of dropped PUBLISH messages due to packet length too large">>},
|
|
||||||
{send_oct, integer,
|
|
||||||
<<"Number of bytes sent">>},
|
|
||||||
{send_pkt, integer,
|
|
||||||
<<"Number of MQTT packets sent">>},
|
|
||||||
{subscriptions_cnt, integer,
|
|
||||||
<<"Number of subscriptions established by this client.">>},
|
|
||||||
{subscriptions_max, integer,
|
|
||||||
<<"v4 api name [max_subscriptions] Maximum number of subscriptions allowed by this client">>},
|
|
||||||
{username, string ,
|
|
||||||
<<"User name of client when connecting">>},
|
|
||||||
{will_msg, string ,
|
|
||||||
<<"Client will message">>},
|
|
||||||
{zone, string ,
|
|
||||||
<<"Indicate the configuration group used by the client">>}
|
|
||||||
];
|
|
||||||
properties(authz_cache) ->
|
|
||||||
[
|
|
||||||
{access, string, <<"Access type">>},
|
|
||||||
{result, string, <<"Allow or deny">>},
|
|
||||||
{topic, string, <<"Topic name">>},
|
|
||||||
{updated_time, integer, <<"Update time">>}
|
|
||||||
].
|
|
||||||
|
|
||||||
clients_api() ->
|
|
||||||
Metadata = #{
|
|
||||||
get => #{
|
get => #{
|
||||||
description => <<"List clients">>,
|
description => <<"List clients">>,
|
||||||
parameters => [
|
parameters => [
|
||||||
#{
|
hoconsc:ref(emqx_dashboard_swagger, page),
|
||||||
name => page,
|
hoconsc:ref(emqx_dashboard_swagger, limit),
|
||||||
|
{node, hoconsc:mk(binary(), #{
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true,
|
||||||
description => <<"Page">>,
|
desc => <<"Node name">>,
|
||||||
schema => #{type => integer}
|
example => atom_to_list(node())})},
|
||||||
},
|
{username, hoconsc:mk(binary(), #{
|
||||||
#{
|
|
||||||
name => limit,
|
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true,
|
||||||
description => <<"Page limit">>,
|
desc => <<"User name">>})},
|
||||||
schema => #{type => integer}
|
{zone, hoconsc:mk(binary(), #{
|
||||||
},
|
|
||||||
#{
|
|
||||||
name => node,
|
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true})},
|
||||||
description => <<"Node name">>,
|
{ip_address, hoconsc:mk(binary(), #{
|
||||||
schema => #{type => string}
|
|
||||||
},
|
|
||||||
#{
|
|
||||||
name => username,
|
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true,
|
||||||
description => <<"User name">>,
|
desc => <<"Client's IP address">>,
|
||||||
schema => #{type => string}
|
example => <<"127.0.0.1">>})},
|
||||||
},
|
{conn_state, hoconsc:mk(hoconsc:enum([connected, idle, disconnected]), #{
|
||||||
#{
|
|
||||||
name => zone,
|
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true,
|
||||||
schema => #{type => string}
|
desc => <<"The current connection status of the client, ",
|
||||||
},
|
"the possible values are connected,idle,disconnected">>})},
|
||||||
#{
|
{clean_start, hoconsc:mk(boolean(), #{
|
||||||
name => ip_address,
|
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true,
|
||||||
description => <<"Client's IP address">>,
|
description => <<"Whether the client uses a new session">>})},
|
||||||
schema => #{type => string}
|
{proto_name, hoconsc:mk(hoconsc:enum(['MQTT', 'CoAP', 'LwM2M', 'MQTT-SN']), #{
|
||||||
},
|
|
||||||
#{
|
|
||||||
name => conn_state,
|
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true,
|
||||||
description =>
|
description => <<"Client protocol name, ",
|
||||||
<<"The current connection status of the client, ",
|
"the possible values are MQTT,CoAP,LwM2M,MQTT-SN">>})},
|
||||||
"the possible values are connected,idle,disconnected">>,
|
{proto_ver, hoconsc:mk(binary(), #{
|
||||||
schema => #{type => string, enum => [connected, idle, disconnected]}
|
|
||||||
},
|
|
||||||
#{
|
|
||||||
name => clean_start,
|
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true,
|
||||||
description => <<"Whether the client uses a new session">>,
|
desc => <<"Client protocol version">>})},
|
||||||
schema => #{type => boolean}
|
{like_clientid, hoconsc:mk(binary(), #{
|
||||||
},
|
|
||||||
#{
|
|
||||||
name => proto_name,
|
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true,
|
||||||
description =>
|
desc => <<"Fuzzy search of client identifier by substring method">>})},
|
||||||
<<"Client protocol name, ",
|
{like_username, hoconsc:mk(binary(), #{
|
||||||
"the possible values are MQTT,CoAP,LwM2M,MQTT-SN">>,
|
|
||||||
schema => #{type => string, enum => ['MQTT', 'CoAP', 'LwM2M', 'MQTT-SN']}
|
|
||||||
},
|
|
||||||
#{
|
|
||||||
name => proto_ver,
|
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true,
|
||||||
description => <<"Client protocol version">>,
|
desc => <<"Client user name, fuzzy search by substring">>})},
|
||||||
schema => #{type => string}
|
{gte_created_at, hoconsc:mk(binary(), #{
|
||||||
},
|
|
||||||
#{
|
|
||||||
name => like_clientid,
|
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true,
|
||||||
description => <<"Fuzzy search of client identifier by substring method">>,
|
desc => <<"Search client session creation time by greater",
|
||||||
schema => #{type => string}
|
" than or equal method, rfc3339 or timestamp(millisecond)">>})},
|
||||||
},
|
{lte_created_at, hoconsc:mk(binary(), #{
|
||||||
#{
|
|
||||||
name => like_username,
|
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true,
|
||||||
description => <<"Client user name, fuzzy search by substring">>,
|
desc => <<"Search client session creation time by less",
|
||||||
schema => #{type => string}
|
" than or equal method, rfc3339 or timestamp(millisecond)">>})},
|
||||||
},
|
{gte_connected_at, hoconsc:mk(binary(), #{
|
||||||
#{
|
|
||||||
name => gte_created_at,
|
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true,
|
||||||
description =>
|
desc => <<"Search client connection creation time by greater"
|
||||||
<<"Search client session creation time by greater than or equal method, "
|
" than or equal method, rfc3339 or timestamp(millisecond)">>})},
|
||||||
"rfc3339 or timestamp(millisecond)">>,
|
{lte_connected_at, hoconsc:mk(binary(), #{
|
||||||
schema => #{type => string}
|
|
||||||
},
|
|
||||||
#{
|
|
||||||
name => lte_created_at,
|
|
||||||
in => query,
|
in => query,
|
||||||
required => false,
|
nullable => true,
|
||||||
description =>
|
desc => <<"Search client connection creation time by less"
|
||||||
<<"Search client session creation time by less than or equal method, ",
|
" than or equal method, rfc3339 or timestamp(millisecond)">>})}
|
||||||
"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 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 or timestamp(millisecond) ">>,
|
|
||||||
schema => #{type => string}
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
responses => #{
|
responses => #{
|
||||||
<<"200">> => emqx_mgmt_util:array_schema(client, <<"List clients 200 OK">>),
|
200 => [
|
||||||
<<"400">> => emqx_mgmt_util:error_schema( <<"Invalid parameters">>
|
{data, hoconsc:mk(hoconsc:array(hoconsc:ref(?MODULE, client)), #{})},
|
||||||
, ['INVALID_PARAMETER'])}}},
|
{meta, hoconsc:mk(hoconsc:ref(?MODULE, meta), #{})}
|
||||||
{"/clients", Metadata, clients}.
|
],
|
||||||
|
400 =>
|
||||||
|
emqx_dashboard_swagger:error_codes(
|
||||||
|
['INVALID_PARAMETER'], <<"Invalid parameters">>)}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
client_api() ->
|
schema("/clients/:clientid") ->
|
||||||
Metadata = #{
|
#{
|
||||||
|
'operationId' => client,
|
||||||
get => #{
|
get => #{
|
||||||
description => <<"Get clients info by client ID">>,
|
description => <<"Get clients info by client ID">>,
|
||||||
parameters => [#{
|
parameters => [{clientid, hoconsc:mk(binary(), #{in => path})}],
|
||||||
name => clientid,
|
|
||||||
in => path,
|
|
||||||
schema => #{type => string},
|
|
||||||
required => true
|
|
||||||
}],
|
|
||||||
responses => #{
|
responses => #{
|
||||||
<<"404">> => emqx_mgmt_util:error_schema(<<"Client id not found">>),
|
200 => hoconsc:mk(hoconsc:ref(?MODULE, client), #{}),
|
||||||
<<"200">> => emqx_mgmt_util:schema(client, <<"List clients 200 OK">>)}},
|
404 => emqx_dashboard_swagger:error_codes(
|
||||||
|
['CLIENTID_NOT_FOUND'], <<"Client id not found">>)}},
|
||||||
delete => #{
|
delete => #{
|
||||||
description => <<"Kick out client by client ID">>,
|
description => <<"Kick out client by client ID">>,
|
||||||
parameters => [#{
|
parameters => [
|
||||||
name => clientid,
|
{clientid, hoconsc:mk(binary(), #{in => path})}],
|
||||||
in => path,
|
|
||||||
schema => #{type => string},
|
|
||||||
required => true
|
|
||||||
}],
|
|
||||||
responses => #{
|
responses => #{
|
||||||
<<"404">> => emqx_mgmt_util:error_schema(<<"Client id not found">>),
|
204 => <<"Kick out client successfully">>,
|
||||||
<<"204">> => emqx_mgmt_util:schema(<<"Kick out client successfully">>)}}},
|
404 => emqx_dashboard_swagger:error_codes(
|
||||||
{"/clients/:clientid", Metadata, client}.
|
['CLIENTID_NOT_FOUND'], <<"Client id not found">>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
clients_authz_cache_api() ->
|
schema("/clients/:clientid/authz_cache") ->
|
||||||
Metadata = #{
|
#{
|
||||||
|
'operationId' => authz_cache,
|
||||||
get => #{
|
get => #{
|
||||||
description => <<"Get client authz cache">>,
|
description => <<"Get client authz cache">>,
|
||||||
parameters => [#{
|
parameters => [{clientid, hoconsc:mk(binary(), #{in => path})}],
|
||||||
name => clientid,
|
|
||||||
in => path,
|
|
||||||
schema => #{type => string},
|
|
||||||
required => true
|
|
||||||
}],
|
|
||||||
responses => #{
|
responses => #{
|
||||||
<<"404">> => emqx_mgmt_util:error_schema(<<"Client id not found">>),
|
200 => hoconsc:mk(hoconsc:ref(?MODULE, authz_cache), #{}),
|
||||||
<<"200">> => emqx_mgmt_util:schema(authz_cache, <<"Get client authz cache">>)}},
|
404 => emqx_dashboard_swagger:error_codes(
|
||||||
|
['CLIENTID_NOT_FOUND'], <<"Client id not found">>)
|
||||||
|
}
|
||||||
|
},
|
||||||
delete => #{
|
delete => #{
|
||||||
description => <<"Clean client authz cache">>,
|
description => <<"Clean client authz cache">>,
|
||||||
parameters => [#{
|
parameters => [{clientid, hoconsc:mk(binary(), #{in => path})}],
|
||||||
name => clientid,
|
|
||||||
in => path,
|
|
||||||
schema => #{type => string},
|
|
||||||
required => true
|
|
||||||
}],
|
|
||||||
responses => #{
|
responses => #{
|
||||||
<<"404">> => emqx_mgmt_util:error_schema(<<"Client id not found">>),
|
204 => <<"Kick out client successfully">>,
|
||||||
<<"204">> => emqx_mgmt_util:schema(<<"Clean client authz cache successfully">>)}}},
|
404 => emqx_dashboard_swagger:error_codes(
|
||||||
{"/clients/:clientid/authz_cache", Metadata, authz_cache}.
|
['CLIENTID_NOT_FOUND'], <<"Client id not found">>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
clients_subscriptions_api() ->
|
schema("/clients/:clientid/subscriptions") ->
|
||||||
Metadata = #{
|
#{
|
||||||
|
'operationId' => subscriptions,
|
||||||
get => #{
|
get => #{
|
||||||
description => <<"Get client subscriptions">>,
|
description => <<"Get client subscriptions">>,
|
||||||
parameters => [#{
|
parameters => [{clientid, hoconsc:mk(binary(), #{in => path})}],
|
||||||
name => clientid,
|
|
||||||
in => path,
|
|
||||||
schema => #{type => string},
|
|
||||||
required => true
|
|
||||||
}],
|
|
||||||
responses => #{
|
responses => #{
|
||||||
<<"200">> =>
|
200 => hoconsc:mk(hoconsc:array(hoconsc:ref(emqx_mgmt_api_subscriptions, subscription)), #{}),
|
||||||
emqx_mgmt_util:array_schema(subscription, <<"Get client subscriptions">>)}}
|
404 => emqx_dashboard_swagger:error_codes(
|
||||||
},
|
['CLIENTID_NOT_FOUND'], <<"Client id not found">>)
|
||||||
{"/clients/:clientid/subscriptions", Metadata, subscriptions}.
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
unsubscribe_api() ->
|
schema("/clients/:clientid/subscribe") ->
|
||||||
Metadata = #{
|
#{
|
||||||
post => #{
|
'operationId' => subscribe,
|
||||||
description => <<"Unsubscribe">>,
|
|
||||||
parameters => [
|
|
||||||
#{
|
|
||||||
name => clientid,
|
|
||||||
in => path,
|
|
||||||
schema => #{type => string},
|
|
||||||
required => true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'requestBody' => emqx_mgmt_util:schema(#{
|
|
||||||
type => object,
|
|
||||||
properties => #{
|
|
||||||
topic => #{
|
|
||||||
type => string,
|
|
||||||
description => <<"Topic">>}}}),
|
|
||||||
responses => #{
|
|
||||||
<<"404">> => emqx_mgmt_util:error_schema(<<"Client id not found">>),
|
|
||||||
<<"200">> => emqx_mgmt_util:schema(<<"Unsubscribe ok">>)}}},
|
|
||||||
{"/clients/:clientid/unsubscribe", Metadata, unsubscribe}.
|
|
||||||
subscribe_api() ->
|
|
||||||
Metadata = #{
|
|
||||||
post => #{
|
post => #{
|
||||||
description => <<"Subscribe">>,
|
description => <<"Subscribe">>,
|
||||||
parameters => [#{
|
parameters => [{clientid, hoconsc:mk(binary(), #{in => path})}],
|
||||||
name => clientid,
|
'requestBody' => hoconsc:mk(hoconsc:ref(?MODULE, subscribe)),
|
||||||
in => path,
|
|
||||||
schema => #{type => string},
|
|
||||||
required => true
|
|
||||||
}],
|
|
||||||
'requestBody' => emqx_mgmt_util:schema(#{
|
|
||||||
type => object,
|
|
||||||
properties => #{
|
|
||||||
topic => #{
|
|
||||||
type => string,
|
|
||||||
description => <<"Topic">>},
|
|
||||||
qos => #{
|
|
||||||
type => integer,
|
|
||||||
enum => [0, 1, 2],
|
|
||||||
example => 0,
|
|
||||||
description => <<"QoS">>}}}),
|
|
||||||
responses => #{
|
responses => #{
|
||||||
<<"404">> => emqx_mgmt_util:error_schema(<<"Client id not found">>),
|
200 => hoconsc:ref(emqx_mgmt_api_subscriptions, subscription),
|
||||||
<<"200">> => emqx_mgmt_util:schema(<<"Subscribe ok">>)}}},
|
404 => emqx_dashboard_swagger:error_codes(
|
||||||
{"/clients/:clientid/subscribe", Metadata, subscribe}.
|
['CLIENTID_NOT_FOUND'], <<"Client id not found">>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
keepalive_api() ->
|
schema("/clients/:clientid/unsubscribe") ->
|
||||||
Metadata = #{
|
#{
|
||||||
put => #{
|
'operationId' => unsubscribe,
|
||||||
description => <<"set the online client keepalive by second ">>,
|
post => #{
|
||||||
parameters => [#{
|
description => <<"Unsubscribe">>,
|
||||||
name => clientid,
|
parameters => [{clientid, hoconsc:mk(binary(), #{in => path})}],
|
||||||
in => path,
|
'requestBody' => hoconsc:mk(hoconsc:ref(?MODULE, unsubscribe)),
|
||||||
schema => #{type => string},
|
|
||||||
required => true
|
|
||||||
},
|
|
||||||
#{
|
|
||||||
name => interval,
|
|
||||||
in => query,
|
|
||||||
schema => #{type => integer},
|
|
||||||
required => true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
responses => #{
|
responses => #{
|
||||||
<<"404">> => emqx_mgmt_util:error_schema(<<"Client id not found">>),
|
204 => <<"Unsubscribe OK">>,
|
||||||
<<"400">> => emqx_mgmt_util:error_schema(<<"">>, ['PARAMS_ERROR']),
|
404 => emqx_dashboard_swagger:error_codes(
|
||||||
<<"200">> => emqx_mgmt_util:schema(<<"ok">>)}}},
|
['CLIENTID_NOT_FOUND'], <<"Client id not found">>)
|
||||||
{"/clients/:clientid/keepalive", Metadata, set_keepalive}.
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
schema("/clients/:clientid/keepalive") ->
|
||||||
|
#{
|
||||||
|
'operationId' => set_keepalive,
|
||||||
|
put => #{
|
||||||
|
description => <<"Set the online client keepalive by seconds">>,
|
||||||
|
parameters => [{clientid, hoconsc:mk(binary(), #{in => path})}],
|
||||||
|
'requestBody' => hoconsc:mk(hoconsc:ref(?MODULE, keepalive)),
|
||||||
|
responses => #{
|
||||||
|
200 => hoconsc:mk(hoconsc:ref(?MODULE, client), #{}),
|
||||||
|
404 => emqx_dashboard_swagger:error_codes(
|
||||||
|
['CLIENTID_NOT_FOUND'], <<"Client id not found">>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.
|
||||||
|
|
||||||
|
fields(client) ->
|
||||||
|
[
|
||||||
|
{awaiting_rel_cnt, hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"v4 api name [awaiting_rel] Number of awaiting PUBREC packet">>})},
|
||||||
|
{awaiting_rel_max, hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"v4 api name [max_awaiting_rel]. "
|
||||||
|
"Maximum allowed number of awaiting PUBREC packet">>})},
|
||||||
|
{clean_start, hoconsc:mk(boolean(), #{desc =>
|
||||||
|
<<"Indicate whether the client is using a brand new session">>})},
|
||||||
|
{clientid, hoconsc:mk(binary(), #{desc => <<"Client identifier">>})},
|
||||||
|
{connected, hoconsc:mk(boolean(), #{desc => <<"Whether the client is connected">>})},
|
||||||
|
{connected_at, hoconsc:mk(binary(), #{desc => <<"Client connection time, rfc3339">>})},
|
||||||
|
{created_at, hoconsc:mk(binary(), #{desc => <<"Session creation time, rfc3339">>})},
|
||||||
|
{disconnected_at, hoconsc:mk(binary(), #{desc =>
|
||||||
|
<<"Client offline time."
|
||||||
|
" It's Only valid and returned when connected is false, rfc3339">>})},
|
||||||
|
{expiry_interval, hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Session expiration interval, with the unit of second">>})},
|
||||||
|
{heap_size, hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Process heap size with the unit of byte">>})},
|
||||||
|
{inflight_cnt, hoconsc:mk(integer(), #{desc => <<"Current length of inflight">>})},
|
||||||
|
{inflight_max, hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"v4 api name [max_inflight]. Maximum length of inflight">>})},
|
||||||
|
{ip_address, hoconsc:mk(binary(), #{desc => <<"Client's IP address">>})},
|
||||||
|
{is_bridge, hoconsc:mk(boolean(), #{desc =>
|
||||||
|
<<"Indicates whether the client is connectedvia bridge">>})},
|
||||||
|
{keepalive, hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"keepalive time, with the unit of second">>})},
|
||||||
|
{mailbox_len, hoconsc:mk(integer(), #{desc => <<"Process mailbox size">>})},
|
||||||
|
{mqueue_dropped, hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of messages dropped by the message queue due to exceeding the length">>})},
|
||||||
|
{mqueue_len, hoconsc:mk(integer(), #{desc => <<"Current length of message queue">>})},
|
||||||
|
{mqueue_max, hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"v4 api name [max_mqueue]. Maximum length of message queue">>})},
|
||||||
|
{node, hoconsc:mk(binary(), #{desc =>
|
||||||
|
<<"Name of the node to which the client is connected">>})},
|
||||||
|
{port, hoconsc:mk(integer(), #{desc => <<"Client's port">>})},
|
||||||
|
{proto_name, hoconsc:mk(binary(), #{desc => <<"Client protocol name">>})},
|
||||||
|
{proto_ver, hoconsc:mk(integer(), #{desc => <<"Protocol version used by the client">>})},
|
||||||
|
{recv_cnt, hoconsc:mk(integer(), #{desc => <<"Number of TCP packets received">>})},
|
||||||
|
{recv_msg, hoconsc:mk(integer(), #{desc => <<"Number of PUBLISH packets received">>})},
|
||||||
|
{'recv_msg.dropped', hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of dropped PUBLISH packets">>})},
|
||||||
|
{'recv_msg.dropped.await_pubrel_timeout', hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of dropped PUBLISH packets due to expired">>})},
|
||||||
|
{'recv_msg.qos0', hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of PUBLISH QoS0 packets received">>})},
|
||||||
|
{'recv_msg.qos1', hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of PUBLISH QoS1 packets received">>})},
|
||||||
|
{'recv_msg.qos2', hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of PUBLISH QoS2 packets received">>})},
|
||||||
|
{recv_oct, hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of bytes received by EMQ X Broker (the same below)">>})},
|
||||||
|
{recv_pkt, hoconsc:mk(integer(), #{desc => <<"Number of MQTT packets received">>})},
|
||||||
|
{reductions, hoconsc:mk(integer(), #{desc => <<"Erlang reduction">>})},
|
||||||
|
{send_cnt, hoconsc:mk(integer(), #{desc => <<"Number of TCP packets sent">>})},
|
||||||
|
{send_msg, hoconsc:mk(integer(), #{desc => <<"Number of PUBLISH packets sent">>})},
|
||||||
|
{'send_msg.dropped', hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of dropped PUBLISH packets">>})},
|
||||||
|
{'send_msg.dropped.expired', hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of dropped PUBLISH packets due to expired">>})},
|
||||||
|
{'send_msg.dropped.queue_full', hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of dropped PUBLISH packets due to queue full">>})},
|
||||||
|
{'send_msg.dropped.too_large', hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of dropped PUBLISH packets due to packet length too large">>})},
|
||||||
|
{'send_msg.qos0', hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of PUBLISH QoS0 packets sent">>})},
|
||||||
|
{'send_msg.qos1', hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of PUBLISH QoS1 packets sent">>})},
|
||||||
|
{'send_msg.qos2', hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of PUBLISH QoS2 packets sent">>})},
|
||||||
|
{send_oct, hoconsc:mk(integer(), #{desc => <<"Number of bytes sent">>})},
|
||||||
|
{send_pkt, hoconsc:mk(integer(), #{desc => <<"Number of MQTT packets sent">>})},
|
||||||
|
{subscriptions_cnt, hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"Number of subscriptions established by this client.">>})},
|
||||||
|
{subscriptions_max, hoconsc:mk(integer(), #{desc =>
|
||||||
|
<<"v4 api name [max_subscriptions]",
|
||||||
|
" Maximum number of subscriptions allowed by this client">>})},
|
||||||
|
{username, hoconsc:mk(binary(), #{desc => <<"User name of client when connecting">>})},
|
||||||
|
{will_msg, hoconsc:mk(binary(), #{desc => <<"Client will message">>})},
|
||||||
|
{zone, hoconsc:mk(binary(), #{desc =>
|
||||||
|
<<"Indicate the configuration group used by the client">>})}
|
||||||
|
];
|
||||||
|
|
||||||
|
fields(authz_cache) ->
|
||||||
|
[
|
||||||
|
{access, hoconsc:mk(binary(), #{desc => <<"Access type">>})},
|
||||||
|
{result, hoconsc:mk(binary(), #{desc => <<"Allow or deny">>})},
|
||||||
|
{topic, hoconsc:mk(binary(), #{desc => <<"Topic name">>})},
|
||||||
|
{updated_time, hoconsc:mk(integer(), #{desc => <<"Update time">>})}
|
||||||
|
];
|
||||||
|
|
||||||
|
fields(keepalive) ->
|
||||||
|
[
|
||||||
|
{interval, hoconsc:mk(integer(), #{desc => <<"Keepalive time, with the unit of second">>})}
|
||||||
|
];
|
||||||
|
|
||||||
|
fields(subscribe) ->
|
||||||
|
[
|
||||||
|
{topic, hoconsc:mk(binary(), #{desc => <<"Access type">>})},
|
||||||
|
{qos, hoconsc:mk(emqx_schema:qos(), #{desc => <<"QoS">>})}
|
||||||
|
];
|
||||||
|
|
||||||
|
fields(unsubscribe) ->
|
||||||
|
[
|
||||||
|
{topic, hoconsc:mk(binary(), #{desc => <<"Access type">>})}
|
||||||
|
];
|
||||||
|
|
||||||
|
fields(meta) ->
|
||||||
|
emqx_dashboard_swagger:fields(page) ++
|
||||||
|
emqx_dashboard_swagger:fields(limit) ++
|
||||||
|
[{count, hoconsc:mk(integer(), #{example => 1})}].
|
||||||
|
|
||||||
%%%==============================================================================================
|
%%%==============================================================================================
|
||||||
%% parameters trans
|
%% parameters trans
|
||||||
clients(get, #{query_string := Qs}) ->
|
clients(get, #{query_string := Qs}) ->
|
||||||
list(emqx_mgmt_api:ensure_timestamp_format(Qs, time_keys())).
|
list_clients(emqx_mgmt_api:ensure_timestamp_format(Qs, time_keys())).
|
||||||
|
|
||||||
client(get, #{bindings := Bindings}) ->
|
client(get, #{bindings := Bindings}) ->
|
||||||
lookup(Bindings);
|
lookup(Bindings);
|
||||||
|
@ -529,13 +436,12 @@ subscriptions(get, #{bindings := #{clientid := ClientID}}) ->
|
||||||
{200, lists:map(Formatter, Subs)}
|
{200, lists:map(Formatter, Subs)}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
set_keepalive(put, #{bindings := #{clientid := ClientID}, query_string := Query}) ->
|
set_keepalive(put, #{bindings := #{clientid := ClientID}, body := Body}) ->
|
||||||
case maps:find(<<"interval">>, Query) of
|
case maps:find(<<"interval">>, Body) of
|
||||||
error -> {404, "Interval Not Found"};
|
error -> {400, 'BAD_REQUEST',"Interval Not Found"};
|
||||||
{ok, Interval0} ->
|
{ok, Interval} ->
|
||||||
Interval = binary_to_integer(Interval0),
|
|
||||||
case emqx_mgmt:set_keepalive(emqx_mgmt_util:urldecode(ClientID), Interval) of
|
case emqx_mgmt:set_keepalive(emqx_mgmt_util:urldecode(ClientID), Interval) of
|
||||||
ok -> {200};
|
ok -> lookup(#{clientid => ClientID});
|
||||||
{error, not_found} ->{404, ?CLIENT_ID_NOT_FOUND};
|
{error, not_found} ->{404, ?CLIENT_ID_NOT_FOUND};
|
||||||
{error, Reason} -> {400, #{code => 'PARAMS_ERROR', message => Reason}}
|
{error, Reason} -> {400, #{code => 'PARAMS_ERROR', message => Reason}}
|
||||||
end
|
end
|
||||||
|
@ -544,7 +450,7 @@ set_keepalive(put, #{bindings := #{clientid := ClientID}, query_string := Query}
|
||||||
%%%==============================================================================================
|
%%%==============================================================================================
|
||||||
%% api apply
|
%% api apply
|
||||||
|
|
||||||
list(Params) ->
|
list_clients(Params) ->
|
||||||
{Tab, QuerySchema} = ?CLIENT_QS_SCHEMA,
|
{Tab, QuerySchema} = ?CLIENT_QS_SCHEMA,
|
||||||
case maps:get(<<"node">>, Params, undefined) of
|
case maps:get(<<"node">>, Params, undefined) of
|
||||||
undefined ->
|
undefined ->
|
||||||
|
@ -590,7 +496,7 @@ get_authz_cache(#{clientid := ClientID})->
|
||||||
clean_authz_cache(#{clientid := ClientID}) ->
|
clean_authz_cache(#{clientid := ClientID}) ->
|
||||||
case emqx_mgmt:clean_authz_cache(ClientID) of
|
case emqx_mgmt:clean_authz_cache(ClientID) of
|
||||||
ok ->
|
ok ->
|
||||||
{200};
|
{204};
|
||||||
{error, not_found} ->
|
{error, not_found} ->
|
||||||
{404, ?CLIENT_ID_NOT_FOUND};
|
{404, ?CLIENT_ID_NOT_FOUND};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
|
@ -605,8 +511,15 @@ subscribe(#{clientid := ClientID, topic := Topic, qos := Qos}) ->
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
Message = list_to_binary(io_lib:format("~p", [Reason])),
|
Message = list_to_binary(io_lib:format("~p", [Reason])),
|
||||||
{500, #{code => <<"UNKNOW_ERROR">>, message => Message}};
|
{500, #{code => <<"UNKNOW_ERROR">>, message => Message}};
|
||||||
ok ->
|
{ok, Node} ->
|
||||||
{200}
|
Response =
|
||||||
|
#{
|
||||||
|
clientid => ClientID,
|
||||||
|
topic => Topic,
|
||||||
|
qos => Qos,
|
||||||
|
node => Node
|
||||||
|
},
|
||||||
|
{200, Response}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
unsubscribe(#{clientid := ClientID, topic := Topic}) ->
|
unsubscribe(#{clientid := ClientID, topic := Topic}) ->
|
||||||
|
@ -614,7 +527,7 @@ unsubscribe(#{clientid := ClientID, topic := Topic}) ->
|
||||||
{error, channel_not_found} ->
|
{error, channel_not_found} ->
|
||||||
{404, ?CLIENT_ID_NOT_FOUND};
|
{404, ?CLIENT_ID_NOT_FOUND};
|
||||||
{unsubscribe, [{Topic, #{}}]} ->
|
{unsubscribe, [{Topic, #{}}]} ->
|
||||||
{200}
|
{204}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
subscribe_batch(#{clientid := ClientID, topics := Topics}) ->
|
subscribe_batch(#{clientid := ClientID, topics := Topics}) ->
|
||||||
|
@ -630,10 +543,10 @@ do_subscribe(ClientID, Topic0, Qos) ->
|
||||||
case emqx_mgmt:subscribe(ClientID, TopicTable) of
|
case emqx_mgmt:subscribe(ClientID, TopicTable) of
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{error, Reason};
|
{error, Reason};
|
||||||
{subscribe, Subscriptions} ->
|
{subscribe, Subscriptions, Node} ->
|
||||||
case proplists:is_defined(Topic, Subscriptions) of
|
case proplists:is_defined(Topic, Subscriptions) of
|
||||||
true ->
|
true ->
|
||||||
ok;
|
{ok, Node};
|
||||||
false ->
|
false ->
|
||||||
{error, unknow_error}
|
{error, unknow_error}
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,15 +18,14 @@
|
||||||
|
|
||||||
-behaviour(minirest_api).
|
-behaviour(minirest_api).
|
||||||
|
|
||||||
|
-include_lib("typerefl/include/types.hrl").
|
||||||
-include_lib("emqx/include/emqx.hrl").
|
-include_lib("emqx/include/emqx.hrl").
|
||||||
|
-include_lib("emqx/include/emqx_mqtt.hrl").
|
||||||
|
|
||||||
-import(emqx_mgmt_util, [ page_schema/1
|
-export([ api_spec/0
|
||||||
, error_schema/2
|
, paths/0
|
||||||
, properties/1
|
, schema/1
|
||||||
, page_params/0
|
, fields/1]).
|
||||||
]).
|
|
||||||
|
|
||||||
-export([api_spec/0]).
|
|
||||||
|
|
||||||
-export([subscriptions/2]).
|
-export([subscriptions/2]).
|
||||||
|
|
||||||
|
@ -46,73 +45,73 @@
|
||||||
-define(format_fun, {?MODULE, format}).
|
-define(format_fun, {?MODULE, format}).
|
||||||
|
|
||||||
api_spec() ->
|
api_spec() ->
|
||||||
{subscriptions_api(), subscription_schema()}.
|
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
|
||||||
|
|
||||||
subscriptions_api() ->
|
paths() ->
|
||||||
MetaData = #{
|
["/subscriptions"].
|
||||||
|
|
||||||
|
schema("/subscriptions") ->
|
||||||
|
#{
|
||||||
|
'operationId' => subscriptions,
|
||||||
get => #{
|
get => #{
|
||||||
description => <<"List subscriptions">>,
|
description => <<"List subscriptions">>,
|
||||||
parameters => parameters(),
|
parameters => parameters(),
|
||||||
responses => #{
|
responses => #{
|
||||||
<<"200">> => page_schema(subscription),
|
200 => hoconsc:mk(hoconsc:array(hoconsc:ref(?MODULE, subscription)), #{})}}
|
||||||
<<"400">> => error_schema(<<"Invalid parameters">>, ['INVALID_PARAMETER'])
|
}.
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[{"/subscriptions", MetaData, subscriptions}].
|
|
||||||
|
|
||||||
subscription_schema() ->
|
fields(subscription) ->
|
||||||
Props = properties([
|
[
|
||||||
{node, string},
|
{node, hoconsc:mk(binary(), #{desc => <<"Access type">>})},
|
||||||
{topic, string},
|
{topic, hoconsc:mk(binary(), #{desc => <<"Topic name">>})},
|
||||||
{clientid, string},
|
{clientid, hoconsc:mk(binary(), #{desc => <<"Client identifier">>})},
|
||||||
{qos, integer, <<>>, [0,1,2]}]),
|
{qos, hoconsc:mk(emqx_schema:qos(), #{desc => <<"QoS">>})}
|
||||||
[#{subscription => #{type => object, properties => Props}}].
|
].
|
||||||
|
|
||||||
parameters() ->
|
parameters() ->
|
||||||
[
|
[
|
||||||
#{
|
hoconsc:ref(emqx_dashboard_swagger, page),
|
||||||
name => clientid,
|
hoconsc:ref(emqx_dashboard_swagger, limit),
|
||||||
|
{
|
||||||
|
node, hoconsc:mk(binary(), #{
|
||||||
in => query,
|
in => query,
|
||||||
description => <<"Client ID">>,
|
nullable => true,
|
||||||
schema => #{type => string}
|
desc => <<"Node name">>,
|
||||||
|
example => atom_to_list(node())})
|
||||||
},
|
},
|
||||||
#{
|
{
|
||||||
name => node,
|
clientid, hoconsc:mk(binary(), #{
|
||||||
in => query,
|
in => query,
|
||||||
description => <<"Node name">>,
|
nullable => true,
|
||||||
schema => #{type => string}
|
desc => <<"Client ID">>})
|
||||||
},
|
},
|
||||||
#{
|
{
|
||||||
name => qos,
|
qos, hoconsc:mk(emqx_schema:qos(), #{
|
||||||
in => query,
|
in => query,
|
||||||
description => <<"QoS">>,
|
nullable => true,
|
||||||
schema => #{type => integer, enum => [0, 1, 2]}
|
desc => <<"QoS">>})
|
||||||
},
|
},
|
||||||
#{
|
{
|
||||||
name => share_group,
|
topic, hoconsc:mk(binary(), #{
|
||||||
in => query,
|
in => query,
|
||||||
description => <<"Shared subscription group name">>,
|
nullable => true,
|
||||||
schema => #{type => string}
|
desc => <<"Topic, url encoding">>})
|
||||||
},
|
},
|
||||||
#{
|
{
|
||||||
name => topic,
|
match_topic, hoconsc:mk(binary(), #{
|
||||||
in => query,
|
in => query,
|
||||||
description => <<"Topic, url encoding">>,
|
nullable => true,
|
||||||
schema => #{type => string}
|
desc => <<"Match topic string, url encoding">>})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
share_group, hoconsc:mk(binary(), #{
|
||||||
|
in => query,
|
||||||
|
nullable => true,
|
||||||
|
desc => <<"Shared subscription group name">>})
|
||||||
}
|
}
|
||||||
#{
|
|
||||||
name => match_topic,
|
|
||||||
in => query,
|
|
||||||
description => <<"Match topic string, url encoding">>,
|
|
||||||
schema => #{type => string}
|
|
||||||
} | page_params()
|
|
||||||
].
|
].
|
||||||
|
|
||||||
subscriptions(get, #{query_string := Params}) ->
|
subscriptions(get, #{query_string := Params}) ->
|
||||||
list(Params).
|
|
||||||
|
|
||||||
list(Params) ->
|
|
||||||
{Tab, QuerySchema} = ?SUBS_QS_SCHEMA,
|
{Tab, QuerySchema} = ?SUBS_QS_SCHEMA,
|
||||||
case maps:get(<<"node">>, Params, undefined) of
|
case maps:get(<<"node">>, Params, undefined) of
|
||||||
undefined ->
|
undefined ->
|
||||||
|
|
|
@ -96,8 +96,9 @@ t_clients(_) ->
|
||||||
%% post /clients/:clientid/unsubscribe
|
%% post /clients/:clientid/unsubscribe
|
||||||
UnSubscribePath = emqx_mgmt_api_test_util:api_path(["clients",
|
UnSubscribePath = emqx_mgmt_api_test_util:api_path(["clients",
|
||||||
binary_to_list(ClientId1), "unsubscribe"]),
|
binary_to_list(ClientId1), "unsubscribe"]),
|
||||||
|
UnSubscribeBody = #{topic => Topic},
|
||||||
{ok, _} = emqx_mgmt_api_test_util:request_api(post, UnSubscribePath,
|
{ok, _} = emqx_mgmt_api_test_util:request_api(post, UnSubscribePath,
|
||||||
"", AuthHeader, SubscribeBody),
|
"", AuthHeader, UnSubscribeBody),
|
||||||
timer:sleep(100),
|
timer:sleep(100),
|
||||||
?assertEqual([], emqx_mgmt:lookup_subscriptions(Client1)),
|
?assertEqual([], emqx_mgmt:lookup_subscriptions(Client1)),
|
||||||
|
|
||||||
|
@ -165,15 +166,15 @@ t_query_clients_with_time(_) ->
|
||||||
t_keepalive(_Config) ->
|
t_keepalive(_Config) ->
|
||||||
Username = "user_keepalive",
|
Username = "user_keepalive",
|
||||||
ClientId = "client_keepalive",
|
ClientId = "client_keepalive",
|
||||||
AuthHeader = emqx_mgmt_api_test_util:auth_header_(),
|
AuthHeader = emqx_mgmt_api_test_util:auth_header_(),
|
||||||
Path = emqx_mgmt_api_test_util:api_path(["clients", ClientId, "keepalive"]),
|
Path = emqx_mgmt_api_test_util:api_path(["clients", ClientId, "keepalive"]),
|
||||||
Query = "interval=11",
|
Body = #{interval => 11},
|
||||||
{error,{"HTTP/1.1",404,"Not Found"}} =
|
{error,{"HTTP/1.1",404,"Not Found"}} =
|
||||||
emqx_mgmt_api_test_util:request_api(put, Path, Query, AuthHeader, <<"">>),
|
emqx_mgmt_api_test_util:request_api(put, Path, <<"">>, AuthHeader, Body),
|
||||||
{ok, C1} = emqtt:start_link(#{username => Username, clientid => ClientId}),
|
{ok, C1} = emqtt:start_link(#{username => Username, clientid => ClientId}),
|
||||||
{ok, _} = emqtt:connect(C1),
|
{ok, _} = emqtt:connect(C1),
|
||||||
{ok, Ok} = emqx_mgmt_api_test_util:request_api(put, Path, Query, AuthHeader, <<"">>),
|
{ok, NewClient} = emqx_mgmt_api_test_util:request_api(put, Path, <<"">>, AuthHeader, Body),
|
||||||
?assertEqual("", Ok),
|
#{<<"keepalive">> := 11} = emqx_json:decode(NewClient, [return_maps]),
|
||||||
[Pid] = emqx_cm:lookup_channels(list_to_binary(ClientId)),
|
[Pid] = emqx_cm:lookup_channels(list_to_binary(ClientId)),
|
||||||
#{conninfo := #{keepalive := Keepalive}} = emqx_connection:info(Pid),
|
#{conninfo := #{keepalive := Keepalive}} = emqx_connection:info(Pid),
|
||||||
?assertEqual(11, Keepalive),
|
?assertEqual(11, Keepalive),
|
||||||
|
|
|
@ -31,10 +31,8 @@
|
||||||
, stats/2
|
, stats/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-define(API_TAG_PROMETHEUS, [<<"premetheus">>]).
|
|
||||||
-define(SCHEMA_MODULE, emqx_prometheus_schema).
|
-define(SCHEMA_MODULE, emqx_prometheus_schema).
|
||||||
|
|
||||||
|
|
||||||
api_spec() ->
|
api_spec() ->
|
||||||
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
|
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true}).
|
||||||
|
|
||||||
|
@ -47,7 +45,6 @@ schema("/prometheus") ->
|
||||||
#{ 'operationId' => prometheus
|
#{ 'operationId' => prometheus
|
||||||
, get =>
|
, get =>
|
||||||
#{ description => <<"Get Prometheus config info">>
|
#{ description => <<"Get Prometheus config info">>
|
||||||
, tags => ?API_TAG_PROMETHEUS
|
|
||||||
, responses =>
|
, responses =>
|
||||||
#{200 => prometheus_config_schema()}
|
#{200 => prometheus_config_schema()}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue