diff --git a/apps/emqx_gateway/i18n/emqx_coap_api_i18n.conf b/apps/emqx_gateway/i18n/emqx_coap_api_i18n.conf
new file mode 100644
index 000000000..351beaf70
--- /dev/null
+++ b/apps/emqx_gateway/i18n/emqx_coap_api_i18n.conf
@@ -0,0 +1,58 @@
+emqx_coap_api {
+
+ send_coap_request {
+ desc {
+ en: """Send a CoAP request message to the client"""
+ zh: """ """
+ }
+ }
+
+ token {
+ desc {
+ en: """Message token, can be empty"""
+ zh: """ """
+ }
+ }
+
+ method {
+ desc {
+ en: """"Request method type"""
+ zh: """ """
+ }
+ }
+
+ timeout {
+ desc {
+ en: """Timespan for response"""
+ zh: """ """
+ }
+ }
+
+ content_type {
+ desc {
+ en: """"Payload type" """
+ zh: """ """
+ }
+ }
+
+ payload {
+ desc {
+ en: """The content of the payload"""
+ zh: """ """
+ }
+ }
+
+ message_id {
+ desc {
+ en: """Message ID"""
+ zh: """ """
+ }
+ }
+
+ response_code {
+ desc {
+ en: """Response code"""
+ zh: """ """
+ }
+ }
+}
diff --git a/apps/emqx_gateway/i18n/emqx_gateway_api_authn_i18n.conf b/apps/emqx_gateway/i18n/emqx_gateway_api_authn_i18n.conf
new file mode 100644
index 000000000..37f9a6ec6
--- /dev/null
+++ b/apps/emqx_gateway/i18n/emqx_gateway_api_authn_i18n.conf
@@ -0,0 +1,93 @@
+emqx_gateway_api_authn {
+
+ get_authn {
+ desc {
+ en: """Get the gateway authentication"""
+ zh: """ """
+ }
+ }
+
+ update_authn {
+ desc {
+ en: """Update authentication for the gateway"""
+ zh: """ """
+ }
+ }
+
+ add_authn {
+ desc {
+ en: """Add authentication for the gateway"""
+ zh: """ """
+ }
+ }
+
+ delete_authn {
+ desc {
+ en: """Remove the gateway authentication"""
+ zh: """ """
+ }
+ }
+
+ list_users {
+ desc {
+ en: """Get the users for the authentication"""
+ zh: """ """
+ }
+ }
+
+ add_user {
+ desc {
+ en: """Add user for the authentication"""
+ zh: """ """
+ }
+ }
+
+ get_user {
+ desc {
+ en: """Get user info from the gateway authentication"""
+ zh: """ """
+ }
+ }
+
+ update_user {
+ desc {
+ en: """Update the user info for the gateway authentication"""
+ zh: """ """
+ }
+ }
+
+ delete_user {
+ desc {
+ en: """Delete the user for the gateway authentication"""
+ zh: """ """
+ }
+ }
+
+ import_users {
+ desc {
+ en: """Import users into the gateway authentication"""
+ zh: """ """
+ }
+ }
+
+ user_id {
+ desc {
+ en: """User ID"""
+ zh: """ """
+ }
+ }
+
+ like_username {
+ desc {
+ en: """Fuzzy search by username"""
+ zh: """ """
+ }
+ }
+
+ like_clientid{
+ desc {
+ en: """Fuzzy search by clientid"""
+ zh: """ """
+ }
+ }
+}
diff --git a/apps/emqx_gateway/i18n/emqx_gateway_api_clients_i18n.conf b/apps/emqx_gateway/i18n/emqx_gateway_api_clients_i18n.conf
new file mode 100644
index 000000000..7aea14695
--- /dev/null
+++ b/apps/emqx_gateway/i18n/emqx_gateway_api_clients_i18n.conf
@@ -0,0 +1,507 @@
+emqx_gateway_api_clients {
+
+ list_clients {
+ desc {
+ en: """Get the gateway client list"""
+ zh: """ """
+ }
+ }
+
+ get_client {
+ desc {
+ en: """Get the gateway client information"""
+ zh: """ """
+ }
+ }
+
+ kick_client {
+ desc {
+ en: """Kick out the gateway client"""
+ zh: """ """
+ }
+ }
+
+ list_subscriptions {
+ desc {
+ en: """Get the gateway client subscriptions"""
+ zh: """ """
+ }
+ }
+
+ add_subscription {
+ desc {
+ en: """Create a subscription membership"""
+ zh: """ """
+ }
+ }
+
+ delete_subscription {
+ desc {
+ en: """Delete a subscriptions membership"""
+ zh: """ """
+ }
+ }
+
+ param_node {
+ desc {
+ en: """Match the client's node name"""
+ zh: """ """
+ }
+ }
+
+ param_clientid {
+ desc {
+ en: """Match the client's ID"""
+ zh: """ """
+ }
+ }
+
+ param_username {
+ desc {
+ en: """Match the client's Username"""
+ zh: """ """
+ }
+ }
+
+ param_ip_address {
+ desc {
+ en: """Match the client's ip address"""
+ zh: """ """
+ }
+ }
+
+ param_conn_state {
+ desc {
+ en: """Match the client's connection state"""
+ zh: """ """
+ }
+ }
+
+ param_proto_ver {
+ desc {
+ en: """Match the client's protocol version"""
+ zh: """ """
+ }
+ }
+
+ param_clean_start {
+ desc {
+ en: """Match the client's clean start flag"""
+ zh: """ """
+ }
+ }
+
+ param_like_clientid {
+ desc {
+ en: """Use sub-string to match client's ID"""
+ zh: """ """
+ }
+ }
+
+ param_like_username {
+ desc {
+ en: """Use sub-string to match client's username"""
+ zh: """ """
+ }
+ }
+
+ param_gte_created_at {
+ desc {
+ en: """Match the session created datetime greater than a certain value"""
+ zh: """ """
+ }
+ }
+
+ param_lte_created_at {
+ desc {
+ en: """Match the session created datetime less than a certain value"""
+ zh: """ """
+ }
+ }
+
+ param_gte_connected_at{
+ desc {
+ en: """Match the client socket connected datetime greater than a certain value"""
+ zh: """ """
+ }
+ }
+
+ param_lte_connected_at {
+ desc {
+ en: """Match the client socket connected datatime less than a certain value"""
+ zh: """ """
+ }
+ }
+
+ param_endpoint_name {
+ desc {
+ en: """Match the lwm2m client's endpoint name"""
+ zh: """ """
+ }
+ }
+
+ param_like_endpoint_name {
+ desc {
+ en: """Use sub-string to match lwm2m client's endpoint name"""
+ zh: """ """
+ }
+ }
+
+ param_gte_lifetime {
+ desc {
+ en: """Match the lwm2m client registered lifetime greater than a certain value"""
+ zh: """ """
+ }
+ }
+
+ param_lte_lifetime {
+ desc {
+ en: """Match the lwm2m client registered lifetime less than a certain value"""
+ zh: """ """
+ }
+ }
+
+ clientid {
+ desc {
+ en: """Client ID"""
+ zh: """ """
+ }
+ }
+
+ topic {
+ desc {
+ en: """Topic Filter/Name"""
+ zh: """ """
+ }
+ }
+
+ endpoint_name {
+ desc {
+ en: """The LwM2M client endpoint name"""
+ zh: """ """
+ }
+ }
+
+ lifetime {
+ desc {
+ en: """Life time"""
+ zh: """ """
+ }
+ }
+
+ qos {
+ desc {
+ en: """QoS level, enum: 0, 1, 2"""
+ zh: """ """
+ }
+ }
+
+ nl {
+ desc {
+ en: """No Local option, enum: 0, 1"""
+ zh: """ """
+ }
+ }
+
+ rap {
+ desc {
+ en: """Retain as Published option, enum: 0, 1"""
+ zh: """ """
+ }
+ }
+
+ rh {
+ desc {
+ en: """Retain Handling option, enum: 0, 1, 2"""
+ zh: """ """
+ }
+ }
+
+ sub_props {
+ desc {
+ en: """Subscription properties"""
+ zh: """ """
+ }
+ }
+
+ subid {
+ desc {
+ en: """Only stomp protocol, a unique identity for the subscription. range: 1-65535."""
+ zh: """ """
+ }
+ }
+
+ node {
+ desc {
+ en: """Name of the node to which the client is connected"""
+ zh: """ """
+ }
+ }
+
+ username {
+ desc {
+ en: """Username of client when connecting"""
+ zh: """ """
+ }
+ }
+
+ proto_name {
+ desc {
+ en: """Client protocol name"""
+ zh: """ """
+ }
+ }
+
+ proto_ver {
+ desc {
+ en: """Protocol version used by the client"""
+ zh: """ """
+ }
+ }
+
+ ip_address {
+ desc {
+ en: """Client's IP address"""
+ zh: """ """
+ }
+ }
+
+ port {
+ desc {
+ en: """Client's port"""
+ zh: """ """
+ }
+ }
+
+ is_bridge {
+ desc {
+ en: """Indicates whether the client is connected via bridge"""
+ zh: """ """
+ }
+ }
+
+ connected_at {
+ desc {
+ en: """Client connection time"""
+ zh: """ """
+ }
+ }
+
+ disconnected_at {
+ desc {
+ en: """Client offline time, This field is only valid and returned when connected is false"""
+ zh: """ """
+ }
+ }
+
+ connected {
+ desc {
+ en: """Whether the client is connected"""
+ zh: """ """
+ }
+ }
+
+ keepalive {
+ desc {
+ en: """keepalive time, with the unit of second"""
+ zh: """ """
+ }
+ }
+
+ clean_start {
+ desc {
+ en: """Indicate whether the client is using a brand new session"""
+ zh: """ """
+ }
+ }
+
+ expiry_interval {
+ desc {
+ en: """Session expiration interval, with the unit of second"""
+ zh: """ """
+ }
+ }
+
+ created_at {
+ desc {
+ en: """Session creation time"""
+ zh: """ """
+ }
+ }
+
+ subscriptions_cnt {
+ desc {
+ en: """Number of subscriptions established by this client"""
+ zh: """ """
+ }
+ }
+
+ subscriptions_max {
+ desc {
+ en: """Maximum number of subscriptions allowed by this client"""
+ zh: """ """
+ }
+ }
+
+ inflight_cnt {
+ desc {
+ en: """Current length of inflight"""
+ zh: """ """
+ }
+ }
+
+ inflight_max {
+ desc {
+ en: """Maximum length of inflight"""
+ zh: """ """
+ }
+ }
+
+ mqueue_len {
+ desc {
+ en: """Current length of message queue"""
+ zh: """ """
+ }
+ }
+
+ mqueue_max {
+ desc {
+ en: """Maximum length of message queue"""
+ zh: """ """
+ }
+ }
+
+ mqueue_dropped {
+ desc {
+ en: """Number of messages dropped by the message queue due to exceeding the length"""
+ zh: """ """
+ }
+ }
+
+ awaiting_rel_cnt {
+ desc {
+ en: """Number of awaiting acknowledge packet"""
+ zh: """ """
+ }
+ }
+
+ awaiting_rel_max {
+ desc {
+ en: """Maximum allowed number of awaiting PUBREC packet"""
+ zh: """ """
+ }
+ }
+
+ recv_oct {
+ desc {
+ en: """Number of bytes received"""
+ zh: """ """
+ }
+ }
+
+ recv_cnt {
+ desc {
+ en: """Number of socket packets received"""
+ zh: """ """
+ }
+ }
+
+ recv_pkt {
+ desc {
+ en: """Number of protocol packets received"""
+ zh: """ """
+ }
+ }
+
+ recv_msg {
+ desc {
+ en: """Number of message packets received"""
+ zh: """ """
+ }
+ }
+
+ send_oct {
+ desc {
+ en: """Number of bytes sent"""
+ zh: """ """
+ }
+ }
+
+ send_cnt {
+ desc {
+ en: """Number of socket packets sent"""
+ zh: """ """
+ }
+ }
+
+ send_pkt {
+ desc {
+ en: """Number of protocol packets sent"""
+ zh: """ """
+ }
+ }
+
+ send_msg {
+ desc {
+ en: """Number of message packets sent"""
+ zh: """ """
+ }
+ }
+
+ mailbox_len {
+ desc {
+ en: """Process mailbox size"""
+ zh: """ """
+ }
+ }
+
+ heap_size {
+ desc {
+ en: """Process heap size with the unit of byte"""
+ zh: """ """
+ }
+ }
+
+ reductions {
+ desc {
+ en: """Erlang reduction"""
+ zh: """ """
+ }
+ }
+
+ endpoint_name {
+ desc {
+ en: """ """
+ zh: """ """
+ }
+ }
+
+ endpoint_name {
+ desc {
+ en: """ """
+ zh: """ """
+ }
+ }
+
+ endpoint_name {
+ desc {
+ en: """ """
+ zh: """ """
+ }
+ }
+
+ endpoint_name {
+ desc {
+ en: """ """
+ zh: """ """
+ }
+ }
+
+ endpoint_name {
+ desc {
+ en: """ """
+ zh: """ """
+ }
+ }
+
+}
diff --git a/apps/emqx_gateway/i18n/emqx_gateway_api_i18n.conf b/apps/emqx_gateway/i18n/emqx_gateway_api_i18n.conf
new file mode 100644
index 000000000..a66fb2d34
--- /dev/null
+++ b/apps/emqx_gateway/i18n/emqx_gateway_api_i18n.conf
@@ -0,0 +1,121 @@
+emqx_gateway_api {
+
+ list_gateway {
+ desc {
+ en: """Get gateway list"""
+ zh: """ """
+ }
+ }
+
+ enable_gateway {
+ desc {
+ en: """Enable a gateway"""
+ zh: """ """
+ }
+ }
+
+ get_gateway {
+ desc {
+ en: """Get the gateway configurations"""
+ zh: """ """
+ }
+ }
+
+ delete_gateway {
+ desc {
+ en: """Delete/Unload the gateway"""
+ zh: """ """
+ }
+ }
+
+ update_gateway {
+ desc {
+ en: """Update the gateway configurations/status"""
+ zh: """ """
+ }
+ }
+
+ gateway_name {
+ desc {
+ en: """Gateway Name"""
+ zh: """ """
+ }
+ }
+
+ gateway_status {
+ desc {
+ en: """Gateway Status"""
+ zh: """ """
+ }
+ }
+
+ gateway_created_at {
+ desc {
+ en: """The Gateway created datetime"""
+ zh: """ """
+ }
+ }
+
+ gateway_started_at {
+ desc {
+ en: """The Gateway started datetime"""
+ zh: """ """
+ }
+ }
+
+ gateway_stopped_at {
+ desc {
+ en: """The Gateway stopped datetime"""
+ zh: """ """
+ }
+ }
+
+ gateway_max_connections {
+ desc {
+ en: """The Gateway allowed maximum connections/clients"""
+ zh: """ """
+ }
+ }
+
+ gateway_current_connections {
+ desc {
+ en: """The Gateway current connected connections/clients"""
+ zh: """ """
+ }
+ }
+
+ gateway_listeners {
+ desc {
+ en: """The Gateway listeners overview"""
+ zh: """ """
+ }
+ }
+
+ gateway_listener_id {
+ desc {
+ en: """Listener ID"""
+ zh: """ """
+ }
+ }
+
+ gateway_listener_name {
+ desc {
+ en: """Listener Name"""
+ zh: """ """
+ }
+ }
+
+ gateway_listener_running {
+ desc {
+ en: """Listener Running status"""
+ zh: """ """
+ }
+ }
+
+ gateway_listener_type {
+ desc {
+ en: """Listener Type"""
+ zh: """ """
+ }
+ }
+}
diff --git a/apps/emqx_gateway/i18n/emqx_gateway_api_listeners_i18n.conf b/apps/emqx_gateway/i18n/emqx_gateway_api_listeners_i18n.conf
new file mode 100644
index 000000000..3716a8ab6
--- /dev/null
+++ b/apps/emqx_gateway/i18n/emqx_gateway_api_listeners_i18n.conf
@@ -0,0 +1,114 @@
+emqx_gateway_api_listeners {
+
+ list_listeners {
+ desc {
+ en: """Get the gateway listeners"""
+ zh: """ """
+ }
+ }
+
+ add_listener {
+ desc {
+ en: """Create the gateway listener"""
+ zh: """ """
+ }
+ }
+
+ get_listener {
+ desc {
+ en: """Get the gateway listener configurations"""
+ zh: """ """
+ }
+ }
+
+ delete_listener {
+ desc {
+ en: """Delete the gateway listener"""
+ zh: """ """
+ }
+ }
+
+ update_listener {
+ desc {
+ en: """Update the gateway listener"""
+ zh: """ """
+ }
+ }
+
+ get_listener_authn {
+ desc {
+ en: """Get the listener's authentication info"""
+ zh: """ """
+ }
+ }
+
+ add_listener_authn {
+ desc {
+ en: """Add authentication for the listener"""
+ zh: """ """
+ }
+ }
+
+ update_listener_authn {
+ desc {
+ en: """Update authentication for the listener"""
+ zh: """ """
+ }
+ }
+
+ delete_listener_authn {
+ desc {
+ en: """Remove authentication for the listener"""
+ zh: """ """
+ }
+ }
+
+ list_users {
+ desc {
+ en: """Get the users for the authentication"""
+ zh: """ """
+ }
+ }
+
+ add_user {
+ desc {
+ en: """Add user for the authentication"""
+ zh: """ """
+ }
+ }
+
+ get_user {
+ desc {
+ en: """Get user info from the gateway authentication"""
+ zh: """ """
+ }
+ }
+
+ update_user {
+ desc {
+ en: """Update the user info for the gateway authentication"""
+ zh: """ """
+ }
+ }
+
+ delete_user {
+ desc {
+ en: """Delete the user for the gateway authentication"""
+ zh: """ """
+ }
+ }
+
+ import_users {
+ desc {
+ en: """Import users into the gateway authentication"""
+ zh: """ """
+ }
+ }
+
+ listener_id {
+ desc {
+ en: """Listener ID"""
+ zh: """ """
+ }
+ }
+}
diff --git a/apps/emqx_gateway/i18n/emqx_gateway_schema_i18n.conf b/apps/emqx_gateway/i18n/emqx_gateway_schema_i18n.conf
new file mode 100644
index 000000000..e13727e7e
--- /dev/null
+++ b/apps/emqx_gateway/i18n/emqx_gateway_schema_i18n.conf
@@ -0,0 +1,587 @@
+emqx_gateway_schema {
+
+ stomp {
+ desc {
+ en: """The Stomp Gateway configuration.
+This gateway supports v1.2/1.1/1.0"""
+ zh: """Stomp 网关配置。当前实现支持 v1.2/1.1/1.0 协议版本"""
+ }
+ }
+
+ stom_frame_max_headers {
+ desc {
+ en: """The maximum number of Header"""
+ zh: """ """
+ }
+ }
+
+ stomp_frame_max_headers_length {
+ desc {
+ en: """The maximum string length of the Header Value"""
+ zh: """ """
+ }
+ }
+
+ stom_frame_max_body_length {
+ desc {
+ en: """Maximum number of bytes of Body allowed per Stomp packet"""
+ zh: """ """
+ }
+ }
+
+ mqttsn {
+ desc {
+ en: """The MQTT-SN Gateway configuration.
+This gateway only supports the v1.2 protocol"""
+ zh: """MQTT-SN 网关配置。当前实现仅支持 v1.2 版本"""
+ }
+ }
+
+ mqttsn_gateway_id {
+ desc {
+ en: """MQTT-SN Gateway ID.
+When the broadcast
option is enabled, the gateway will broadcast ADVERTISE message with this value"""
+ zh: """ """
+ }
+ }
+
+ mqttsn_broadcast {
+ desc {
+ en: """Whether to periodically broadcast ADVERTISE messages"""
+ zh: """ """
+ }
+ }
+
+ mqttsn_enable_qos3 {
+ desc {
+ en: """Allows connectionless clients to publish messages with a Qos of -1.
+This feature is defined for very simple client implementations which do not support any other features except this one. There is no connection setup nor tear down, no registration nor subscription. The client just sends its 'PUBLISH' messages to a GW"""
+ zh: """ """
+ }
+ }
+
+ mqttsn_subs_resume {
+ desc {
+ en: """Whether to initiate all subscribed topic name registration messages to the client after the Session has been taken over by a new channel"""
+ zh: """ """
+ }
+ }
+
+ mqttsn_predefined {
+ desc {
+ en: """The pre-defined topic IDs and topic names.
+A 'pre-defined' topic ID is a topic ID whose mapping to a topic name is known in advance by both the client's application and the gateway"""
+ zh: """ """
+ }
+ }
+
+ mqttsn_predefined_id {
+ desc {
+ en: """Topic ID.
Range: 1-65535"""
+ zh: """ """
+ }
+ }
+
+ mqttsn_predefined_topic {
+ desc {
+ en: """Topic Name"""
+ zh: """ """
+ }
+ }
+
+ coap {
+ desc {
+ en: """The CoAP Gateway configuration.
\n
+This gateway is implemented based on RFC-7252 and https://core-wg.github.io/coap-pubsub/draft-ietf-core-pubsub.html"""
+ zh: """ """
+ }
+ }
+
+ coap_heartbeat {
+ desc {
+ en: """The gateway server required minimum heartbeat interval.
+When connection mode is enabled, this parameter is used to set the minimum heartbeat interval for the connection to be alive"""
+ zh: """ """
+ }
+ }
+
+ coap_connection_required {
+ desc {
+ en: """Enable or disable connection mode.
+Connection mode is a feature of non-standard protocols. When connection mode is enabled, it is necessary to maintain the creation, authentication and alive of connection resources"""
+ zh: """ """
+ }
+ }
+
+ coap_notify_type {
+ desc {
+ en: """The Notification Message will be delivered to the CoAP client if a new message received on an observed topic.
+The type of delivered coap message can be set to:
+ 1. non: Non-confirmable;
+ 2. con: Confirmable;
+ 3. qos: Mapping from QoS type of received message, QoS0 -> non, QoS1,2 -> con"""
+ zh: """ """
+ }
+ }
+
+ coap_subscribe_qos {
+ desc {
+ en: """The Default QoS Level indicator for subscribe request.
+This option specifies the QoS level for the CoAP Client when establishing a subscription membership, if the subscribe request is not carried `qos` option. The indicator can be set to:
+ - qos0, qos1, qos2: Fixed default QoS level
+ - coap: Dynamic QoS level by the message type of subscribe request
+ * qos0: If the subscribe request is non-confirmable
+ * qos1: If the subscribe request is confirmable"""
+
+ zh: """ """
+ }
+ }
+
+ coap_publish_qos {
+ desc {
+ en: """The Default QoS Level indicator for publish request.
+This option specifies the QoS level for the CoAP Client when publishing a message to EMQX PUB/SUB system, if the publish request is not carried `qos` option. The indicator can be set to:
+ - qos0, qos1, qos2: Fixed default QoS level
+ - coap: Dynamic QoS level by the message type of publish request
+ * qos0: If the publish request is non-confirmable
+ * qos1: If the publish request is confirmable"""
+
+ zh: """ """
+ }
+ }
+
+ lwm2m {
+ desc {
+ en: """The LwM2M Gateway configuration.
+This gateway only supports the v1.0.1 protocol"""
+ zh: """ """
+ }
+ }
+
+ lwm2m_xml_dir {
+ desc {
+ en: """The Directory for LwM2M Resource definition"""
+ zh: """ """
+ }
+ }
+
+ lwm2m_lifetime_min {
+ desc {
+ en: """Minimum value of lifetime allowed to be set by the LwM2M client"""
+ zh: """ """
+ }
+ }
+
+ lwm2m_lifetime_max {
+ desc {
+ en: """Maximum value of lifetime allowed to be set by the LwM2M client"""
+ zh: """ """
+ }
+ }
+
+ lwm2m_qmode_time_window {
+ desc {
+ en: """The value of the time window during which the network link is considered valid by the LwM2M Gateway in QMode mode.
+For example, after receiving an update message from a client, any messages within this time window are sent directly to the LwM2M client, and all messages beyond this time window are temporarily stored in memory."""
+
+ zh: """ """
+ }
+ }
+
+ lwm2m_auto_observe {
+ desc {
+ en: """Automatically observe the object list of REGISTER packet"""
+ zh: """ """
+ }
+ }
+
+ lwm2m_update_msg_publish_condition {
+ desc {
+ en: """"Policy for publishing UPDATE event message.
+ - always: send update events as long as the UPDATE request is received.
+ - contains_object_list: send update events only if the UPDATE request carries any Object List"""
+
+ zh: """ """
+ }
+ }
+
+ lwm2m_translators {
+ desc {
+ en: """Topic configuration for LwM2M's gateway publishing and subscription"""
+ zh: """ """
+ }
+ }
+
+ lwm2m_translators_command {
+ desc {
+ en: """The topic for receiving downstream commands.
+For each new LwM2M client that succeeds in going online, the gateway creates a subscription relationship to receive downstream commands and send it to the LwM2M client"""
+
+ zh: """ """
+ }
+ }
+
+ lwm2m_translators_response {
+ desc {
+ en: """The topic for gateway to publish the acknowledge events from LwM2M client"""
+ zh: """ """
+ }
+ }
+
+ lwm2m_translators_notify {
+ desc {
+ en: """The topic for gateway to publish the notify events from LwM2M client.
+After succeed observe a resource of LwM2M client, Gateway will send the notify events via this topic, if the client reports any resource changes"""
+
+ zh: """ """
+ }
+ }
+
+ lwm2m_translators_register {
+ desc {
+ en: """The topic for gateway to publish the register events from LwM2M client."""
+ zh: """ """
+ }
+ }
+
+ lwm2m_translators_update {
+ desc {
+ en: """The topic for gateway to publish the update events from LwM2M client"""
+ zh: """ """
+ }
+ }
+
+ translator {
+ desc {
+ en: """MQTT topic that corresponds to a particular type of event."""
+ zh: """ """
+ }
+ }
+
+ translator_topic {
+ desc {
+ en: """Which topic the device's upstream message is published to."""
+ zh: """ """
+ }
+ }
+
+ translator_qos {
+ desc {
+ en: """QoS of the published messages."""
+ zh: """ """
+ }
+ }
+
+ exproto {
+ desc {
+ en: """The Extension Protocol configuration"""
+ zh: """ """
+ }
+ }
+
+ exproto_server {
+ desc {
+ en: """Configurations for starting the ConnectionAdapter
service"""
+ zh: """ """
+ }
+ }
+
+ exproto_grpc_server_bind {
+ desc {
+ en: """Listening address and port for the gRPC server."""
+ zh: """ """
+ }
+ }
+
+ exproto_grpc_server_ssl {
+ desc {
+ en: """SSL configuration for the gRPC server."""
+ zh: """ """
+ }
+ }
+
+ exproto_handler {
+ desc {
+ en: """Configurations for request to ConnectionHandler
service"""
+ zh: """ """
+ }
+ }
+
+ exproto_grpc_handler_address {
+ desc {
+ en: """gRPC server address."""
+ zh: """ """
+ }
+ }
+
+ exproto_grpc_handler_ssl {
+ desc {
+ en: """SSL configuration for the gRPC client."""
+ zh: """ """
+ }
+ }
+
+ gateway_common_enable {
+ desc {
+ en: """Whether to enable this gateway"""
+ zh: """ """
+ }
+ }
+
+ gateway_common_enable_stats {
+ desc {
+ en: """Whether to enable client process statistic"""
+ zh: """ """
+ }
+ }
+
+ gateway_common_idle_timeout {
+ desc {
+ en: """The idle time of the client connection process. It has two purposes:
+ 1. A newly created client process that does not receive any client requests after that time will be closed directly.
+ 2. A running client process that does not receive any client requests after this time will go into hibernation to save resources."""
+ zh: """ """
+ }
+ }
+
+ gateway_common_mountpoint {
+ desc {
+ en: """ """
+ zh: """ """
+ }
+ }
+
+ gateway_common_clientinfo_override {
+ desc {
+ en: """ClientInfo override."""
+ zh: """ """
+ }
+ }
+
+ gateway_common_clientinfo_override_username {
+ desc {
+ en: """Template for overriding username."""
+ zh: """ """
+ }
+ }
+ gateway_common_clientinfo_override_password {
+ desc {
+ en: """Template for overriding password."""
+ zh: """ """
+ }
+ }
+ gateway_common_clientinfo_override_clientid {
+ desc {
+ en: """Template for overriding clientid."""
+ zh: """ """
+ }
+ }
+
+ gateway_common_authentication {
+ desc {
+ en: """Default authentication configs for all the gateway listeners. For per-listener overrides see authentication
\n in listener configs"""
+ zh: """ """
+ }
+ }
+
+ tcp_udp_listeners {
+ desc {
+ en: """Settings for the listeners."""
+ zh: """ """
+ }
+ }
+
+ tcp_listeners {
+ desc {
+ en: """Settings for the TCP listeners."""
+ zh: """ """
+ }
+ }
+
+ udp_listeners {
+ desc {
+ en: """Settings for the UDP listeners."""
+ zh: """ """
+ }
+ }
+
+ tcp_listener {
+ desc {
+ en: """ """
+ zh: """ """
+ }
+ }
+
+ tcp_listener_acceptors {
+ desc {
+ en: """Size of the acceptor pool."""
+ zh: """ """
+ }
+ }
+
+ tcp_listener_tcp_opts{
+ desc {
+ en: """Setting the TCP socket options."""
+ zh: """ """
+ }
+ }
+
+ tcp_listener_proxy_protocol {
+ desc {
+ en: """Enable the Proxy Protocol V1/2 if the EMQX cluster is deployed behind HAProxy or Nginx.
+See: https://www.haproxy.com/blog/haproxy/proxy-protocol/"""
+ zh: """ """
+ }
+ }
+
+ tcp_listener_proxy_protocol_timeout {
+ desc {
+ en: """Timeout for proxy protocol.
+EMQX will close the TCP connection if proxy protocol packet is not received within the timeout."""
+ zh: """ """
+ }
+ }
+
+ ssl_listener {
+ desc {
+ en: """ """
+ zh: """ """
+ }
+ }
+
+ ssl_listener_options {
+ desc {
+ en: """SSL listener options."""
+ zh: """ """
+ }
+ }
+
+ udp_listener {
+ desc {
+ en: """ """
+ zh: """ """
+ }
+ }
+
+ udp_listener_udp_opts {
+ desc {
+ en: """Settings for the UDP sockets."""
+ zh: """ """
+ }
+ }
+
+ udp_listener_active_n {
+ desc {
+ en: """Specify the {active, N} option for the socket.
+See: https://erlang.org/doc/man/inet.html#setopts-2"""
+ zh: """ """
+ }
+ }
+
+ udp_listener_recbuf {
+ desc {
+ en: """Size of the kernel-space receive buffer for the socket."""
+ zh: """ """
+ }
+ }
+
+ udp_listener_sndbuf {
+ desc {
+ en: """Size of the kernel-space send buffer for the socket."""
+ zh: """ """
+ }
+ }
+
+ udp_listener_buffer {
+ desc {
+ en: """Size of the user-space buffer for the socket."""
+ zh: """ """
+ }
+ }
+
+ udp_listener_reuseaddr {
+ desc {
+ en: """Allow local reuse of port numbers."""
+ zh: """ """
+ }
+ }
+
+ dtls_listener {
+ desc {
+ en: """ """
+ zh: """ """
+ }
+ }
+
+ dtls_listener_acceptors {
+ desc {
+ en: """Size of the acceptor pool."""
+ zh: """ """
+ }
+ }
+
+ dtls_listener_dtls_opts {
+ desc {
+ en: """DTLS listener options"""
+ zh: """ """
+ }
+
+ }
+
+ gateway_common_listener_enable {
+ desc {
+ en: """Enable the listener."""
+ zh: """ """
+ }
+ }
+
+ gateway_common_listener_bind {
+ desc {
+ en: """The IP address and port that the listener will bind."""
+ zh: """ """
+ }
+ }
+
+ gateway_common_listener_max_connections {
+ desc {
+ en: """Maximum number of concurrent connections."""
+ zh: """ """
+ }
+ }
+
+ gateway_common_listener_max_conn_rate {
+ desc {
+ en: """Maximum connections per second."""
+ zh: """ """
+ }
+ }
+
+ gateway_common_listener_mountpoint {
+ desc {
+ en: """When publishing or subscribing, prefix all topics with a mountpoint string.
+The prefixed string will be removed from the topic name when the message is delivered to the subscriber. The mountpoint is a way that users can use to implement isolation of message routing between different listeners.
+For example if a client A subscribes to `t` with `listeners.tcp..mountpoint` set to `some_tenant`, then the client actually subscribes to the topic `some_tenant/t`. Similarly, if another client B (connected to the same listener as the client A) sends a message to topic `t`, the message is routed to all the clients subscribed `some_tenant/t`, so client A will receive the message, with topic name `t`. Set to `\"\"` to disable the feature.
+Variables in mountpoint string:
+ - ${clientid}
: clientid
+ - ${username}
: username
+"""
+ zh: """ """
+ }
+ }
+
+ gateway_common_listener_access_rules {
+ desc {
+ en: """The access control rules for this listener.
+See: https://github.com/emqtt/esockd#allowdeny"""
+ zh: """ """
+ }
+ }
+
+ gateway_common_listener_enable {
+ desc {
+ en: """ """
+ zh: """ """
+ }
+ }
+
+}
diff --git a/apps/emqx_gateway/i18n/emqx_lwm2m_api_i18n.conf b/apps/emqx_gateway/i18n/emqx_lwm2m_api_i18n.conf
new file mode 100644
index 000000000..f9f4cc9b1
--- /dev/null
+++ b/apps/emqx_gateway/i18n/emqx_lwm2m_api_i18n.conf
@@ -0,0 +1,58 @@
+emqx_lwm2m_api {
+
+ lookup_resource {
+ desc {
+ en: """Look up a resource"""
+ zh: """ """
+ }
+ }
+
+ observe_resource {
+ desc {
+ en: """Observe or Cancel observe a resource"""
+ zh: """ """
+ }
+ }
+
+ read_resource {
+ desc {
+ en: """Send a read command to a resource"""
+ zh: """ """
+ }
+ }
+
+ write_resource {
+ desc {
+ en: """Send a write command to a resource"""
+ zh: """ """
+ }
+ }
+
+ operations {
+ desc {
+ en: """Resource Operations"""
+ zh: """ """
+ }
+ }
+
+ dataType {
+ desc {
+ en: """Data Type"""
+ zh: """ """
+ }
+ }
+
+ path {
+ desc {
+ en: """Resource Path"""
+ zh: """ """
+ }
+ }
+
+ name {
+ desc {
+ en: """Resource Name"""
+ zh: """ """
+ }
+ }
+}
diff --git a/apps/emqx_gateway/src/coap/emqx_coap_api.erl b/apps/emqx_gateway/src/coap/emqx_coap_api.erl
index 118aef798..deba77445 100644
--- a/apps/emqx_gateway/src/coap/emqx_coap_api.erl
+++ b/apps/emqx_gateway/src/coap/emqx_coap_api.erl
@@ -18,6 +18,7 @@
-behaviour(minirest_api).
+-include_lib("hocon/include/hoconsc.hrl").
-include_lib("typerefl/include/types.hrl").
-include_lib("emqx/include/logger.hrl").
-include("src/coap/include/emqx_coap.hrl").
@@ -48,7 +49,7 @@ schema(?PREFIX ++ "/request") ->
operationId => request,
post => #{
tags => [<<"gateway|coap">>],
- desc => <<"Send a CoAP request message to the client">>,
+ desc => ?DESC(send_coap_request),
parameters => request_parameters(),
requestBody => request_body(),
responses => #{
@@ -97,23 +98,23 @@ request_parameters() ->
request_body() ->
[
- {token, mk(binary(), #{desc => "message token, can be empty"})},
- {method, mk(enum([get, put, post, delete]), #{desc => "request method type"})},
- {timeout, mk(emqx_schema:duration_ms(), #{desc => "timespan for response"})},
+ {token, mk(binary(), #{desc => ?DESC(token)})},
+ {method, mk(enum([get, put, post, delete]), #{desc => ?DESC(method)})},
+ {timeout, mk(emqx_schema:duration_ms(), #{desc => ?DESC(timeout)})},
{content_type,
mk(
enum(['text/plain', 'application/json', 'application/octet-stream']),
- #{desc => "payload type"}
+ #{desc => ?DESC(content_type)}
)},
- {payload, mk(binary(), #{desc => "the content of the payload"})}
+ {payload, mk(binary(), #{desc => ?DESC(payload)})}
].
coap_message() ->
[
- {id, mk(integer(), #{desc => "message id"})},
- {token, mk(string(), #{desc => "message token, can be empty"})},
- {method, mk(string(), #{desc => "response code"})},
- {payload, mk(string(), #{desc => "payload"})}
+ {id, mk(integer(), #{desc => ?DESC(message_id)})},
+ {token, mk(string(), #{desc => ?DESC(token)})},
+ {method, mk(string(), #{desc => ?DESC(response_code)})},
+ {payload, mk(string(), #{desc => ?DESC(payload)})}
].
format_to_response(ContentType, #coap_message{
diff --git a/apps/emqx_gateway/src/emqx_gateway_api.erl b/apps/emqx_gateway/src/emqx_gateway_api.erl
index b8a8d9902..a0ff42138 100644
--- a/apps/emqx_gateway/src/emqx_gateway_api.erl
+++ b/apps/emqx_gateway/src/emqx_gateway_api.erl
@@ -43,7 +43,8 @@
-export([
roots/0,
- fields/1
+ fields/1,
+ listener_schema/0
]).
%% http handlers
@@ -161,7 +162,7 @@ schema("/gateway") ->
'operationId' => gateway,
get =>
#{
- desc => <<"Get gateway list">>,
+ desc => ?DESC(list_gateway),
parameters => params_gateway_status_in_qs(),
responses =>
?STANDARD_RESP(
@@ -175,7 +176,7 @@ schema("/gateway") ->
},
post =>
#{
- desc => <<"Load a gateway">>,
+ desc => ?DESC(enable_gateway),
%% TODO: distinguish create & response swagger schema
'requestBody' => schema_gateways_conf(),
responses =>
@@ -187,21 +188,21 @@ schema("/gateway/:name") ->
'operationId' => gateway_insta,
get =>
#{
- desc => <<"Get the gateway configurations">>,
+ desc => ?DESC(get_gateway),
parameters => params_gateway_name_in_path(),
responses =>
?STANDARD_RESP(#{200 => schema_gateways_conf()})
},
delete =>
#{
- desc => <<"Delete/Unload the gateway">>,
+ desc => ?DESC(delete_gateway),
parameters => params_gateway_name_in_path(),
responses =>
?STANDARD_RESP(#{204 => <<"Deleted">>})
},
put =>
#{
- desc => <<"Update the gateway configurations/status">>,
+ desc => ?DESC(update_gateway),
parameters => params_gateway_name_in_path(),
'requestBody' => schema_update_gateways_conf(),
responses =>
@@ -219,7 +220,7 @@ params_gateway_name_in_path() ->
binary(),
#{
in => path,
- desc => <<"Gateway Name">>,
+ desc => ?DESC(gateway_name),
example => <<"">>
}
)}
@@ -234,7 +235,7 @@ params_gateway_status_in_qs() ->
#{
in => query,
required => false,
- desc => <<"Gateway Status">>,
+ desc => ?DESC(gateway_status),
example => <<"">>
}
)}
@@ -254,24 +255,24 @@ fields(gateway_overview) ->
{name,
mk(
binary(),
- #{desc => <<"Gateway Name">>}
+ #{desc => ?DESC(gateway_name)}
)},
{status,
mk(
hoconsc:enum([running, stopped, unloaded]),
- #{desc => <<"The Gateway status">>}
+ #{desc => ?DESC(gateway_status)}
)},
{created_at,
mk(
binary(),
- #{desc => <<"The Gateway created datetime">>}
+ #{desc => ?DESC(gateway_created_at)}
)},
{started_at,
mk(
binary(),
#{
required => false,
- desc => <<"The Gateway started datetime">>
+ desc => ?DESC(gateway_started_at)
}
)},
{stopped_at,
@@ -279,25 +280,25 @@ fields(gateway_overview) ->
binary(),
#{
required => false,
- desc => <<"The Gateway stopped datetime">>
+ desc => ?DESC(gateway_stopped_at)
}
)},
{max_connections,
mk(
pos_integer(),
- #{desc => <<"The Gateway allowed maximum connections/clients">>}
+ #{desc => ?DESC(gateway_max_connections)}
)},
{current_connections,
mk(
non_neg_integer(),
- #{desc => <<"The Gateway current connected connections/clients">>}
+ #{desc => ?DESC(gateway_current_connections)}
)},
{listeners,
mk(
hoconsc:array(ref(gateway_listener_overview)),
#{
required => {false, recursively},
- desc => <<"The Gateway listeners overview">>
+ desc => ?DESC(gateway_listeners)
}
)}
];
@@ -306,17 +307,17 @@ fields(gateway_listener_overview) ->
{id,
mk(
binary(),
- #{desc => <<"Listener ID">>}
+ #{desc => ?DESC(gateway_listener_id)}
)},
{running,
mk(
boolean(),
- #{desc => <<"Listener Running status">>}
+ #{desc => ?DESC(gateway_listener_running)}
)},
{type,
mk(
hoconsc:enum([tcp, ssl, udp, dtls]),
- #{desc => <<"Listener Type">>}
+ #{desc => ?DESC(gateway_listener_type)}
)}
];
fields(Gw) when
@@ -326,7 +327,7 @@ fields(Gw) when
Gw == lwm2m;
Gw == exproto
->
- [{name, mk(hoconsc:union([Gw]), #{desc => <<"Gateway Name">>})}] ++
+ [{name, mk(Gw, #{desc => ?DESC(gateway_name)})}] ++
convert_listener_struct(emqx_gateway_schema:fields(Gw));
fields(Gw) when
Gw == update_stomp;
@@ -344,31 +345,36 @@ fields(Listener) when
Listener == udp_listener;
Listener == dtls_listener
->
+ Type =
+ case Listener of
+ tcp_listener -> tcp;
+ ssl_listener -> ssl;
+ udp_listener -> udp;
+ dtls_listener -> dtls
+ end,
[
{id,
mk(
binary(),
#{
- required => false,
- desc => <<"Listener ID">>
+ desc => ?DESC(gateway_listener_id)
}
)},
{type,
mk(
- hoconsc:union([tcp, ssl, udp, dtls]),
- #{desc => <<"Listener type">>}
+ Type,
+ #{desc => ?DESC(gateway_listener_type)}
)},
{name,
mk(
binary(),
- #{desc => <<"Listener Name">>}
+ #{desc => ?DESC(gateway_listener_name)}
)},
{running,
mk(
boolean(),
#{
- required => false,
- desc => <<"Listener running status">>
+ desc => ?DESC(gateway_listener_running)
}
)}
] ++ emqx_gateway_schema:fields(Listener);
@@ -403,10 +409,7 @@ convert_listener_struct(Schema) ->
{value, {listeners, #{type := Type}}, Schema1} = lists:keytake(listeners, 1, Schema),
ListenerSchema = hoconsc:mk(
listeners_schema(Type),
- #{
- required => {false, recursively},
- desc => <<"The gateway listeners">>
- }
+ #{required => {false, recursively}}
),
lists:keystore(listeners, 1, Schema1, {listeners, ListenerSchema}).
@@ -421,7 +424,7 @@ listeners_schema(?R_REF(_Mod, tcp_listeners)) ->
hoconsc:array(hoconsc:union([ref(tcp_listener), ref(ssl_listener)]));
listeners_schema(?R_REF(_Mod, udp_listeners)) ->
hoconsc:array(hoconsc:union([ref(udp_listener), ref(dtls_listener)]));
-listeners_schema(?R_REF(_Mod, udp_tcp_listeners)) ->
+listeners_schema(?R_REF(_Mod, tcp_udp_listeners)) ->
hoconsc:array(
hoconsc:union([
ref(tcp_listener),
@@ -431,6 +434,14 @@ listeners_schema(?R_REF(_Mod, udp_tcp_listeners)) ->
])
).
+listener_schema() ->
+ hoconsc:union([
+ ref(?MODULE, tcp_listener),
+ ref(?MODULE, ssl_listener),
+ ref(?MODULE, udp_listener),
+ ref(?MODULE, dtls_listener)
+ ]).
+
%%--------------------------------------------------------------------
%% examples
diff --git a/apps/emqx_gateway/src/emqx_gateway_api_authn.erl b/apps/emqx_gateway/src/emqx_gateway_api_authn.erl
index 9b37145f8..68941e516 100644
--- a/apps/emqx_gateway/src/emqx_gateway_api_authn.erl
+++ b/apps/emqx_gateway/src/emqx_gateway_api_authn.erl
@@ -19,6 +19,7 @@
-behaviour(minirest_api).
-include("emqx_gateway_http.hrl").
+-include_lib("hocon/include/hoconsc.hrl").
-include_lib("typerefl/include/types.hrl").
-import(hoconsc, [mk/2, ref/2]).
@@ -208,7 +209,7 @@ schema("/gateway/:name/authentication") ->
'operationId' => authn,
get =>
#{
- desc => <<"Get the gateway authentication">>,
+ desc => ?DESC(get_authn),
parameters => params_gateway_name_in_path(),
responses =>
?STANDARD_RESP(
@@ -220,7 +221,7 @@ schema("/gateway/:name/authentication") ->
},
put =>
#{
- desc => <<"Update authentication for the gateway">>,
+ desc => ?DESC(update_authn),
parameters => params_gateway_name_in_path(),
'requestBody' => schema_authn(),
responses =>
@@ -228,7 +229,7 @@ schema("/gateway/:name/authentication") ->
},
post =>
#{
- desc => <<"Add authentication for the gateway">>,
+ desc => ?DESC(add_authn),
parameters => params_gateway_name_in_path(),
'requestBody' => schema_authn(),
responses =>
@@ -236,7 +237,7 @@ schema("/gateway/:name/authentication") ->
},
delete =>
#{
- desc => <<"Remove the gateway authentication">>,
+ desc => ?DESC(delete_authn),
parameters => params_gateway_name_in_path(),
responses =>
?STANDARD_RESP(#{204 => <<"Deleted">>})
@@ -247,7 +248,7 @@ schema("/gateway/:name/authentication/users") ->
'operationId' => users,
get =>
#{
- desc => <<"Get the users for the authentication">>,
+ desc => ?DESC(list_users),
parameters => params_gateway_name_in_path() ++
params_paging_in_qs() ++
params_fuzzy_in_qs(),
@@ -263,7 +264,7 @@ schema("/gateway/:name/authentication/users") ->
},
post =>
#{
- desc => <<"Add user for the authentication">>,
+ desc => ?DESC(add_user),
parameters => params_gateway_name_in_path(),
'requestBody' => emqx_dashboard_swagger:schema_with_examples(
ref(emqx_authn_api, request_user_create),
@@ -285,10 +286,7 @@ schema("/gateway/:name/authentication/users/:uid") ->
'operationId' => users_insta,
get =>
#{
- desc => <<
- "Get user info from the gateway "
- "authentication"
- >>,
+ desc => ?DESC(get_user),
parameters => params_gateway_name_in_path() ++
params_userid_in_path(),
responses =>
@@ -303,10 +301,7 @@ schema("/gateway/:name/authentication/users/:uid") ->
},
put =>
#{
- desc => <<
- "Update the user info for the gateway "
- "authentication"
- >>,
+ desc => ?DESC(update_user),
parameters => params_gateway_name_in_path() ++
params_userid_in_path(),
'requestBody' => emqx_dashboard_swagger:schema_with_examples(
@@ -325,10 +320,7 @@ schema("/gateway/:name/authentication/users/:uid") ->
},
delete =>
#{
- desc => <<
- "Delete the user for the gateway "
- "authentication"
- >>,
+ desc => ?DESC(delete_user),
parameters => params_gateway_name_in_path() ++
params_userid_in_path(),
responses =>
@@ -340,7 +332,7 @@ schema("/gateway/:name/authentication/import_users") ->
'operationId' => import_users,
post =>
#{
- desc => <<"Import users into the gateway authentication">>,
+ desc => ?DESC(import_users),
parameters => params_gateway_name_in_path(),
'requestBody' => emqx_dashboard_swagger:schema_with_examples(
ref(emqx_authn_api, request_import_users),
@@ -361,7 +353,7 @@ params_gateway_name_in_path() ->
binary(),
#{
in => path,
- desc => <<"Gateway Name">>,
+ desc => ?DESC(emqx_gateway_api, gateway_name),
example => <<"">>
}
)}
@@ -374,35 +366,15 @@ params_userid_in_path() ->
binary(),
#{
in => path,
- desc => <<"User ID">>,
+ desc => ?DESC(user_id),
example => <<"">>
}
)}
].
params_paging_in_qs() ->
- [
- {page,
- mk(
- pos_integer(),
- #{
- in => query,
- required => false,
- desc => <<"Page Index">>,
- example => 1
- }
- )},
- {limit,
- mk(
- pos_integer(),
- #{
- in => query,
- required => false,
- desc => <<"Page Limit">>,
- example => 100
- }
- )}
- ].
+ emqx_dashboard_swagger:fields(page) ++
+ emqx_dashboard_swagger:fields(limit).
params_fuzzy_in_qs() ->
[
@@ -412,7 +384,7 @@ params_fuzzy_in_qs() ->
#{
in => query,
required => false,
- desc => <<"Fuzzy search by username">>,
+ desc => ?DESC(like_username),
example => <<"username">>
}
)},
@@ -422,7 +394,7 @@ params_fuzzy_in_qs() ->
#{
in => query,
required => false,
- desc => <<"Fuzzy search by clientid">>,
+ desc => ?DESC(like_clientid),
example => <<"clientid">>
}
)}
diff --git a/apps/emqx_gateway/src/emqx_gateway_api_clients.erl b/apps/emqx_gateway/src/emqx_gateway_api_clients.erl
index 6eccdc045..af6393a27 100644
--- a/apps/emqx_gateway/src/emqx_gateway_api_clients.erl
+++ b/apps/emqx_gateway/src/emqx_gateway_api_clients.erl
@@ -468,7 +468,7 @@ schema("/gateway/:name/clients") ->
'operationId' => clients,
get =>
#{
- desc => <<"Get the gateway client list">>,
+ desc => ?DESC(list_clients),
parameters => params_client_query(),
responses =>
?STANDARD_RESP(#{200 => schema_client_list()})
@@ -479,14 +479,14 @@ schema("/gateway/:name/clients/:clientid") ->
'operationId' => clients_insta,
get =>
#{
- desc => <<"Get the gateway client information">>,
+ desc => ?DESC(get_client),
parameters => params_client_insta(),
responses =>
?STANDARD_RESP(#{200 => schema_client()})
},
delete =>
#{
- desc => <<"Kick out the gateway client">>,
+ desc => ?DESC(kick_client),
parameters => params_client_insta(),
responses =>
?STANDARD_RESP(#{204 => <<"Kicked">>})
@@ -497,7 +497,7 @@ schema("/gateway/:name/clients/:clientid/subscriptions") ->
'operationId' => subscriptions,
get =>
#{
- desc => <<"Get the gateway client subscriptions">>,
+ desc => ?DESC(list_subscriptions),
parameters => params_client_insta(),
responses =>
?STANDARD_RESP(
@@ -511,7 +511,7 @@ schema("/gateway/:name/clients/:clientid/subscriptions") ->
},
post =>
#{
- desc => <<"Create a subscription membership">>,
+ desc => ?DESC(add_subscription),
parameters => params_client_insta(),
'requestBody' => emqx_dashboard_swagger:schema_with_examples(
ref(subscription),
@@ -533,7 +533,7 @@ schema("/gateway/:name/clients/:clientid/subscriptions/:topic") ->
'operationId' => subscriptions,
delete =>
#{
- desc => <<"Delete a subscriptions membership">>,
+ desc => ?DESC(delete_subscription),
parameters => params_topic_name_in_path() ++ params_client_insta(),
responses =>
?STANDARD_RESP(#{204 => <<"Unsubscribed">>})
@@ -555,143 +555,105 @@ params_client_searching_in_qs() ->
{node,
mk(
binary(),
- M#{desc => <<"Match the client's node name">>}
+ M#{desc => ?DESC(param_node)}
)},
{clientid,
mk(
binary(),
- M#{desc => <<"Match the client's ID">>}
+ M#{desc => ?DESC(param_clientid)}
)},
{username,
mk(
binary(),
- M#{desc => <<"Match the client's Username">>}
+ M#{desc => ?DESC(param_username)}
)},
{ip_address,
mk(
binary(),
- M#{desc => <<"Match the client's ip address">>}
+ M#{desc => ?DESC(param_ip_address)}
)},
{conn_state,
mk(
binary(),
- M#{desc => <<"Match the client's connection state">>}
+ M#{desc => ?DESC(param_conn_state)}
)},
{proto_ver,
mk(
binary(),
- M#{desc => <<"Match the client's protocol version">>}
+ M#{desc => ?DESC(param_proto_ver)}
)},
{clean_start,
mk(
boolean(),
- M#{desc => <<"Match the client's clean start flag">>}
+ M#{desc => ?DESC(param_clean_start)}
)},
{like_clientid,
mk(
binary(),
- M#{desc => <<"Use sub-string to match client's ID">>}
+ M#{desc => ?DESC(param_like_clientid)}
)},
{like_username,
mk(
binary(),
- M#{desc => <<"Use sub-string to match client's username">>}
+ M#{desc => ?DESC(param_like_username)}
)},
{gte_created_at,
mk(
emqx_datetime:epoch_millisecond(),
M#{
- desc => <<
- "Match the session created datetime greater than "
- "a certain value"
- >>
+ desc => ?DESC(param_gte_created_at)
}
)},
{lte_created_at,
mk(
emqx_datetime:epoch_millisecond(),
M#{
- desc => <<
- "Match the session created datetime less than "
- "a certain value"
- >>
+ desc => ?DESC(param_lte_created_at)
}
)},
{gte_connected_at,
mk(
emqx_datetime:epoch_millisecond(),
M#{
- desc => <<
- "Match the client socket connected datetime greater "
- "than a certain value"
- >>
+ desc => ?DESC(param_gte_connected_at)
}
)},
{lte_connected_at,
mk(
emqx_datetime:epoch_millisecond(),
M#{
- desc => <<
- "Match the client socket connected datatime less than "
- "a certain value"
- >>
+ desc => ?DESC(param_lte_connected_at)
}
)},
{endpoint_name,
mk(
binary(),
- M#{desc => <<"Match the lwm2m client's endpoint name">>}
+ M#{desc => ?DESC(param_endpoint_name)}
)},
{like_endpoint_name,
mk(
binary(),
- M#{desc => <<"Use sub-string to match lwm2m client's endpoint name">>}
+ M#{desc => ?DESC(param_like_endpoint_name)}
)},
{gte_lifetime,
mk(
binary(),
M#{
- desc => <<
- "Match the lwm2m client registered lifetime greater "
- "than a certain value"
- >>
+ desc => ?DESC(param_gte_lifetime)
}
)},
{lte_lifetime,
mk(
binary(),
M#{
- desc => <<
- "Match the lwm2m client registered lifetime less than "
- "a certain value"
- >>
+ desc => ?DESC(param_lte_lifetime)
}
)}
].
params_paging() ->
- [
- {page,
- mk(
- pos_integer(),
- #{
- in => query,
- required => false,
- desc => <<"Page Index">>,
- example => 1
- }
- )},
- {limit,
- mk(
- pos_integer(),
- #{
- in => query,
- desc => <<"Page Limit">>,
- required => false,
- example => 100
- }
- )}
- ].
+ emqx_dashboard_swagger:fields(page) ++
+ emqx_dashboard_swagger:fields(limit).
params_gateway_name_in_path() ->
[
@@ -700,7 +662,7 @@ params_gateway_name_in_path() ->
binary(),
#{
in => path,
- desc => <<"Gateway Name">>
+ desc => ?DESC(emqx_gateway_api, gateway_name)
}
)}
].
@@ -712,7 +674,7 @@ params_clientid_in_path() ->
binary(),
#{
in => path,
- desc => <<"Client ID">>
+ desc => ?DESC(clientid)
}
)}
].
@@ -724,7 +686,7 @@ params_topic_name_in_path() ->
binary(),
#{
in => path,
- desc => <<"Topic Filter/Name">>
+ desc => ?DESC(topic)
}
)}
].
@@ -777,12 +739,12 @@ fields(lwm2m_client) ->
{endpoint_name,
mk(
binary(),
- #{desc => <<"The LwM2M client endpoint name">>}
+ #{desc => ?DESC(endpoint_name)}
)},
{lifetime,
mk(
integer(),
- #{desc => <<"Life time">>}
+ #{desc => ?DESC(lifetime)}
)}
] ++ common_client_props();
fields(exproto_client) ->
@@ -792,33 +754,33 @@ fields(subscription) ->
{topic,
mk(
binary(),
- #{desc => <<"Topic Fillter">>}
+ #{desc => ?DESC(topic)}
)},
{qos,
mk(
integer(),
- #{desc => <<"QoS level, enum: 0, 1, 2">>}
+ #{desc => ?DESC(qos)}
)},
{nl,
%% FIXME: why not boolean?
mk(
integer(),
- #{desc => <<"No Local option, enum: 0, 1">>}
+ #{desc => ?DESC(nl)}
)},
{rap,
mk(
integer(),
- #{desc => <<"Retain as Published option, enum: 0, 1">>}
+ #{desc => ?DESC(rap)}
)},
{rh,
mk(
integer(),
- #{desc => <<"Retain Handling option, enum: 0, 1, 2">>}
+ #{desc => ?DESC(rh)}
)},
{sub_props,
mk(
ref(extra_sub_props),
- #{desc => <<"Subscription properties">>}
+ #{desc => ?DESC(sub_props)}
)}
];
fields(extra_sub_props) ->
@@ -827,10 +789,7 @@ fields(extra_sub_props) ->
mk(
binary(),
#{
- desc => <<
- "Only stomp protocol, a unique identity for "
- "the subscription. range: 1-65535."
- >>
+ desc => ?DESC(subid)
}
)}
].
@@ -841,71 +800,62 @@ common_client_props() ->
mk(
binary(),
#{
- desc => <<
- "Name of the node to which the client is "
- "connected"
- >>
+ desc => ?DESC(node)
}
)},
{clientid,
mk(
binary(),
- #{desc => <<"Client identifier">>}
+ #{desc => ?DESC(clientid)}
)},
{username,
mk(
binary(),
- #{desc => <<"Username of client when connecting">>}
+ #{desc => ?DESC(username)}
)},
{proto_name,
mk(
binary(),
- #{desc => <<"Client protocol name">>}
+ #{desc => ?DESC(proto_name)}
)},
{proto_ver,
mk(
binary(),
- #{desc => <<"Protocol version used by the client">>}
+ #{desc => ?DESC(proto_ver)}
)},
{ip_address,
mk(
binary(),
- #{desc => <<"Client's IP address">>}
+ #{desc => ?DESC(ip_address)}
)},
{port,
mk(
integer(),
- #{desc => <<"Client's port">>}
+ #{desc => ?DESC(port)}
)},
{is_bridge,
mk(
boolean(),
#{
- desc => <<
- "Indicates whether the client is connected via "
- "bridge"
- >>
+ desc => ?DESC(is_bridge)
}
)},
{connected_at,
mk(
emqx_datetime:epoch_millisecond(),
- #{desc => <<"Client connection time">>}
+ #{desc => ?DESC(connected_at)}
)},
{disconnected_at,
mk(
emqx_datetime:epoch_millisecond(),
#{
- desc => <<
- "Client offline time, This field is only valid and "
- "returned when connected is false"
- >>
+ desc => ?DESC(disconnected_at)
}
)},
{connected,
mk(
boolean(),
- #{desc => <<"Whether the client is connected">>}
+ #{desc => ?DESC(connected)}
)},
%% FIXME: the will_msg attribute is not a general attribute
%% for every protocol. But it should be returned to frontend if someone
@@ -913,157 +863,139 @@ common_client_props() ->
%%
%, {will_msg,
% mk(binary(),
- % #{ desc => <<"Client will message">>})}
+ % #{ desc => ?DESC(will_msg)})}
{keepalive,
mk(
integer(),
- #{desc => <<"keepalive time, with the unit of second">>}
+ #{desc => ?DESC(keepalive)}
)},
{clean_start,
mk(
boolean(),
#{
- desc => <<
- "Indicate whether the client is using a brand "
- "new session"
- >>
+ desc => ?DESC(clean_start)
}
)},
{expiry_interval,
mk(
integer(),
#{
- desc => <<
- "Session expiration interval, with the unit of "
- "second"
- >>
+ desc => ?DESC(expiry_interval)
}
)},
{created_at,
mk(
emqx_datetime:epoch_millisecond(),
- #{desc => <<"Session creation time">>}
+ #{desc => ?DESC(created_at)}
)},
{subscriptions_cnt,
mk(
integer(),
#{
- desc => <<
- "Number of subscriptions established by this "
- "client"
- >>
+ desc => ?DESC(subscriptions_cnt)
}
)},
{subscriptions_max,
mk(
integer(),
#{
- desc => <<
- "Maximum number of subscriptions allowed by this "
- "client"
- >>
+ desc => ?DESC(subscriptions_max)
}
)},
{inflight_cnt,
mk(
integer(),
- #{desc => <<"Current length of inflight">>}
+ #{desc => ?DESC(inflight_cnt)}
)},
{inflight_max,
mk(
integer(),
- #{desc => <<"Maximum length of inflight">>}
+ #{desc => ?DESC(inflight_max)}
)},
{mqueue_len,
mk(
integer(),
- #{desc => <<"Current length of message queue">>}
+ #{desc => ?DESC(mqueue_len)}
)},
{mqueue_max,
mk(
integer(),
- #{desc => <<"Maximum length of message queue">>}
+ #{desc => ?DESC(mqueue_max)}
)},
{mqueue_dropped,
mk(
integer(),
#{
- desc => <<
- "Number of messages dropped by the message queue "
- "due to exceeding the length"
- >>
+ desc => ?DESC(mqueue_dropped)
}
)},
{awaiting_rel_cnt,
mk(
integer(),
%% FIXME: PUBREC ??
- #{desc => <<"Number of awaiting acknowledge packet">>}
+ #{desc => ?DESC(awaiting_rel_cnt)}
)},
{awaiting_rel_max,
mk(
integer(),
#{
- desc => <<
- "Maximum allowed number of awaiting PUBREC "
- "packet"
- >>
+ desc => ?DESC(awaiting_rel_max)
}
)},
{recv_oct,
mk(
integer(),
- #{desc => <<"Number of bytes received">>}
+ #{desc => ?DESC(recv_oct)}
)},
{recv_cnt,
mk(
integer(),
- #{desc => <<"Number of socket packets received">>}
+ #{desc => ?DESC(recv_cnt)}
)},
{recv_pkt,
mk(
integer(),
- #{desc => <<"Number of protocol packets received">>}
+ #{desc => ?DESC(recv_pkt)}
)},
{recv_msg,
mk(
integer(),
- #{desc => <<"Number of message packets received">>}
+ #{desc => ?DESC(recv_msg)}
)},
{send_oct,
mk(
integer(),
- #{desc => <<"Number of bytes sent">>}
+ #{desc => ?DESC(send_oct)}
)},
{send_cnt,
mk(
integer(),
- #{desc => <<"Number of socket packets sent">>}
+ #{desc => ?DESC(send_cnt)}
)},
{send_pkt,
mk(
integer(),
- #{desc => <<"Number of protocol packets sent">>}
+ #{desc => ?DESC(send_pkt)}
)},
{send_msg,
mk(
integer(),
- #{desc => <<"Number of message packets sent">>}
+ #{desc => ?DESC(send_msg)}
)},
{mailbox_len,
mk(
integer(),
- #{desc => <<"Process mailbox size">>}
+ #{desc => ?DESC(mailbox_len)}
)},
{heap_size,
mk(
integer(),
- #{desc => <<"Process heap size with the unit of byte">>}
+ #{desc => ?DESC(heap_size)}
)},
{reductions,
mk(
integer(),
- #{desc => <<"Erlang reduction">>}
+ #{desc => ?DESC(reductions)}
)}
].
diff --git a/apps/emqx_gateway/src/emqx_gateway_api_listeners.erl b/apps/emqx_gateway/src/emqx_gateway_api_listeners.erl
index aebe77a7c..9eefbb2c5 100644
--- a/apps/emqx_gateway/src/emqx_gateway_api_listeners.erl
+++ b/apps/emqx_gateway/src/emqx_gateway_api_listeners.erl
@@ -19,6 +19,7 @@
-behaviour(minirest_api).
-include("emqx_gateway_http.hrl").
+-include_lib("hocon/include/hoconsc.hrl").
-include_lib("typerefl/include/types.hrl").
-import(hoconsc, [mk/2, ref/1, ref/2]).
@@ -273,13 +274,13 @@ schema("/gateway/:name/listeners") ->
'operationId' => listeners,
get =>
#{
- desc => <<"Get the gateway listeners">>,
+ desc => ?DESC(list_listeners),
parameters => params_gateway_name_in_path(),
responses =>
?STANDARD_RESP(
#{
200 => emqx_dashboard_swagger:schema_with_example(
- hoconsc:array(ref(listener)),
+ hoconsc:array(emqx_gateway_api:listener_schema()),
examples_listener_list()
)
}
@@ -287,19 +288,19 @@ schema("/gateway/:name/listeners") ->
},
post =>
#{
- desc => <<"Create the gateway listener">>,
+ desc => ?DESC(add_listener),
parameters => params_gateway_name_in_path(),
%% XXX: How to distinguish the different listener supported by
%% different types of gateways?
'requestBody' => emqx_dashboard_swagger:schema_with_examples(
- ref(listener),
+ emqx_gateway_api:listener_schema(),
examples_listener()
),
responses =>
?STANDARD_RESP(
#{
201 => emqx_dashboard_swagger:schema_with_examples(
- ref(listener),
+ emqx_gateway_api:listener_schema(),
examples_listener()
)
}
@@ -311,14 +312,14 @@ schema("/gateway/:name/listeners/:id") ->
'operationId' => listeners_insta,
get =>
#{
- desc => <<"Get the gateway listener configurations">>,
+ desc => ?DESC(get_listener),
parameters => params_gateway_name_in_path() ++
params_listener_id_in_path(),
responses =>
?STANDARD_RESP(
#{
200 => emqx_dashboard_swagger:schema_with_examples(
- ref(listener),
+ emqx_gateway_api:listener_schema(),
examples_listener()
)
}
@@ -326,7 +327,7 @@ schema("/gateway/:name/listeners/:id") ->
},
delete =>
#{
- desc => <<"Delete the gateway listener">>,
+ desc => ?DESC(delete_listener),
parameters => params_gateway_name_in_path() ++
params_listener_id_in_path(),
responses =>
@@ -334,18 +335,18 @@ schema("/gateway/:name/listeners/:id") ->
},
put =>
#{
- desc => <<"Update the gateway listener">>,
+ desc => ?DESC(update_listener),
parameters => params_gateway_name_in_path() ++
params_listener_id_in_path(),
'requestBody' => emqx_dashboard_swagger:schema_with_examples(
- ref(listener),
+ emqx_gateway_api:listener_schema(),
examples_listener()
),
responses =>
?STANDARD_RESP(
#{
200 => emqx_dashboard_swagger:schema_with_examples(
- ref(listener),
+ emqx_gateway_api:listener_schema(),
examples_listener()
)
}
@@ -357,7 +358,7 @@ schema("/gateway/:name/listeners/:id/authentication") ->
'operationId' => listeners_insta_authn,
get =>
#{
- desc => <<"Get the listener's authentication info">>,
+ desc => ?DESC(get_listener_authn),
parameters => params_gateway_name_in_path() ++
params_listener_id_in_path(),
responses =>
@@ -370,7 +371,7 @@ schema("/gateway/:name/listeners/:id/authentication") ->
},
post =>
#{
- desc => <<"Add authentication for the listener">>,
+ desc => ?DESC(add_listener_authn),
parameters => params_gateway_name_in_path() ++
params_listener_id_in_path(),
'requestBody' => schema_authn(),
@@ -379,7 +380,7 @@ schema("/gateway/:name/listeners/:id/authentication") ->
},
put =>
#{
- desc => <<"Update authentication for the listener">>,
+ desc => ?DESC(update_listener_authn),
parameters => params_gateway_name_in_path() ++
params_listener_id_in_path(),
'requestBody' => schema_authn(),
@@ -388,7 +389,7 @@ schema("/gateway/:name/listeners/:id/authentication") ->
},
delete =>
#{
- desc => <<"Remove authentication for the listener">>,
+ desc => ?DESC(delete_listener_authn),
parameters => params_gateway_name_in_path() ++
params_listener_id_in_path(),
responses =>
@@ -400,7 +401,7 @@ schema("/gateway/:name/listeners/:id/authentication/users") ->
'operationId' => users,
get =>
#{
- desc => <<"Get the users for the authentication">>,
+ desc => ?DESC(list_users),
parameters => params_gateway_name_in_path() ++
params_listener_id_in_path() ++
params_paging_in_qs(),
@@ -416,7 +417,7 @@ schema("/gateway/:name/listeners/:id/authentication/users") ->
},
post =>
#{
- desc => <<"Add user for the authentication">>,
+ desc => ?DESC(add_user),
parameters => params_gateway_name_in_path() ++
params_listener_id_in_path(),
'requestBody' => emqx_dashboard_swagger:schema_with_examples(
@@ -439,10 +440,7 @@ schema("/gateway/:name/listeners/:id/authentication/users/:uid") ->
'operationId' => users_insta,
get =>
#{
- desc => <<
- "Get user info from the gateway "
- "authentication"
- >>,
+ desc => ?DESC(get_user),
parameters => params_gateway_name_in_path() ++
params_listener_id_in_path() ++
params_userid_in_path(),
@@ -458,10 +456,7 @@ schema("/gateway/:name/listeners/:id/authentication/users/:uid") ->
},
put =>
#{
- desc => <<
- "Update the user info for the gateway "
- "authentication"
- >>,
+ desc => ?DESC(update_user),
parameters => params_gateway_name_in_path() ++
params_listener_id_in_path() ++
params_userid_in_path(),
@@ -481,10 +476,7 @@ schema("/gateway/:name/listeners/:id/authentication/users/:uid") ->
},
delete =>
#{
- desc => <<
- "Delete the user for the gateway "
- "authentication"
- >>,
+ desc => ?DESC(delete_user),
parameters => params_gateway_name_in_path() ++
params_listener_id_in_path() ++
params_userid_in_path(),
@@ -497,7 +489,7 @@ schema("/gateway/:name/listeners/:id/authentication/import_users") ->
'operationId' => import_users,
post =>
#{
- desc => <<"Import users into the gateway authentication">>,
+ desc => ?DESC(import_users),
parameters => params_gateway_name_in_path() ++
params_listener_id_in_path(),
'requestBody' => emqx_dashboard_swagger:schema_with_examples(
@@ -519,7 +511,7 @@ params_gateway_name_in_path() ->
binary(),
#{
in => path,
- desc => <<"Gateway Name">>,
+ desc => ?DESC(emqx_gateway_api, gateway_name),
example => <<"">>
}
)}
@@ -532,7 +524,7 @@ params_listener_id_in_path() ->
binary(),
#{
in => path,
- desc => <<"Listener ID">>,
+ desc => ?DESC(listener_id),
example => <<"">>
}
)}
@@ -545,35 +537,15 @@ params_userid_in_path() ->
binary(),
#{
in => path,
- desc => <<"User ID">>,
+ desc => ?DESC(emqx_gateway_api_authn, user_id),
example => <<"">>
}
)}
].
params_paging_in_qs() ->
- [
- {page,
- mk(
- pos_integer(),
- #{
- in => query,
- required => false,
- desc => <<"Page Index">>,
- example => 1
- }
- )},
- {limit,
- mk(
- pos_integer(),
- #{
- in => query,
- required => false,
- desc => <<"Page Limit">>,
- example => 100
- }
- )}
- ].
+ emqx_dashboard_swagger:fields(page) ++
+ emqx_dashboard_swagger:fields(limit).
%%--------------------------------------------------------------------
%% schemas
@@ -581,205 +553,8 @@ params_paging_in_qs() ->
roots() ->
[listener].
-fields(listener) ->
- common_listener_opts() ++
- [
- {tcp,
- mk(
- ref(tcp_listener_opts),
- #{
- required => {false, recursively},
- desc => <<"The tcp socket options for tcp or ssl listener">>
- }
- )},
- {ssl,
- mk(
- ref(ssl_listener_opts),
- #{
- required => {false, recursively},
- desc => <<"The ssl socket options for ssl listener">>
- }
- )},
- {udp,
- mk(
- ref(udp_listener_opts),
- #{
- required => {false, recursively},
- desc => <<"The udp socket options for udp or dtls listener">>
- }
- )},
- {dtls,
- mk(
- ref(dtls_listener_opts),
- #{
- required => {false, recursively},
- desc => <<"The dtls socket options for dtls listener">>
- }
- )}
- ];
-fields(tcp_listener_opts) ->
- [
- {active_n, mk(integer(), #{})},
- {backlog, mk(integer(), #{})},
- {buffer, mk(binary(), #{})},
- {recbuf, mk(binary(), #{})},
- {sndbuf, mk(binary(), #{})},
- {high_watermark, mk(binary(), #{})},
- {nodelay, mk(boolean(), #{})},
- {reuseaddr, boolean()},
- %% TODO: duri
- {send_timeout, binary()},
- {send_timeout_close, boolean()}
- ];
-fields(ssl_listener_opts) ->
- %% TODO: maybe use better ssl options schema from emqx_ssl_lib or somewhere
- [
- {cacertfile, binary()},
- {certfile, binary()},
- {keyfile, binary()},
- {verify, binary()},
- {fail_if_no_peer_cert, boolean()},
- {depth, integer()},
- {password, binary()},
- {handshake_timeout, binary()},
- {versions, hoconsc:array(binary())},
- {ciphers, hoconsc:array(binary())},
- {user_lookup_fun, binary()},
- {reuse_sessions, boolean()},
- {secure_renegotiate, boolean()},
- {honor_cipher_order, boolean()},
- {dhfile, binary()}
- ];
-fields(udp_listener_opts) ->
- [
- {active_n, integer()},
- {buffer, binary()},
- {recbuf, binary()},
- {sndbuf, binary()},
- {reuseaddr, boolean()}
- ];
-fields(dtls_listener_opts) ->
- Ls = lists_key_without(
- [versions, ciphers, handshake_timeout],
- 1,
- fields(ssl_listener_opts)
- ),
- [
- {versions, hoconsc:array(binary())},
- {ciphers, hoconsc:array(binary())}
- | Ls
- ].
-
-lists_key_without([], _N, L) ->
- L;
-lists_key_without([K | Ks], N, L) ->
- lists_key_without(Ks, N, lists:keydelete(K, N, L)).
-
-common_listener_opts() ->
- [
- {enable,
- mk(
- boolean(),
- #{
- required => false,
- desc => <<"Whether to enable this listener">>
- }
- )},
- {id,
- mk(
- binary(),
- #{
- required => false,
- desc => <<"Listener Id">>
- }
- )},
- {name,
- mk(
- binary(),
- #{
- required => false,
- desc => <<"Listener name">>
- }
- )},
- {type,
- mk(
- hoconsc:enum([tcp, ssl, udp, dtls]),
- #{
- required => false,
- desc => <<"Listener type. Enum: tcp, udp, ssl, dtls">>
- }
- )},
- {running,
- mk(
- boolean(),
- #{
- required => false,
- desc => <<"Listener running status">>
- }
- )},
- {bind,
- mk(
- binary(),
- #{
- required => false,
- desc => <<"Listener bind address or port">>
- }
- )},
- {acceptors,
- mk(
- integer(),
- #{
- required => false,
- desc => <<"Listener acceptors number">>
- }
- )},
- {access_rules,
- mk(
- hoconsc:array(binary()),
- #{
- required => false,
- desc => <<"Listener Access rules for client">>
- }
- )},
- {max_conn_rate,
- mk(
- integer(),
- #{
- required => false,
- desc => <<"Max connection rate for the listener">>
- }
- )},
- {max_connections,
- mk(
- integer(),
- #{
- required => false,
- desc => <<"Max connections for the listener">>
- }
- )},
- {mountpoint,
- mk(
- binary(),
- #{
- required => false,
- desc =>
- <<
- "The Mountpoint for clients of the listener. "
- "The gateway-level mountpoint configuration can be overloaded "
- "when it is not null or empty string"
- >>
- }
- )},
- %% FIXME:
- {authentication,
- mk(
- emqx_authn_schema:authenticator_type(),
- #{
- required => {false, recursively},
- desc => <<"The authenticator for this listener">>
- }
- )}
- ] ++ emqx_gateway_schema:proxy_protocol_opts().
+fields(_) ->
+ [].
%%--------------------------------------------------------------------
%% examples
diff --git a/apps/emqx_gateway/src/emqx_gateway_schema.erl b/apps/emqx_gateway/src/emqx_gateway_schema.erl
index 385be93ad..8c60b428a 100644
--- a/apps/emqx_gateway/src/emqx_gateway_schema.erl
+++ b/apps/emqx_gateway/src/emqx_gateway_schema.erl
@@ -25,6 +25,7 @@
-dialyzer(no_fail_call).
-include_lib("emqx/include/emqx_authentication.hrl").
+-include_lib("hocon/include/hoconsc.hrl").
-include_lib("typerefl/include/types.hrl").
-type ip_port() :: tuple().
@@ -63,9 +64,7 @@ fields(gateway) ->
ref(stomp),
#{
required => {false, recursively},
- desc =>
- "The Stomp Gateway configuration.
\n"
- "This gateway supports v1.2/1.1/1.0"
+ desc => ?DESC(stomp)
}
)},
{mqttsn,
@@ -73,9 +72,7 @@ fields(gateway) ->
ref(mqttsn),
#{
required => {false, recursively},
- desc =>
- "The MQTT-SN Gateway configuration.
\n"
- "This gateway only supports the v1.2 protocol"
+ desc => ?DESC(mqttsn)
}
)},
{coap,
@@ -83,10 +80,7 @@ fields(gateway) ->
ref(coap),
#{
required => {false, recursively},
- desc =>
- "The CoAP Gateway configuration.
\n"
- "This gateway is implemented based on RFC-7252 and\n"
- "https://core-wg.github.io/coap-pubsub/draft-ietf-core-pubsub.html"
+ desc => ?DESC(coap)
}
)},
{lwm2m,
@@ -94,9 +88,7 @@ fields(gateway) ->
ref(lwm2m),
#{
required => {false, recursively},
- desc =>
- "The LwM2M Gateway configuration.
\n"
- "This gateway only supports the v1.0.1 protocol"
+ desc => ?DESC(lwm2m)
}
)},
{exproto,
@@ -104,14 +96,14 @@ fields(gateway) ->
ref(exproto),
#{
required => {false, recursively},
- desc => "The Extension Protocol configuration"
+ desc => ?DESC(exproto)
}
)}
];
fields(stomp) ->
[
{frame, sc(ref(stomp_frame))},
- {listeners, sc(ref(tcp_listeners))}
+ {listeners, sc(ref(tcp_listeners), #{desc => ?DESC(tcp_listeners)})}
] ++ gateway_common_options();
fields(stomp_frame) ->
[
@@ -120,7 +112,7 @@ fields(stomp_frame) ->
non_neg_integer(),
#{
default => 10,
- desc => "The maximum number of Header"
+ desc => ?DESC(stom_frame_max_headers)
}
)},
{max_headers_length,
@@ -128,7 +120,7 @@ fields(stomp_frame) ->
non_neg_integer(),
#{
default => 1024,
- desc => "The maximum string length of the Header Value"
+ desc => ?DESC(stomp_frame_max_headers_length)
}
)},
{max_body_length,
@@ -136,7 +128,7 @@ fields(stomp_frame) ->
integer(),
#{
default => 65536,
- desc => "Maximum number of bytes of Body allowed per Stomp packet"
+ desc => ?DESC(stom_frame_max_body_length)
}
)}
];
@@ -148,10 +140,7 @@ fields(mqttsn) ->
#{
default => 1,
required => true,
- desc =>
- "MQTT-SN Gateway ID.
\n"
- "When the broadcast
option is enabled,\n"
- "the gateway will broadcast ADVERTISE message with this value"
+ desc => ?DESC(mqttsn_gateway_id)
}
)},
{broadcast,
@@ -159,7 +148,7 @@ fields(mqttsn) ->
boolean(),
#{
default => false,
- desc => "Whether to periodically broadcast ADVERTISE messages"
+ desc => ?DESC(mqttsn_broadcast)
}
)},
%% TODO: rename
@@ -168,12 +157,7 @@ fields(mqttsn) ->
boolean(),
#{
default => true,
- desc =>
- "Allows connectionless clients to publish messages with a Qos of -1.
\n"
- "This feature is defined for very simple client implementations\n"
- "which do not support any other features except this one.
\n"
- "There is no connection setup nor tear down, no registration nor subscription.
\n"
- "The client just sends its 'PUBLISH' messages to a GW"
+ desc => ?DESC(mqttsn_enable_qos3)
}
)},
{subs_resume,
@@ -181,9 +165,7 @@ fields(mqttsn) ->
boolean(),
#{
default => false,
- desc =>
- "Whether to initiate all subscribed topic name registration messages to the\n"
- "client after the Session has been taken over by a new channel."
+ desc => ?DESC(mqttsn_subs_resume)
}
)},
{predefined,
@@ -192,20 +174,24 @@ fields(mqttsn) ->
#{
default => [],
required => {false, recursively},
- desc =>
- <<
- "The pre-defined topic IDs and topic names.
\n"
- "A 'pre-defined' topic ID is a topic ID whose mapping to a topic name\n"
- "is known in advance by both the client's application and the gateway"
- >>
+ desc => ?DESC(mqttsn_predefined)
}
)},
- {listeners, sc(ref(udp_listeners))}
+ {listeners, sc(ref(udp_listeners), #{desc => ?DESC(udp_listeners)})}
] ++ gateway_common_options();
fields(mqttsn_predefined) ->
[
- {id, sc(integer(), #{desc => "Topic ID.
Range: 1-65535"})},
- {topic, sc(binary(), #{desc => "Topic Name"})}
+ {id,
+ sc(integer(), #{
+ required => true,
+ desc => ?DESC(mqttsn_predefined_id)
+ })},
+
+ {topic,
+ sc(binary(), #{
+ required => true,
+ desc => ?DESC(mqttsn_predefined_topic)
+ })}
];
fields(coap) ->
[
@@ -214,10 +200,7 @@ fields(coap) ->
duration(),
#{
default => <<"30s">>,
- desc =>
- "The gateway server required minimum heartbeat interval.
\n"
- "When connection mode is enabled, this parameter is used to set the minimum\n"
- "heartbeat interval for the connection to be alive."
+ desc => ?DESC(coap_heartbeat)
}
)},
{connection_required,
@@ -225,11 +208,7 @@ fields(coap) ->
boolean(),
#{
default => false,
- desc =>
- "Enable or disable connection mode.
\n"
- "Connection mode is a feature of non-standard protocols. When connection mode\n"
- "is enabled, it is necessary to maintain the creation, authentication and alive\n"
- "of connection resources"
+ desc => ?DESC(coap_connection_required)
}
)},
{notify_type,
@@ -237,13 +216,7 @@ fields(coap) ->
hoconsc:union([non, con, qos]),
#{
default => qos,
- desc =>
- "The Notification Message will be delivered to the CoAP client if a new message\n"
- "received on an observed topic.\n"
- "The type of delivered coap message can be set to:
\n"
- "1. non: Non-confirmable;
\n"
- "2. con: Confirmable;
\n"
- "3. qos: Mapping from QoS type of received message, QoS0 -> non, QoS1,2 -> con"
+ desc => ?DESC(coap_notify_type)
}
)},
{subscribe_qos,
@@ -251,15 +224,7 @@ fields(coap) ->
hoconsc:enum([qos0, qos1, qos2, coap]),
#{
default => coap,
- desc =>
- "The Default QoS Level indicator for subscribe request.
\n"
- "This option specifies the QoS level for the CoAP Client when establishing a\n"
- "subscription membership, if the subscribe request is not carried `qos` option.\n"
- "The indicator can be set to:\n"
- " - qos0, qos1, qos2: Fixed default QoS level\n"
- " - coap: Dynamic QoS level by the message type of subscribe request\n"
- " * qos0: If the subscribe request is non-confirmable\n"
- " * qos1: If the subscribe request is confirmable"
+ desc => ?DESC(coap_subscribe_qos)
}
)},
{publish_qos,
@@ -267,21 +232,13 @@ fields(coap) ->
hoconsc:enum([qos0, qos1, qos2, coap]),
#{
default => coap,
- desc =>
- "The Default QoS Level indicator for publish request.
\n"
- "This option specifies the QoS level for the CoAP Client when publishing a\n"
- "message to EMQX PUB/SUB system, if the publish request is not carried `qos`\n"
- "option. The indicator can be set to:\n"
- " - qos0, qos1, qos2: Fixed default QoS level\n"
- " - coap: Dynamic QoS level by the message type of publish request\n"
- " * qos0: If the publish request is non-confirmable\n"
- " * qos1: If the publish request is confirmable"
+ desc => ?DESC(coap_publish_qos)
}
)},
{listeners,
sc(
ref(udp_listeners),
- #{desc => "Listeners (UDP) for CoAP service"}
+ #{desc => ?DESC(udp_listeners)}
)}
] ++ gateway_common_options();
fields(lwm2m) ->
@@ -292,7 +249,7 @@ fields(lwm2m) ->
#{
default => emqx:etc_file("lwm2m_xml"),
required => true,
- desc => "The Directory for LwM2M Resource definition"
+ desc => ?DESC(lwm2m_xml_dir)
}
)},
{lifetime_min,
@@ -300,7 +257,7 @@ fields(lwm2m) ->
duration(),
#{
default => "15s",
- desc => "Minimum value of lifetime allowed to be set by the LwM2M client"
+ desc => ?DESC(lwm2m_lifetime_min)
}
)},
{lifetime_max,
@@ -308,7 +265,7 @@ fields(lwm2m) ->
duration(),
#{
default => "86400s",
- desc => "Maximum value of lifetime allowed to be set by the LwM2M client"
+ desc => ?DESC(lwm2m_lifetime_max)
}
)},
{qmode_time_window,
@@ -316,12 +273,7 @@ fields(lwm2m) ->
duration_s(),
#{
default => "22s",
- desc =>
- "The value of the time window during which the network link is considered\n"
- "valid by the LwM2M Gateway in QMode mode.
\n"
- "For example, after receiving an update message from a client, any messages\n"
- "within this time window are sent directly to the LwM2M client, and all messages\n"
- "beyond this time window are temporarily stored in memory."
+ desc => ?DESC(lwm2m_qmode_time_window)
}
)},
%% TODO: Support config resource path
@@ -330,7 +282,7 @@ fields(lwm2m) ->
boolean(),
#{
default => false,
- desc => "Automatically observe the object list of REGISTER packet"
+ desc => ?DESC(lwm2m_auto_observe)
}
)},
%% FIXME: not working now
@@ -339,11 +291,7 @@ fields(lwm2m) ->
hoconsc:union([always, contains_object_list]),
#{
default => "contains_object_list",
- desc =>
- "Policy for publishing UPDATE event message.
\n"
- " - always: send update events as long as the UPDATE request is received.\n"
- " - contains_object_list: send update events only if the UPDATE request carries "
- "any Object List."
+ desc => ?DESC(lwm2m_update_msg_publish_condition)
}
)},
{translators,
@@ -351,10 +299,10 @@ fields(lwm2m) ->
ref(lwm2m_translators),
#{
required => true,
- desc => "Topic configuration for LwM2M's gateway publishing and subscription"
+ desc => ?DESC(lwm2m_translators)
}
)},
- {listeners, sc(ref(udp_listeners))}
+ {listeners, sc(ref(udp_listeners), #{desc => ?DESC(udp_listeners)})}
] ++ gateway_common_options();
fields(exproto) ->
[
@@ -363,7 +311,7 @@ fields(exproto) ->
ref(exproto_grpc_server),
#{
required => true,
- desc => "Configurations for starting the ConnectionAdapter
service"
+ desc => ?DESC(exproto_server)
}
)},
{handler,
@@ -371,10 +319,10 @@ fields(exproto) ->
ref(exproto_grpc_handler),
#{
required => true,
- desc => "Configurations for request to ConnectionHandler
service"
+ desc => ?DESC(exproto_handler)
}
)},
- {listeners, sc(ref(udp_tcp_listeners))}
+ {listeners, sc(ref(tcp_udp_listeners), #{desc => ?DESC(tcp_udp_listeners)})}
] ++ gateway_common_options();
fields(exproto_grpc_server) ->
[
@@ -383,7 +331,7 @@ fields(exproto_grpc_server) ->
hoconsc:union([ip_port(), integer()]),
#{
required => true,
- desc => "Listening address and port for the gRPC server."
+ desc => ?DESC(exproto_grpc_server_bind)
}
)},
{ssl,
@@ -391,19 +339,19 @@ fields(exproto_grpc_server) ->
ref(ssl_server_opts),
#{
required => {false, recursively},
- desc => "SSL configuration for the gRPC server."
+ desc => ?DESC(exproto_grpc_server_ssl)
}
)}
];
fields(exproto_grpc_handler) ->
[
- {address, sc(binary(), #{required => true, desc => "gRPC server address."})},
+ {address, sc(binary(), #{required => true, desc => ?DESC(exproto_grpc_handler_address)})},
{ssl,
sc(
ref(emqx_schema, ssl_client_opts),
#{
required => {false, recursively},
- desc => "SSL configuration for the gRPC client."
+ desc => ?DESC(exproto_grpc_handler_ssl)
}
)}
];
@@ -419,9 +367,9 @@ fields(ssl_server_opts) ->
);
fields(clientinfo_override) ->
[
- {username, sc(binary(), #{desc => "Template for overriding username."})},
- {password, sc(binary(), #{desc => "Template for overriding password."})},
- {clientid, sc(binary(), #{desc => "Template for overriding clientid."})}
+ {username, sc(binary(), #{desc => ?DESC(gateway_common_clientinfo_override_username)})},
+ {password, sc(binary(), #{desc => ?DESC(gateway_common_clientinfo_override_password)})},
+ {clientid, sc(binary(), #{desc => ?DESC(gateway_common_clientinfo_override_clientid)})}
];
fields(lwm2m_translators) ->
[
@@ -429,11 +377,7 @@ fields(lwm2m_translators) ->
sc(
ref(translator),
#{
- desc =>
- "The topic for receiving downstream commands.
\n"
- "For each new LwM2M client that succeeds in going online, the gateway creates\n"
- "a subscription relationship to receive downstream commands and send it to\n"
- "the LwM2M client",
+ desc => ?DESC(lwm2m_translators_command),
required => true
}
)},
@@ -441,8 +385,7 @@ fields(lwm2m_translators) ->
sc(
ref(translator),
#{
- desc =>
- "The topic for gateway to publish the acknowledge events from LwM2M client",
+ desc => ?DESC(lwm2m_translators_response),
required => true
}
)},
@@ -450,10 +393,7 @@ fields(lwm2m_translators) ->
sc(
ref(translator),
#{
- desc =>
- "The topic for gateway to publish the notify events from LwM2M client.
\n"
- " After succeed observe a resource of LwM2M client, Gateway will send the\n"
- " notify events via this topic, if the client reports any resource changes",
+ desc => ?DESC(lwm2m_translators_notify),
required => true
}
)},
@@ -461,8 +401,7 @@ fields(lwm2m_translators) ->
sc(
ref(translator),
#{
- desc =>
- "The topic for gateway to publish the register events from LwM2M client.
",
+ desc => ?DESC(lwm2m_translators_register),
required => true
}
)},
@@ -470,8 +409,7 @@ fields(lwm2m_translators) ->
sc(
ref(translator),
#{
- desc =>
- "The topic for gateway to publish the update events from LwM2M client.
",
+ desc => ?DESC(lwm2m_translators_update),
required => true
}
)}
@@ -483,7 +421,7 @@ fields(translator) ->
binary(),
#{
required => true,
- desc => "Which topic the device's upstream message is published to."
+ desc => ?DESC(translator_topic)
}
)},
{qos,
@@ -491,31 +429,31 @@ fields(translator) ->
emqx_schema:qos(),
#{
default => 0,
- desc => "QoS of the published messages."
+ desc => ?DESC(translator_qos)
}
)}
];
fields(udp_listeners) ->
[
- {udp, sc(map(name, ref(udp_listener)), #{desc => "UDP configuration."})},
- {dtls, sc(map(name, ref(dtls_listener)), #{desc => "DTLS configuration."})}
+ {udp, sc(map(name, ref(udp_listener)), #{desc => ?DESC(udp_listener)})},
+ {dtls, sc(map(name, ref(dtls_listener)), #{desc => ?DESC(dtls_listener)})}
];
fields(tcp_listeners) ->
[
- {tcp, sc(map(name, ref(tcp_listener)), #{desc => "TCP configuration."})},
- {ssl, sc(map(name, ref(ssl_listener)), #{desc => "SSL configuration."})}
+ {tcp, sc(map(name, ref(tcp_listener)), #{desc => ?DESC(tcp_listener)})},
+ {ssl, sc(map(name, ref(ssl_listener)), #{desc => ?DESC(ssl_listener)})}
];
-fields(udp_tcp_listeners) ->
+fields(tcp_udp_listeners) ->
[
- {udp, sc(map(name, ref(udp_listener)), #{desc => "UDP configuration."})},
- {dtls, sc(map(name, ref(dtls_listener)), #{desc => "DTLS configuration."})},
- {tcp, sc(map(name, ref(tcp_listener)), #{desc => "TCP configuration."})},
- {ssl, sc(map(name, ref(ssl_listener)), #{desc => "SSL configuration."})}
+ {tcp, sc(map(name, ref(tcp_listener)), #{desc => ?DESC(tcp_listener)})},
+ {ssl, sc(map(name, ref(ssl_listener)), #{desc => ?DESC(ssl_listener)})},
+ {udp, sc(map(name, ref(udp_listener)), #{desc => ?DESC(udp_listener)})},
+ {dtls, sc(map(name, ref(dtls_listener)), #{desc => ?DESC(dtls_listener)})}
];
fields(tcp_listener) ->
%% some special configs for tcp listener
[
- {acceptors, sc(integer(), #{default => 16, desc => "Size of the acceptor pool."})}
+ {acceptors, sc(integer(), #{default => 16, desc => ?DESC(tcp_listener_acceptors)})}
] ++
tcp_opts() ++
proxy_protocol_opts() ++
@@ -526,7 +464,7 @@ fields(ssl_listener) ->
{ssl,
sc(
hoconsc:ref(emqx_schema, "listener_ssl_opts"),
- #{desc => "SSL listener options"}
+ #{desc => ?DESC(ssl_listener_options)}
)}
];
fields(udp_listener) ->
@@ -536,9 +474,9 @@ fields(udp_listener) ->
udp_opts() ++
common_listener_opts();
fields(dtls_listener) ->
- [{acceptors, sc(integer(), #{default => 16, desc => "Size of the acceptor pool."})}] ++
+ [{acceptors, sc(integer(), #{default => 16, desc => ?DESC(dtls_listener_acceptors)})}] ++
fields(udp_listener) ++
- [{dtls, sc(ref(dtls_opts), #{desc => "DTLS listener options"})}];
+ [{dtls, sc(ref(dtls_opts), #{desc => ?DESC(dtls_listener_dtls_opts)})}];
fields(udp_opts) ->
[
{active_n,
@@ -546,16 +484,13 @@ fields(udp_opts) ->
integer(),
#{
default => 100,
- desc =>
- "Specify the {active, N} option for the socket.
"
- "See: https://erlang.org/doc/man/inet.html#setopts-2"
+ desc => ?DESC(udp_listener_active_n)
}
)},
- {recbuf,
- sc(bytesize(), #{desc => "Size of the kernel-space receive buffer for the socket."})},
- {sndbuf, sc(bytesize(), #{desc => "Size of the kernel-space send buffer for the socket."})},
- {buffer, sc(bytesize(), #{desc => "Size of the user-space buffer for the socket."})},
- {reuseaddr, sc(boolean(), #{default => true, desc => "Allow local reuse of port numbers."})}
+ {recbuf, sc(bytesize(), #{desc => ?DESC(udp_listener_recbuf)})},
+ {sndbuf, sc(bytesize(), #{desc => ?DESC(udp_listener_sndbuf)})},
+ {buffer, sc(bytesize(), #{desc => ?DESC(udp_listener_buffer)})},
+ {reuseaddr, sc(boolean(), #{default => true, desc => ?DESC(udp_listener_reuseaddr)})}
];
fields(dtls_opts) ->
emqx_schema:server_ssl_opts_schema(
@@ -597,28 +532,6 @@ desc(ssl_server_opts) ->
"SSL configuration for the server.";
desc(clientinfo_override) ->
"ClientInfo override.";
-desc(lwm2m_translators) ->
- "MQTT topics that correspond to LwM2M events.";
-desc(translator) ->
- "MQTT topic that corresponds to a particular type of event.";
-desc(udp_listeners) ->
- "Settings for the UDP listeners.";
-desc(tcp_listeners) ->
- "Settings for the TCP listeners.";
-desc(udp_tcp_listeners) ->
- "Settings for the listeners.";
-desc(tcp_listener) ->
- "Settings for the TCP listener.";
-desc(ssl_listener) ->
- "Settings for the SSL listener.";
-desc(udp_listener) ->
- "Settings for the UDP listener.";
-desc(dtls_listener) ->
- "Settings for the DTLS listener.";
-desc(udp_opts) ->
- "Settings for the UDP sockets.";
-desc(dtls_opts) ->
- "Settings for the DTLS protocol.";
desc(_) ->
undefined.
@@ -627,10 +540,7 @@ authentication_schema() ->
emqx_authn_schema:authenticator_type(),
#{
required => {false, recursively},
- desc =>
- "Default authentication configs for all the gateway listeners.
\n"
- "For per-listener overrides see authentication
\n"
- "in listener configs"
+ desc => ?DESC(gateway_common_authentication)
}
).
@@ -641,7 +551,7 @@ gateway_common_options() ->
boolean(),
#{
default => true,
- desc => "Whether to enable this gateway"
+ desc => ?DESC(gateway_common_enable)
}
)},
{enable_stats,
@@ -649,7 +559,7 @@ gateway_common_options() ->
boolean(),
#{
default => true,
- desc => "Whether to enable client process statistic"
+ desc => ?DESC(gateway_common_enable_stats)
}
)},
{idle_timeout,
@@ -657,13 +567,7 @@ gateway_common_options() ->
duration(),
#{
default => <<"30s">>,
- desc =>
- "The idle time of the client connection process.
\n"
- "It has two purposes:\n"
- "1. A newly created client process that does not receive any client requests\n"
- " after that time will be closed directly.\n"
- "2. A running client process that does not receive any client requests after\n"
- " this time will go into hibernation to save resources."
+ desc => ?DESC(gateway_common_idle_timeout)
}
)},
{mountpoint,
@@ -672,10 +576,14 @@ gateway_common_options() ->
#{
default => <<>>,
%% TODO: variable support?
- desc => ""
+ desc => ?DESC(gateway_common_mountpoint)
}
)},
- {clientinfo_override, sc(ref(clientinfo_override), #{})},
+ {clientinfo_override,
+ sc(
+ ref(clientinfo_override),
+ #{desc => ?DESC(gateway_common_clientinfo_override)}
+ )},
{?EMQX_AUTHENTICATION_CONFIG_ROOT_NAME_ATOM, authentication_schema()}
].
@@ -686,20 +594,20 @@ common_listener_opts() ->
boolean(),
#{
default => true,
- desc => "Enable the listener."
+ desc => ?DESC(gateway_common_listener_enable)
}
)},
{bind,
sc(
hoconsc:union([ip_port(), integer()]),
- #{desc => "The IP address and port that the listener will bind."}
+ #{desc => ?DESC(gateway_common_listener_bind)}
)},
{max_connections,
sc(
integer(),
#{
default => 1024,
- desc => "Maximum number of concurrent connections."
+ desc => ?DESC(gateway_common_listener_max_connections)
}
)},
{max_conn_rate,
@@ -707,7 +615,7 @@ common_listener_opts() ->
integer(),
#{
default => 1000,
- desc => "Maximum connections per second."
+ desc => ?DESC(gateway_common_listener_max_conn_rate)
}
)},
{?EMQX_AUTHENTICATION_CONFIG_ROOT_NAME_ATOM, authentication_schema()},
@@ -716,22 +624,7 @@ common_listener_opts() ->
binary(),
#{
default => undefined,
- desc =>
- "When publishing or subscribing, prefix all topics with a mountpoint string.\n"
- " The prefixed string will be removed from the topic name when the message\n"
- " is delivered to the subscriber. The mountpoint is a way that users can use\n"
- " to implement isolation of message routing between different listeners.\n"
- " For example if a client A subscribes to `t` with `listeners.tcp..mountpoint`\n"
- " set to `some_tenant`, then the client actually subscribes to the topic\n"
- " `some_tenant/t`. Similarly, if another client B (connected to the same listener\n"
- " as the client A) sends a message to topic `t`, the message is routed\n"
- " to all the clients subscribed `some_tenant/t`, so client A will receive the\n"
- " message, with topic name `t`.
\n"
- " Set to `\"\"` to disable the feature.
\n"
- "\n"
- " Variables in mountpoint string:\n"
- " - ${clientid}
: clientid\n"
- " - ${username}
: username"
+ desc => ?DESC(gateway_common_listener_mountpoint)
}
)},
{access_rules,
@@ -739,15 +632,13 @@ common_listener_opts() ->
hoconsc:array(string()),
#{
default => [],
- desc =>
- "The access control rules for this listener.
"
- "See: https://github.com/emqtt/esockd#allowdeny"
+ desc => ?DESC(gateway_common_listener_access_rules)
}
)}
].
tcp_opts() ->
- [{tcp, sc(ref(emqx_schema, "tcp_opts"), #{})}].
+ [{tcp, sc(ref(emqx_schema, "tcp_opts"), #{desc => ?DESC(tcp_listener_tcp_opts)})}].
udp_opts() ->
[{udp, sc(ref(udp_opts), #{})}].
@@ -759,10 +650,7 @@ proxy_protocol_opts() ->
boolean(),
#{
default => false,
- desc =>
- "Enable the Proxy Protocol V1/2 if the EMQX cluster is deployed "
- "behind HAProxy or Nginx.
"
- "See: https://www.haproxy.com/blog/haproxy/proxy-protocol/"
+ desc => ?DESC(tcp_listener_proxy_protocol)
}
)},
{proxy_protocol_timeout,
@@ -770,10 +658,7 @@ proxy_protocol_opts() ->
duration(),
#{
default => "15s",
- desc =>
- "Timeout for proxy protocol.
"
- "EMQX will close the TCP connection if proxy protocol packet is not "
- "received within the timeout."
+ desc => ?DESC(tcp_listener_proxy_protocol_timeout)
}
)}
].
diff --git a/apps/emqx_gateway/src/lwm2m/emqx_lwm2m_api.erl b/apps/emqx_gateway/src/lwm2m/emqx_lwm2m_api.erl
index d053a8b06..1cd7d48a4 100644
--- a/apps/emqx_gateway/src/lwm2m/emqx_lwm2m_api.erl
+++ b/apps/emqx_gateway/src/lwm2m/emqx_lwm2m_api.erl
@@ -17,11 +17,13 @@
-module(emqx_lwm2m_api).
-behaviour(minirest_api).
+
+-include_lib("hocon/include/hoconsc.hrl").
-include_lib("typerefl/include/types.hrl").
-export([api_spec/0, paths/0, schema/1, fields/1, namespace/0]).
--export([lookup_cmd/2, observe/2, read/2, write/2]).
+-export([lookup/2, observe/2, read/2, write/2]).
-define(PATH(Suffix), "/gateway/lwm2m/clients/:clientid" Suffix).
-define(DATA_TYPE, ['Integer', 'Float', 'Time', 'String', 'Boolean', 'Opaque', 'Objlnk']).
@@ -35,14 +37,14 @@ api_spec() ->
emqx_dashboard_swagger:spec(?MODULE).
paths() ->
- [?PATH("/lookup_cmd"), ?PATH("/observe"), ?PATH("/read"), ?PATH("/write")].
+ [?PATH("/lookup"), ?PATH("/observe"), ?PATH("/read"), ?PATH("/write")].
-schema(?PATH("/lookup_cmd")) ->
+schema(?PATH("/lookup")) ->
#{
- 'operationId' => lookup_cmd,
+ 'operationId' => lookup,
get => #{
tags => [<<"lwm2m">>],
- desc => <<"Look up resource">>,
+ desc => ?DESC(lookup_resource),
parameters => [
{clientid, mk(binary(), #{in => path, example => "urn:oma:lwm2m:oma:2"})},
{path, mk(binary(), #{in => query, required => true, example => "/3/0/7"})},
@@ -66,7 +68,7 @@ schema(?PATH("/observe")) ->
'operationId' => observe,
post => #{
tags => [<<"lwm2m">>],
- desc => <<"(cancel) observe resource">>,
+ desc => ?DESC(observe_resource),
parameters => [
{clientid, mk(binary(), #{in => path, example => "urn:oma:lwm2m:oma:2"})},
{path, mk(binary(), #{in => query, required => true, example => "/3/0/7"})},
@@ -84,7 +86,7 @@ schema(?PATH("/read")) ->
'operationId' => read,
post => #{
tags => [<<"lwm2m">>],
- desc => <<"Send a read command to resource">>,
+ desc => ?DESC(read_resource),
parameters => [
{clientid, mk(binary(), #{in => path, example => "urn:oma:lwm2m:oma:2"})},
{path, mk(binary(), #{in => query, required => true, example => "/3/0/7"})}
@@ -99,7 +101,7 @@ schema(?PATH("/write")) ->
#{
'operationId' => write,
post => #{
- desc => <<"Send a write command to resource">>,
+ desc => ?DESC(write_resource),
tags => [<<"lwm2m">>],
parameters => [
{clientid, mk(binary(), #{in => path, example => "urn:oma:lwm2m:oma:2"})},
@@ -120,17 +122,17 @@ schema(?PATH("/write")) ->
fields(resource) ->
[
- {operations, mk(binary(), #{desc => <<"Resource Operations">>, example => "E"})},
+ {operations, mk(binary(), #{desc => ?DESC(operations), example => "E"})},
{'dataType',
mk(hoconsc:enum(?DATA_TYPE), #{
- desc => <<"Data Type">>,
+ desc => ?DESC(dataType),
example => 'Integer'
})},
- {path, mk(binary(), #{desc => <<"Resource Path">>, example => "urn:oma:lwm2m:oma:2"})},
- {name, mk(binary(), #{desc => <<"Resource Name">>, example => "lwm2m-test"})}
+ {path, mk(binary(), #{desc => ?DESC(path), example => "urn:oma:lwm2m:oma:2"})},
+ {name, mk(binary(), #{desc => ?DESC(name), example => "lwm2m-test"})}
].
-lookup_cmd(get, #{bindings := Bindings, query_string := QS}) ->
+lookup(get, #{bindings := Bindings, query_string := QS}) ->
ClientId = maps:get(clientid, Bindings),
case emqx_gateway_cm_registry:lookup_channels(lwm2m, ClientId) of
[Channel | _] ->
@@ -139,12 +141,12 @@ lookup_cmd(get, #{bindings := Bindings, query_string := QS}) ->
<<"action">> := Action
} = QS,
{ok, Result} = emqx_lwm2m_channel:lookup_cmd(Channel, Path, Action),
- lookup_cmd_return(Result, ClientId, Action, Path);
+ lookup_return(Result, ClientId, Action, Path);
_ ->
{404, #{code => 'CLIENT_NOT_FOUND'}}
end.
-lookup_cmd_return(undefined, ClientId, Action, Path) ->
+lookup_return(undefined, ClientId, Action, Path) ->
{200, #{
clientid => ClientId,
action => Action,
@@ -152,7 +154,7 @@ lookup_cmd_return(undefined, ClientId, Action, Path) ->
codeMsg => <<"reply_not_received">>,
path => Path
}};
-lookup_cmd_return({Code, CodeMsg, Content}, ClientId, Action, Path) ->
+lookup_return({Code, CodeMsg, Content}, ClientId, Action, Path) ->
{200,
format_cmd_content(
Content,