From eb4b9936dcc19fad4266fd5a62bf798250d3688e Mon Sep 17 00:00:00 2001 From: turtled Date: Sun, 11 Oct 2020 11:12:39 +0800 Subject: [PATCH 01/41] fix(modules): fix conflicts --- etc/acl.conf | 26 - etc/acl.conf.paho | 14 - etc/cluster.conf | 170 ++ etc/emqx.conf | 1938 +-------------------- etc/listeners.conf | 928 ++++++++++ etc/logger.conf | 170 ++ etc/rpc.conf | 98 ++ etc/sys_mon.conf | 148 ++ etc/zones.conf | 327 ++++ priv/emqx.schema | 112 +- rebar.config | 2 +- src/emqx_access_rule.erl | 155 -- src/emqx_alarm.erl | 8 +- src/emqx_app.erl | 10 +- src/emqx_channel.erl | 59 +- src/emqx_cm_locker.erl | 2 +- src/emqx_gen_mod.erl | 23 - src/emqx_mod_acl_internal.erl | 122 -- src/emqx_mod_delayed.erl | 204 --- src/emqx_mod_presence.erl | 130 -- src/emqx_mod_rewrite.erl | 103 -- src/emqx_mod_subscription.erl | 65 - src/emqx_mod_sup.erl | 63 - src/emqx_mod_topic_metrics.erl | 382 ---- src/emqx_modules.erl | 169 -- src/emqx_session.erl | 2 +- src/emqx_sup.erl | 3 +- src/emqx_types.erl | 1 + test/emqx_access_SUITE_data/acl_temp.conf | 1 + test/emqx_access_rule_SUITE.erl | 97 -- test/emqx_acl_cache_SUITE.erl | 23 +- test/emqx_acl_test_mod.erl | 33 - test/emqx_channel_SUITE.erl | 15 +- test/emqx_mod_acl_internal_SUITE.erl | 64 - test/emqx_mod_delayed_SUITE.erl | 78 - test/emqx_mod_presence_SUITE.erl | 88 - test/emqx_mod_rewrite_SUITE.erl | 93 - test/emqx_mod_subscription_SUITE.erl | 92 - test/emqx_mod_sup_SUITE.erl | 51 - test/emqx_mod_topic_metrics_SUITE.erl | 92 - test/emqx_modules_SUITE.erl | 47 - test/mqtt_protocol_v5_SUITE.erl | 8 +- 42 files changed, 1933 insertions(+), 4283 deletions(-) delete mode 100644 etc/acl.conf delete mode 100644 etc/acl.conf.paho create mode 100644 etc/cluster.conf create mode 100644 etc/listeners.conf create mode 100644 etc/logger.conf create mode 100644 etc/rpc.conf create mode 100644 etc/sys_mon.conf create mode 100644 etc/zones.conf delete mode 100644 src/emqx_access_rule.erl delete mode 100644 src/emqx_gen_mod.erl delete mode 100644 src/emqx_mod_acl_internal.erl delete mode 100644 src/emqx_mod_delayed.erl delete mode 100644 src/emqx_mod_presence.erl delete mode 100644 src/emqx_mod_rewrite.erl delete mode 100644 src/emqx_mod_subscription.erl delete mode 100644 src/emqx_mod_sup.erl delete mode 100644 src/emqx_mod_topic_metrics.erl delete mode 100644 src/emqx_modules.erl create mode 100644 test/emqx_access_SUITE_data/acl_temp.conf delete mode 100644 test/emqx_access_rule_SUITE.erl delete mode 100644 test/emqx_acl_test_mod.erl delete mode 100644 test/emqx_mod_acl_internal_SUITE.erl delete mode 100644 test/emqx_mod_delayed_SUITE.erl delete mode 100644 test/emqx_mod_presence_SUITE.erl delete mode 100644 test/emqx_mod_rewrite_SUITE.erl delete mode 100644 test/emqx_mod_subscription_SUITE.erl delete mode 100644 test/emqx_mod_sup_SUITE.erl delete mode 100644 test/emqx_mod_topic_metrics_SUITE.erl delete mode 100644 test/emqx_modules_SUITE.erl diff --git a/etc/acl.conf b/etc/acl.conf deleted file mode 100644 index af2fb0dd1..000000000 --- a/etc/acl.conf +++ /dev/null @@ -1,26 +0,0 @@ -%%-------------------------------------------------------------------- -%% [ACL](https://docs.emqx.io/broker/v3/en/config.html) -%% -%% -type(who() :: all | binary() | -%% {ipaddr, esockd_access:cidr()} | -%% {client, binary()} | -%% {user, binary()}). -%% -%% -type(access() :: subscribe | publish | pubsub). -%% -%% -type(topic() :: binary()). -%% -%% -type(rule() :: {allow, all} | -%% {allow, who(), access(), list(topic())} | -%% {deny, all} | -%% {deny, who(), access(), list(topic())}). -%%-------------------------------------------------------------------- - -{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}. - -{allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}. - -{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}. - -{allow, all}. - diff --git a/etc/acl.conf.paho b/etc/acl.conf.paho deleted file mode 100644 index 5beec4347..000000000 --- a/etc/acl.conf.paho +++ /dev/null @@ -1,14 +0,0 @@ -%%-------------------------------------------------------------------- -%% For paho interoperability test cases -%%-------------------------------------------------------------------- - -{deny, {client, "myclientid"}, subscribe, ["test/nosubscribe"]}. - -{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}. - -{allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}. - -{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}. - -{allow, all}. - diff --git a/etc/cluster.conf b/etc/cluster.conf new file mode 100644 index 000000000..cd4d3d007 --- /dev/null +++ b/etc/cluster.conf @@ -0,0 +1,170 @@ +##-------------------------------------------------------------------- +## Cluster +##-------------------------------------------------------------------- + +## Cluster name. +## +## Value: String +cluster.name = emqxcl + +## Specify the erlang distributed protocol. +## +## Value: Enum +## - inet_tcp: the default; handles TCP streams with IPv4 addressing. +## - inet6_tcp: handles TCP with IPv6 addressing. +## - inet_tls: using TLS for Erlang Distribution. +## +## vm.args: -proto_dist inet_tcp +cluster.proto_dist = inet_tcp + +## Cluster auto-discovery strategy. +## +## Value: Enum +## - manual: Manual join command +## - static: Static node list +## - mcast: IP Multicast +## - dns: DNS A Record +## - etcd: etcd +## - k8s: Kubernetes +## +## Default: manual +cluster.discovery = manual + +## Enable cluster autoheal from network partition. +## +## Value: on | off +## +## Default: on +cluster.autoheal = on + +## Autoclean down node. A down node will be removed from the cluster +## if this value > 0. +## +## Value: Duration +## -h: hour, e.g. '2h' for 2 hours +## -m: minute, e.g. '5m' for 5 minutes +## -s: second, e.g. '30s' for 30 seconds +## +## Default: 5m +cluster.autoclean = 5m + +##-------------------------------------------------------------------- +## Cluster using static node list + +## Node list of the cluster. +## +## Value: String +## cluster.static.seeds = emqx1@127.0.0.1,emqx2@127.0.0.1 + +##-------------------------------------------------------------------- +## Cluster using IP Multicast. + +## IP Multicast Address. +## +## Value: IP Address +## cluster.mcast.addr = 239.192.0.1 + +## Multicast Ports. +## +## Value: Port List +## cluster.mcast.ports = 4369,4370 + +## Multicast Iface. +## +## Value: Iface Address +## +## Default: 0.0.0.0 +## cluster.mcast.iface = 0.0.0.0 + +## Multicast Ttl. +## +## Value: 0-255 +## cluster.mcast.ttl = 255 + +## Multicast loop. +## +## Value: on | off +## cluster.mcast.loop = on + +##-------------------------------------------------------------------- +## Cluster using DNS A records. + +## DNS name. +## +## Value: String +## cluster.dns.name = localhost + +## The App name is used to build 'node.name' with IP address. +## +## Value: String +## cluster.dns.app = emqx + +##-------------------------------------------------------------------- +## Cluster using etcd + +## Etcd server list, seperated by ','. +## +## Value: String +## cluster.etcd.server = http://127.0.0.1:2379 + +## The prefix helps build nodes path in etcd. Each node in the cluster +## will create a path in etcd: v2/keys/// +## +## Value: String +## cluster.etcd.prefix = emqxcl + +## The TTL for node's path in etcd. +## +## Value: Duration +## +## Default: 1m, 1 minute +## cluster.etcd.node_ttl = 1m + +## Path to a file containing the client's private PEM-encoded key. +## +## Value: File +## cluster.etcd.ssl.keyfile = {{ platform_etc_dir }}/certs/client-key.pem + +## The path to a file containing the client's certificate. +## +## Value: File +## cluster.etcd.ssl.certfile = {{ platform_etc_dir }}/certs/client.pem + +## Path to the file containing PEM-encoded CA certificates. The CA certificates +## are used during server authentication and when building the client certificate chain. +## +## Value: File +## cluster.etcd.ssl.cacertfile = {{ platform_etc_dir }}/certs/ca.pem + +##-------------------------------------------------------------------- +## Cluster using Kubernetes + +## Kubernetes API server list, seperated by ','. +## +## Value: String +## cluster.k8s.apiserver = http://10.110.111.204:8080 + +## The service name helps lookup EMQ nodes in the cluster. +## +## Value: String +## cluster.k8s.service_name = emqx + +## The address type is used to extract host from k8s service. +## +## Value: ip | dns | hostname +## cluster.k8s.address_type = ip + +## The app name helps build 'node.name'. +## +## Value: String +## cluster.k8s.app_name = emqx + +## The suffix added to dns and hostname get from k8s service +## +## Value: String +## cluster.k8s.suffix = pod.cluster.local + +## Kubernetes Namespace +## +## Value: String +## cluster.k8s.namespace = default \ No newline at end of file diff --git a/etc/emqx.conf b/etc/emqx.conf index f6ded1032..58cf05cbe 100644 --- a/etc/emqx.conf +++ b/etc/emqx.conf @@ -2,176 +2,12 @@ ## EMQ X Configuration R4.0 ##==================================================================== -##-------------------------------------------------------------------- -## Cluster -##-------------------------------------------------------------------- - -## Cluster name. -## -## Value: String -cluster.name = emqxcl - -## Specify the erlang distributed protocol. -## -## Value: Enum -## - inet_tcp: the default; handles TCP streams with IPv4 addressing. -## - inet6_tcp: handles TCP with IPv6 addressing. -## - inet_tls: using TLS for Erlang Distribution. -## -## vm.args: -proto_dist inet_tcp -cluster.proto_dist = inet_tcp - -## Cluster auto-discovery strategy. -## -## Value: Enum -## - manual: Manual join command -## - static: Static node list -## - mcast: IP Multicast -## - dns: DNS A Record -## - etcd: etcd -## - k8s: Kubernetes -## -## Default: manual -cluster.discovery = manual - -## Enable cluster autoheal from network partition. -## -## Value: on | off -## -## Default: on -cluster.autoheal = on - -## Autoclean down node. A down node will be removed from the cluster -## if this value > 0. -## -## Value: Duration -## -h: hour, e.g. '2h' for 2 hours -## -m: minute, e.g. '5m' for 5 minutes -## -s: second, e.g. '30s' for 30 seconds -## -## Default: 5m -cluster.autoclean = 5m - -##-------------------------------------------------------------------- -## Cluster using static node list - -## Node list of the cluster. -## -## Value: String -## cluster.static.seeds = emqx1@127.0.0.1,emqx2@127.0.0.1 - -##-------------------------------------------------------------------- -## Cluster using IP Multicast. - -## IP Multicast Address. -## -## Value: IP Address -## cluster.mcast.addr = 239.192.0.1 - -## Multicast Ports. -## -## Value: Port List -## cluster.mcast.ports = 4369,4370 - -## Multicast Iface. -## -## Value: Iface Address -## -## Default: 0.0.0.0 -## cluster.mcast.iface = 0.0.0.0 - -## Multicast Ttl. -## -## Value: 0-255 -## cluster.mcast.ttl = 255 - -## Multicast loop. -## -## Value: on | off -## cluster.mcast.loop = on - -##-------------------------------------------------------------------- -## Cluster using DNS A records. - -## DNS name. -## -## Value: String -## cluster.dns.name = localhost - -## The App name is used to build 'node.name' with IP address. -## -## Value: String -## cluster.dns.app = emqx - -##-------------------------------------------------------------------- -## Cluster using etcd - -## Etcd server list, seperated by ','. -## -## Value: String -## cluster.etcd.server = http://127.0.0.1:2379 - -## The prefix helps build nodes path in etcd. Each node in the cluster -## will create a path in etcd: v2/keys/// -## -## Value: String -## cluster.etcd.prefix = emqxcl - -## The TTL for node's path in etcd. -## -## Value: Duration -## -## Default: 1m, 1 minute -## cluster.etcd.node_ttl = 1m - -## Path to a file containing the client's private PEM-encoded key. -## -## Value: File -## cluster.etcd.ssl.keyfile = {{ platform_etc_dir }}/certs/client-key.pem - -## The path to a file containing the client's certificate. -## -## Value: File -## cluster.etcd.ssl.certfile = {{ platform_etc_dir }}/certs/client.pem - -## Path to the file containing PEM-encoded CA certificates. The CA certificates -## are used during server authentication and when building the client certificate chain. -## -## Value: File -## cluster.etcd.ssl.cacertfile = {{ platform_etc_dir }}/certs/ca.pem - -##-------------------------------------------------------------------- -## Cluster using Kubernetes - -## Kubernetes API server list, seperated by ','. -## -## Value: String -## cluster.k8s.apiserver = http://10.110.111.204:8080 - -## The service name helps lookup EMQ nodes in the cluster. -## -## Value: String -## cluster.k8s.service_name = emqx - -## The address type is used to extract host from k8s service. -## -## Value: ip | dns | hostname -## cluster.k8s.address_type = ip - -## The app name helps build 'node.name'. -## -## Value: String -## cluster.k8s.app_name = emqx - -## The suffix added to dns and hostname get from k8s service -## -## Value: String -## cluster.k8s.suffix = pod.cluster.local - -## Kubernetes Namespace -## -## Value: String -## cluster.k8s.namespace = default +include {{ platform_etc_dir }}/cluster.conf +include {{ platform_etc_dir }}/rpc.conf +include {{ platform_etc_dir }}/logger.conf +include {{ platform_etc_dir }}/zones.conf +include {{ platform_etc_dir }}/listeners.conf +include {{ platform_etc_dir }}/sys_mon.conf ##-------------------------------------------------------------------- ## Node @@ -301,276 +137,6 @@ node.crash_dump = {{ platform_log_dir }}/crash.dump node.dist_listen_min = 6369 node.dist_listen_max = 6369 -##-------------------------------------------------------------------- -## RPC -##-------------------------------------------------------------------- -## RPC Mode. -## -## Value: sync | async -rpc.mode = async - -## Max batch size of async RPC requests. -## -## Value: Integer -## Zero or negative value disables rpc batching. -## -## NOTE: RPC batch won't work when rpc.mode = sync -rpc.async_batch_size = 256 - -## RPC port discovery -## -## The strategy for discovering the RPC listening port of other nodes. -## -## Value: Enum -## - manual: discover ports by `tcp_server_port` and `tcp_client_port`. -## - stateless: discover ports in a stateless manner. -## If node name is `emqx@127.0.0.1`, where the `` is an integer, -## then the listening port will be `5370 + ` -## -## Defaults to `stateless`. -rpc.port_discovery = stateless - -## TCP server port for RPC. -## -## Only takes effect when `rpc.port_discovery` = `manual`. -## -## Value: Port [1024-65535] -#rpc.tcp_server_port = 5369 - -## TCP port for outgoing RPC connections. -## -## Only takes effect when `rpc.port_discovery` = `manual`. -## -## Value: Port [1024-65535] -#rpc.tcp_client_port = 5369 - -## Number of outgoing RPC connections. -## -## Value: Interger [1-256] -## Defaults to NumberOfCPUSchedulers / 2 -#rpc.tcp_client_num = 1 - -## RCP Client connect timeout. -## -## Value: Seconds -rpc.connect_timeout = 5s - -## TCP send timeout of RPC client and server. -## -## Value: Seconds -rpc.send_timeout = 5s - -## Authentication timeout -## -## Value: Seconds -rpc.authentication_timeout = 5s - -## Default receive timeout for call() functions -## -## Value: Seconds -rpc.call_receive_timeout = 15s - -## Socket idle keepalive. -## -## Value: Seconds -rpc.socket_keepalive_idle = 900s - -## TCP Keepalive probes interval. -## -## Value: Seconds -rpc.socket_keepalive_interval = 75s - -## Probes lost to close the connection -## -## Value: Integer -rpc.socket_keepalive_count = 9 - -## Size of TCP send buffer. -## -## Value: Bytes -rpc.socket_sndbuf = 1MB - -## Size of TCP receive buffer. -## -## Value: Seconds -rpc.socket_recbuf = 1MB - -## Size of user-level software socket buffer. -## -## Value: Seconds -rpc.socket_buffer = 1MB - -##-------------------------------------------------------------------- -## Log -##-------------------------------------------------------------------- - -## Where to emit the logs. -## Enable the console (standard output) logs. -## -## Value: off | file | console | both -## - off: disable logs entirely -## - file: write logs only to file -## - console: write logs only to standard I/O -## - both: write logs both to file and standard I/O -log.to = both - -## The log severity level. -## -## Value: debug | info | notice | warning | error | critical | alert | emergency -## -## Note: Only the messages with severity level higher than or equal to -## this level will be logged. -## -## Default: warning -log.level = warning - -## The dir for log files. -## -## Value: Folder -log.dir = {{ platform_log_dir }} - -## The log filename for logs of level specified in "log.level". -## -## If `log.rotation` is enabled, this is the base name of the -## files. Each file in a rotated log is named .N, where N is an integer. -## -## Value: String -## Default: emqx.log -log.file = emqx.log - -## Limits the total number of characters printed for each log event. -## -## Value: Integer -## Default: No Limit -#log.chars_limit = 8192 - -## Enables the log rotation. -## With this enabled, new log files will be created when the current -## log file is full, max to `log.rotation.size` files will be created. -## -## Value: on | off -## Default: on -log.rotation = on - -## Maximum size of each log file. -## -## Value: Number -## Default: 10M -## Supported Unit: KB | MB | GB -log.rotation.size = 10MB - -## Maximum rotation count of log files. -## -## Value: Number -## Default: 5 -log.rotation.count = 5 - -## To create additional log files for specific log levels. -## -## Value: File Name -## Format: log.$level.file = $filename, -## where "$level" can be one of: debug, info, notice, warning, -## error, critical, alert, emergency -## Note: Log files for a specific log level will only contain all the logs -## that higher than or equal to that level -## -#log.info.file = info.log -#log.error.file = error.log - -## The max allowed queue length before switching to sync mode. -## -## Log overload protection parameter. If the message queue grows -## larger than this value the handler switches from anync to sync mode. -## -## Default: 100 -## -#log.sync_mode_qlen = 100 - -## The max allowed queue length before switching to drop mode. -## -## Log overload protection parameter. When the message queue grows -## larger than this threshold, the handler switches to a mode in which -## it drops all new events that senders want to log. -## -## Default: 3000 -## -#log.drop_mode_qlen = 3000 - -## The max allowed queue length before switching to flush mode. -## -## Log overload protection parameter. If the length of the message queue -## grows larger than this threshold, a flush (delete) operation takes place. -## To flush events, the handler discards the messages in the message queue -## by receiving them in a loop without logging. -## -## Default: 8000 -## -#log.flush_qlen = 8000 - -## Kill the log handler when it gets overloaded. -## -## Log overload protection parameter. It is possible that a handler, -## even if it can successfully manage peaks of high load without crashing, -## can build up a large message queue, or use a large amount of memory. -## We could kill the log handler in these cases and restart it after a -## few seconds. -## -## Default: on -## -#log.overload_kill = on - -## The max allowed queue length before killing the log hanlder. -## -## Log overload protection parameter. This is the maximum allowed queue -## length. If the message queue grows larger than this, the handler -## process is terminated. -## -## Default: 20000 -## -#log.overload_kill_qlen = 20000 - -## The max allowed memory size before killing the log hanlder. -## -## Log overload protection parameter. This is the maximum memory size -## that the handler process is allowed to use. If the handler grows -## larger than this, the process is terminated. -## -## Default: 30MB -## -#log.overload_kill_mem_size = 30MB - -## Restart the log hanlder after some seconds. -## -## Log overload protection parameter. If the handler is terminated, -## it restarts automatically after a delay specified in seconds. -## The value "infinity" prevents restarts. -## -## Default: 5s -## -#log.overload_kill_restart_after = 5s - -## Max burst count and time window for burst control. -## -## Log overload protection parameter. Large bursts of log events - many -## events received by the handler under a short period of time - can -## potentially cause problems. By specifying the maximum number of events -## to be handled within a certain time frame, the handler can avoid -## choking the log with massive amounts of printouts. -## -## This config controls the maximum number of events to handle within -## a time frame. After the limit is reached, successive events are -## dropped until the end of the time frame. -## -## Note that there would be no warning if any messages were -## dropped because of burst control. -## -## Comment this config out to disable the burst control feature. -## -## Value: MaxBurstCount,TimeWindow -## Default: disabled -## -#log.burst_limit = 20000, 1s - ##-------------------------------------------------------------------- ## Authentication/Access Control ##-------------------------------------------------------------------- @@ -586,11 +152,6 @@ allow_anonymous = true ## Value: allow | deny acl_nomatch = allow -## Default ACL File. -## -## Value: File Name -acl_file = {{ platform_etc_dir }}/acl.conf - ## Whether to enable ACL cache. ## ## If enabled, ACLs roles for each client will be cached in the memory @@ -685,1340 +246,6 @@ mqtt.strict_mode = false ## Value: String ## mqtt.response_information = example -##-------------------------------------------------------------------- -## Zones -##-------------------------------------------------------------------- - -##-------------------------------------------------------------------- -## External Zone - -## Idle timeout of the external MQTT connections. -## -## Value: duration -zone.external.idle_timeout = 15s - -## Enable ACL check. -## -## Value: Flag -zone.external.enable_acl = on - -## Enable ban check. -## -## Value: Flag -zone.external.enable_ban = on - -## Enable per connection statistics. -## -## Value: on | off -zone.external.enable_stats = on - -## The action when acl check reject current operation -## -## Value: ignore | disconnect -## Default: ignore -zone.external.acl_deny_action = ignore - -## Force the MQTT connection process GC after this number of -## messages | bytes passed through. -## -## Numbers delimited by `|'. Zero or negative is to disable. -zone.external.force_gc_policy = 16000|16MB - -## Max message queue length and total heap size to force shutdown -## connection/session process. -## Message queue here is the Erlang process mailbox, but not the number -## of queued MQTT messages of QoS 1 and 2. -## -## Numbers delimited by `|'. Zero or negative is to disable. -## zone.external.force_shutdown_policy = 32000|32MB - -## Maximum MQTT packet size allowed. -## -## Value: Bytes -## Default: 1MB -## zone.external.max_packet_size = 64KB - -## Maximum length of MQTT clientId allowed. -## -## Value: Number [23-65535] -## zone.external.max_clientid_len = 1024 - -## Maximum topic levels allowed. 0 means no limit. -## -## Value: Number -## zone.external.max_topic_levels = 7 - -## Maximum QoS allowed. -## -## Value: 0 | 1 | 2 -## zone.external.max_qos_allowed = 2 - -## Maximum Topic Alias, 0 means no limit. -## -## Value: 0-65535 -## zone.external.max_topic_alias = 65535 - -## Whether the Server supports retained messages. -## -## Value: boolean -## zone.external.retain_available = true - -## Whether the Server supports Wildcard Subscriptions -## -## Value: boolean -## zone.external.wildcard_subscription = false - -## Whether the Server supports Shared Subscriptions -## -## Value: boolean -## zone.external.shared_subscription = false - -## Server Keep Alive -## -## Value: Number -## zone.external.server_keepalive = 0 - -## The backoff for MQTT keepalive timeout. The broker will kick a connection out -## until 'Keepalive * backoff * 2' timeout. -## -## Value: Float > 0.5 -zone.external.keepalive_backoff = 0.75 - -## Maximum number of subscriptions allowed, 0 means no limit. -## -## Value: Number -zone.external.max_subscriptions = 0 - -## Force to upgrade QoS according to subscription. -## -## Value: on | off -zone.external.upgrade_qos = off - -## Maximum size of the Inflight Window storing QoS1/2 messages delivered but unacked. -## -## Value: Number -zone.external.max_inflight = 32 - -## Retry interval for QoS1/2 message delivering. -## -## Value: Duration -zone.external.retry_interval = 30s - -## Maximum QoS2 packets (Client -> Broker) awaiting PUBREL, 0 means no limit. -## -## Value: Number -zone.external.max_awaiting_rel = 100 - -## The QoS2 messages (Client -> Broker) will be dropped if awaiting PUBREL timeout. -## -## Value: Duration -zone.external.await_rel_timeout = 300s - -## Default session expiry interval for MQTT V3.1.1 connections. -## -## Value: Duration -## -d: day -## -h: hour -## -m: minute -## -s: second -## -## Default: 2h, 2 hours -zone.external.session_expiry_interval = 2h - -## Maximum queue length. Enqueued messages when persistent client disconnected, -## or inflight window is full. 0 means no limit. -## -## Value: Number >= 0 -zone.external.max_mqueue_len = 1000 - -## Topic priorities. -## 'none' to indicate no priority table (by default), hence all messages -## are treated equal -## -## Priority number [1-255] -## Example: topic/1=10,topic/2=8 -## NOTE: comma and equal signs are not allowed for priority topic names -## NOTE: messages for topics not in the priority table are treated as -## either highest or lowest priority depending on the configured -## value for mqueue_default_priority -## -zone.external.mqueue_priorities = none - -## Default to highest priority for topics not matching priority table -## -## Value: highest | lowest -zone.external.mqueue_default_priority = highest - -## Whether to enqueue QoS0 messages. -## -## Value: false | true -zone.external.mqueue_store_qos0 = true - -## Whether to turn on flapping detect -## -## Value: on | off -zone.external.enable_flapping_detect = off - -## Message limit for the a external MQTT connection. -## -## Value: Number,Duration -## Example: 100 messages per 10 seconds. -#zone.external.rate_limit.conn_messages_in = 100,10s - -## Bytes limit for a external MQTT connections. -## -## Value: Number,Duration -## Example: 100KB incoming per 10 seconds. -#zone.external.rate_limit.conn_bytes_in = 100KB,10s - -## Messages quota for the each of external MQTT connection. -## This value consumed by the number of recipient on a message. -## -## Value: Number, Duration -## -## Example: 100 messaegs per 1s -#zone.external.quota.conn_messages_routing = 100,1s - -## Messages quota for the all of external MQTT connections. -## This value consumed by the number of recipient on a message. -## -## Value: Number, Duration -## -## Example: 200000 messaegs per 1s -#zone.external.quota.overall_messages_routing = 200000,1s - -## All the topics will be prefixed with the mountpoint path if this option is enabled. -## -## Variables in mountpoint path: -## - %c: clientid -## - %u: username -## -## Value: String -## zone.external.mountpoint = devicebound/ - -## Whether use username replace client id -## -## Value: boolean -## Default: false -zone.external.use_username_as_clientid = false - -## Whether to ignore loop delivery of messages.(for mqtt v3.1.1) -## -## Value: true | false -zone.external.ignore_loop_deliver = false - -## Whether to parse the MQTT frame in strict mode -## -## Value: true | false -zone.external.strict_mode = false - -## Specify the response information returned to the client -## -## Value: String -## zone.external.response_information = example - -##-------------------------------------------------------------------- -## Internal Zone - -zone.internal.allow_anonymous = true - -## Enable per connection stats. -## -## Value: Flag -zone.internal.enable_stats = on - -## Enable ACL check. -## -## Value: Flag -zone.internal.enable_acl = off - -## The action when acl check reject current operation -## -## Value: ignore | disconnect -## Default: ignore -zone.internal.acl_deny_action = ignore - -## See zone.$name.force_gc_policy -## zone.internal.force_gc_policy = 128000|128MB - -## See zone.$name.wildcard_subscription. -## -## Value: boolean -## zone.internal.wildcard_subscription = true - -## See zone.$name.shared_subscription. -## -## Value: boolean -## zone.internal.shared_subscription = true - -## See zone.$name.max_subscriptions. -## -## Value: Integer -zone.internal.max_subscriptions = 0 - -## See zone.$name.max_inflight -## -## Value: Number -zone.internal.max_inflight = 128 - -## See zone.$name.max_awaiting_rel -## -## Value: Number -zone.internal.max_awaiting_rel = 1000 - -## See zone.$name.max_mqueue_len -## -## Value: Number >= 0 -zone.internal.max_mqueue_len = 10000 - -## Whether to enqueue Qos0 messages. -## -## Value: false | true -zone.internal.mqueue_store_qos0 = true - -## Whether to turn on flapping detect -## -## Value: on | off -zone.internal.enable_flapping_detect = off - -## See zone.$name.force_shutdown_policy -## zone.internal.force_shutdown_policy = 128000|128MB - -## All the topics will be prefixed with the mountpoint path if this option is enabled. -## -## Variables in mountpoint path: -## - %c: clientid -## - %u: username -## -## Value: String -## zone.internal.mountpoint = cloudbound/ - -## Whether to ignore loop delivery of messages.(for mqtt v3.1.1) -## -## Value: true | false -zone.internal.ignore_loop_deliver = false - -## Whether to parse the MQTT frame in strict mode -## -## Value: true | false -zone.internal.strict_mode = false - -## Specify the response information returned to the client -## -## Value: String -## zone.internal.response_information = example - -## Allow the zone's clients to bypass authentication step -## -## Value: true | false -zone.internal.bypass_auth_plugins = true - -##-------------------------------------------------------------------- -## Listeners -##-------------------------------------------------------------------- - -##-------------------------------------------------------------------- -## MQTT/TCP - External TCP Listener for MQTT Protocol - -## listener.tcp.$name is the IP address and port that the MQTT/TCP -## listener will bind. -## -## Value: IP:Port | Port -## -## Examples: 1883, 127.0.0.1:1883, ::1:1883 -listener.tcp.external = 0.0.0.0:1883 - -## The acceptor pool for external MQTT/TCP listener. -## -## Value: Number -listener.tcp.external.acceptors = 8 - -## Maximum number of concurrent MQTT/TCP connections. -## -## Value: Number -listener.tcp.external.max_connections = 1024000 - -## Maximum external connections per second. -## -## Value: Number -listener.tcp.external.max_conn_rate = 1000 - -## Specify the {active, N} option for the external MQTT/TCP Socket. -## -## Value: Number -listener.tcp.external.active_n = 100 - -## Zone of the external MQTT/TCP listener belonged to. -## -## See: zone.$name.* -## -## Value: String -listener.tcp.external.zone = external - -## The access control rules for the MQTT/TCP listener. -## -## See: https://github.com/emqtt/esockd#allowdeny -## -## Value: ACL Rule -## -## Example: allow 192.168.0.0/24 -listener.tcp.external.access.1 = allow all - -## Enable the Proxy Protocol V1/2 if the EMQ X cluster is deployed -## behind HAProxy or Nginx. -## -## See: https://www.haproxy.com/blog/haproxy/proxy-protocol/ -## -## Value: on | off -## listener.tcp.external.proxy_protocol = on - -## Sets the timeout for proxy protocol. EMQ X will close the TCP connection -## if no proxy protocol packet recevied within the timeout. -## -## Value: Duration -## listener.tcp.external.proxy_protocol_timeout = 3s - -## Enable the option for X.509 certificate based authentication. -## EMQX will use the common name of certificate as MQTT username. -## -## Value: cn | dn | crt -## listener.tcp.external.peer_cert_as_username = cn - -## The TCP backlog defines the maximum length that the queue of pending -## connections can grow to. -## -## Value: Number >= 0 -listener.tcp.external.backlog = 1024 - -## The TCP send timeout for external MQTT connections. -## -## Value: Duration -listener.tcp.external.send_timeout = 15s - -## Close the TCP connection if send timeout. -## -## Value: on | off -listener.tcp.external.send_timeout_close = on - -## The TCP receive buffer(os kernel) for MQTT connections. -## -## See: http://erlang.org/doc/man/inet.html -## -## Value: Bytes -## listener.tcp.external.recbuf = 2KB - -## The TCP send buffer(os kernel) for MQTT connections. -## -## See: http://erlang.org/doc/man/inet.html -## -## Value: Bytes -## listener.tcp.external.sndbuf = 2KB - -## The size of the user-level software buffer used by the driver. -## Not to be confused with options sndbuf and recbuf, which correspond -## to the Kernel socket buffers. It is recommended to have val(buffer) -## >= max(val(sndbuf),val(recbuf)) to avoid performance issues because -## of unnecessary copying. val(buffer) is automatically set to the above -## maximum when values sndbuf or recbuf are set. -## -## See: http://erlang.org/doc/man/inet.html -## -## Value: Bytes -## listener.tcp.external.buffer = 2KB - -## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. -## -## Value: on | off -## listener.tcp.external.tune_buffer = off - -## The TCP_NODELAY flag for MQTT connections. Small amounts of data are -## sent immediately if the option is enabled. -## -## Value: true | false -listener.tcp.external.nodelay = true - -## The SO_REUSEADDR flag for TCP listener. -## -## Value: true | false -listener.tcp.external.reuseaddr = true - -##-------------------------------------------------------------------- -## Internal TCP Listener for MQTT Protocol - -## The IP address and port that the internal MQTT/TCP protocol listener -## will bind. -## -## Value: IP:Port, Port -## -## Examples: 11883, 127.0.0.1:11883, ::1:11883 -listener.tcp.internal = 127.0.0.1:11883 - -## The acceptor pool for internal MQTT/TCP listener. -## -## Value: Number -listener.tcp.internal.acceptors = 4 - -## Maximum number of concurrent MQTT/TCP connections. -## -## Value: Number -listener.tcp.internal.max_connections = 1024000 - -## Maximum internal connections per second. -## -## Value: Number -listener.tcp.internal.max_conn_rate = 1000 - -## Specify the {active, N} option for the internal MQTT/TCP Socket. -## -## Value: Number -listener.tcp.internal.active_n = 1000 - -## Zone of the internal MQTT/TCP listener belonged to. -## -## Value: String -listener.tcp.internal.zone = internal - -## The TCP backlog of internal MQTT/TCP Listener. -## -## See: listener.tcp.$name.backlog -## -## Value: Number >= 0 -listener.tcp.internal.backlog = 512 - -## The TCP send timeout for internal MQTT connections. -## -## See: listener.tcp.$name.send_timeout -## -## Value: Duration -listener.tcp.internal.send_timeout = 5s - -## Close the MQTT/TCP connection if send timeout. -## -## See: listener.tcp.$name.send_timeout_close -## -## Value: on | off -listener.tcp.internal.send_timeout_close = on - -## The TCP receive buffer(os kernel) for internal MQTT connections. -## -## See: listener.tcp.$name.recbuf -## -## Value: Bytes -listener.tcp.internal.recbuf = 64KB - -## The TCP send buffer(os kernel) for internal MQTT connections. -## -## See: http://erlang.org/doc/man/inet.html -## -## Value: Bytes -listener.tcp.internal.sndbuf = 64KB - -## The size of the user-level software buffer used by the driver. -## -## See: listener.tcp.$name.buffer -## -## Value: Bytes -## listener.tcp.internal.buffer = 16KB - -## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. -## -## See: listener.tcp.$name.tune_buffer -## -## Value: on | off -## listener.tcp.internal.tune_buffer = off - -## The TCP_NODELAY flag for internal MQTT connections. -## -## See: listener.tcp.$name.nodelay -## -## Value: true | false -listener.tcp.internal.nodelay = false - -## The SO_REUSEADDR flag for MQTT/TCP Listener. -## -## Value: true | false -listener.tcp.internal.reuseaddr = true - -##-------------------------------------------------------------------- -## MQTT/SSL - External SSL Listener for MQTT Protocol - -## listener.ssl.$name is the IP address and port that the MQTT/SSL -## listener will bind. -## -## Value: IP:Port | Port -## -## Examples: 8883, 127.0.0.1:8883, ::1:8883 -listener.ssl.external = 8883 - -## The acceptor pool for external MQTT/SSL listener. -## -## Value: Number -listener.ssl.external.acceptors = 16 - -## Maximum number of concurrent MQTT/SSL connections. -## -## Value: Number -listener.ssl.external.max_connections = 102400 - -## Maximum MQTT/SSL connections per second. -## -## Value: Number -listener.ssl.external.max_conn_rate = 500 - -## Specify the {active, N} option for the internal MQTT/SSL Socket. -## -## Value: Number -listener.ssl.external.active_n = 100 - -## Zone of the external MQTT/SSL listener belonged to. -## -## Value: String -listener.ssl.external.zone = external - -## The access control rules for the MQTT/SSL listener. -## -## See: listener.tcp.$name.access -## -## Value: ACL Rule -listener.ssl.external.access.1 = allow all - -## Enable the Proxy Protocol V1/2 if the EMQ cluster is deployed behind -## HAProxy or Nginx. -## -## See: listener.tcp.$name.proxy_protocol -## -## Value: on | off -## listener.ssl.external.proxy_protocol = on - -## Sets the timeout for proxy protocol. -## -## See: listener.tcp.$name.proxy_protocol_timeout -## -## Value: Duration -## listener.ssl.external.proxy_protocol_timeout = 3s - -## TLS versions only to protect from POODLE attack. -## -## See: http://erlang.org/doc/man/ssl.html -## -## Value: String, seperated by ',' -## listener.ssl.external.tls_versions = tlsv1.2,tlsv1.1,tlsv1 - -## TLS Handshake timeout. -## -## Value: Duration -listener.ssl.external.handshake_timeout = 15s - -## Path to the file containing the user's private PEM-encoded key. -## -## See: http://erlang.org/doc/man/ssl.html -## -## Value: File -listener.ssl.external.keyfile = {{ platform_etc_dir }}/certs/key.pem - -## Path to a file containing the user certificate. -## -## See: http://erlang.org/doc/man/ssl.html -## -## Value: File -listener.ssl.external.certfile = {{ platform_etc_dir }}/certs/cert.pem - -## Path to the file containing PEM-encoded CA certificates. The CA certificates -## are used during server authentication and when building the client certificate chain. -## -## Value: File -## listener.ssl.external.cacertfile = {{ platform_etc_dir }}/certs/cacert.pem - -## The Ephemeral Diffie-Helman key exchange is a very effective way of -## ensuring Forward Secrecy by exchanging a set of keys that never hit -## the wire. Since the DH key is effectively signed by the private key, -## it needs to be at least as strong as the private key. In addition, -## the default DH groups that most of the OpenSSL installations have -## are only a handful (since they are distributed with the OpenSSL -## package that has been built for the operating system it’s running on) -## and hence predictable (not to mention, 1024 bits only). -## In order to escape this situation, first we need to generate a fresh, -## strong DH group, store it in a file and then use the option above, -## to force our SSL application to use the new DH group. Fortunately, -## OpenSSL provides us with a tool to do that. Simply run: -## openssl dhparam -out dh-params.pem 2048 -## -## Value: File -## listener.ssl.external.dhfile = {{ platform_etc_dir }}/certs/dh-params.pem - -## A server only does x509-path validation in mode verify_peer, -## as it then sends a certificate request to the client (this -## message is not sent if the verify option is verify_none). -## You can then also want to specify option fail_if_no_peer_cert. -## More information at: http://erlang.org/doc/man/ssl.html -## -## Value: verify_peer | verify_none -## listener.ssl.external.verify = verify_peer - -## Used together with {verify, verify_peer} by an SSL server. If set to true, -## the server fails if the client does not have a certificate to send, that is, -## sends an empty certificate. -## -## Value: true | false -## listener.ssl.external.fail_if_no_peer_cert = true - -## This is the single most important configuration option of an Erlang SSL -## application. Ciphers (and their ordering) define the way the client and -## server encrypt information over the wire, from the initial Diffie-Helman -## key exchange, the session key encryption ## algorithm and the message -## digest algorithm. Selecting a good cipher suite is critical for the -## application’s data security, confidentiality and performance. -## -## The cipher list above offers: -## -## A good balance between compatibility with older browsers. -## It can get stricter for Machine-To-Machine scenarios. -## Perfect Forward Secrecy. -## No old/insecure encryption and HMAC algorithms -## -## Most of it was copied from Mozilla’s Server Side TLS article -## -## Value: Ciphers -listener.ssl.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA - -## Ciphers for TLS PSK. -## Note that 'listener.ssl.external.ciphers' and 'listener.ssl.external.psk_ciphers' cannot -## be configured at the same time. -## See 'https://tools.ietf.org/html/rfc4279#section-2'. -#listener.ssl.external.psk_ciphers = PSK-AES128-CBC-SHA,PSK-AES256-CBC-SHA,PSK-3DES-EDE-CBC-SHA,PSK-RC4-SHA - -## SSL parameter renegotiation is a feature that allows a client and a server -## to renegotiate the parameters of the SSL connection on the fly. -## RFC 5746 defines a more secure way of doing this. By enabling secure renegotiation, -## you drop support for the insecure renegotiation, prone to MitM attacks. -## -## Value: on | off -## listener.ssl.external.secure_renegotiate = off - -## A performance optimization setting, it allows clients to reuse -## pre-existing sessions, instead of initializing new ones. -## Read more about it here. -## -## See: http://erlang.org/doc/man/ssl.html -## -## Value: on | off -## listener.ssl.external.reuse_sessions = on - -## An important security setting, it forces the cipher to be set based -## on the server-specified order instead of the client-specified order, -## hence enforcing the (usually more properly configured) security -## ordering of the server administrator. -## -## Value: on | off -## listener.ssl.external.honor_cipher_order = on - -## Use the CN, DN or CRT field from the client certificate as a username. -## Notice that 'verify' should be set as 'verify_peer'. -## -## Value: cn | dn | crt -## listener.ssl.external.peer_cert_as_username = cn - -## TCP backlog for the SSL connection. -## -## See listener.tcp.$name.backlog -## -## Value: Number >= 0 -## listener.ssl.external.backlog = 1024 - -## The TCP send timeout for the SSL connection. -## -## See listener.tcp.$name.send_timeout -## -## Value: Duration -## listener.ssl.external.send_timeout = 15s - -## Close the SSL connection if send timeout. -## -## See: listener.tcp.$name.send_timeout_close -## -## Value: on | off -## listener.ssl.external.send_timeout_close = on - -## The TCP receive buffer(os kernel) for the SSL connections. -## -## See: listener.tcp.$name.recbuf -## -## Value: Bytes -## listener.ssl.external.recbuf = 4KB - -## The TCP send buffer(os kernel) for internal MQTT connections. -## -## See: listener.tcp.$name.sndbuf -## -## Value: Bytes -## listener.ssl.external.sndbuf = 4KB - -## The size of the user-level software buffer used by the driver. -## -## See: listener.tcp.$name.buffer -## -## Value: Bytes -## listener.ssl.external.buffer = 4KB - -## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. -## -## See: listener.tcp.$name.tune_buffer -## -## Value: on | off -## listener.ssl.external.tune_buffer = off - -## The TCP_NODELAY flag for SSL connections. -## -## See: listener.tcp.$name.nodelay -## -## Value: true | false -## listener.ssl.external.nodelay = true - -## The SO_REUSEADDR flag for MQTT/SSL Listener. -## -## Value: true | false -listener.ssl.external.reuseaddr = true - -##-------------------------------------------------------------------- -## External WebSocket listener for MQTT protocol - -## listener.ws.$name is the IP address and port that the MQTT/WebSocket -## listener will bind. -## -## Value: IP:Port | Port -## -## Examples: 8083, 127.0.0.1:8083, ::1:8083 -listener.ws.external = 8083 - -## The path of WebSocket MQTT endpoint -## -## Value: URL Path -listener.ws.external.mqtt_path = /mqtt - -## The acceptor pool for external MQTT/WebSocket listener. -## -## Value: Number -listener.ws.external.acceptors = 4 - -## Maximum number of concurrent MQTT/WebSocket connections. -## -## Value: Number -listener.ws.external.max_connections = 102400 - -## Maximum MQTT/WebSocket connections per second. -## -## Value: Number -listener.ws.external.max_conn_rate = 1000 - -## Simulate the {active, N} option for the MQTT/WebSocket connections. -## -## Value: Number -listener.ws.external.active_n = 100 - -## Zone of the external MQTT/WebSocket listener belonged to. -## -## Value: String -listener.ws.external.zone = external - -## The access control for the MQTT/WebSocket listener. -## -## See: listener.ws.$name.access -## -## Value: ACL Rule -listener.ws.external.access.1 = allow all - -## Verify if the protocol header is valid. Turn off for WeChat MiniApp. -## -## Value: on | off -listener.ws.external.verify_protocol_header = on - -## Enable the Proxy Protocol V1/2 if the EMQ cluster is deployed behind -## HAProxy or Nginx. -## -## See: listener.ws.$name.proxy_protocol -## -## Value: on | off -## listener.ws.external.proxy_protocol = on - -## Sets the timeout for proxy protocol. -## -## See: listener.ws.$name.proxy_protocol_timeout -## -## Value: Duration -## listener.ws.external.proxy_protocol_timeout = 3s - -## The TCP backlog of external MQTT/WebSocket Listener. -## -## See: listener.ws.$name.backlog -## -## Value: Number >= 0 -listener.ws.external.backlog = 1024 - -## The TCP send timeout for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.send_timeout -## -## Value: Duration -listener.ws.external.send_timeout = 15s - -## Close the MQTT/WebSocket connection if send timeout. -## -## See: listener.ws.$name.send_timeout_close -## -## Value: on | off -listener.ws.external.send_timeout_close = on - -## The TCP receive buffer(os kernel) for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.recbuf -## -## Value: Bytes -## listener.ws.external.recbuf = 2KB - -## The TCP send buffer(os kernel) for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.sndbuf -## -## Value: Bytes -## listener.ws.external.sndbuf = 2KB - -## The size of the user-level software buffer used by the driver. -## -## See: listener.ws.$name.buffer -## -## Value: Bytes -## listener.ws.external.buffer = 2KB - -## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. -## -## See: listener.ws.$name.tune_buffer -## -## Value: on | off -## listener.ws.external.tune_buffer = off - -## The TCP_NODELAY flag for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.nodelay -## -## Value: true | false -listener.ws.external.nodelay = true - -## The compress flag for external MQTT/WebSocket connections. -## -## If this Value is set true,the websocket message would be compressed -## -## Value: true | false -## listener.ws.external.compress = true - -## The level of deflate options for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.level -## -## Value: none | default | best_compression | best_speed -## listener.ws.external.deflate_opts.level = default - -## The mem_level of deflate options for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.mem_level -## -## Valid range is 1-9 -## listener.ws.external.deflate_opts.mem_level = 8 - -## The strategy of deflate options for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.strategy -## -## Value: default | filtered | huffman_only | rle -## listener.ws.external.deflate_opts.strategy = default - -## The deflate option for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.server_context_takeover -## -## Value: takeover | no_takeover -## listener.ws.external.deflate_opts.server_context_takeover = takeover - -## The deflate option for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.client_context_takeover -## -## Value: takeover | no_takeover -## listener.ws.external.deflate_opts.client_context_takeover = takeover - -## The deflate options for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.server_max_window_bits -## -## Valid range is 8-15 -## listener.ws.external.deflate_opts.server_max_window_bits = 15 - -## The deflate options for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.client_max_window_bits -## -## Valid range is 8-15 -## listener.ws.external.deflate_opts.client_max_window_bits = 15 - -## The idle timeout for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.idle_timeout -## -## Value: Duration -## listener.ws.external.idle_timeout = 60s - -## The max frame size for external MQTT/WebSocket connections. -## -## -## Value: Number -## listener.ws.external.max_frame_size = 0 - -## Whether a WebSocket message is allowed to contain multiple MQTT packets -## -## Value: single | multiple -listener.ws.external.mqtt_piggyback = multiple - -##-------------------------------------------------------------------- -## External WebSocket/SSL listener for MQTT Protocol - -## listener.wss.$name is the IP address and port that the MQTT/WebSocket/SSL -## listener will bind. -## -## Value: IP:Port | Port -## -## Examples: 8084, 127.0.0.1:8084, ::1:8084 -listener.wss.external = 8084 - -## The path of WebSocket MQTT endpoint -## -## Value: URL Path -listener.wss.external.mqtt_path = /mqtt - -## The acceptor pool for external MQTT/WebSocket/SSL listener. -## -## Value: Number -listener.wss.external.acceptors = 4 - -## Maximum number of concurrent MQTT/Webwocket/SSL connections. -## -## Value: Number -listener.wss.external.max_connections = 16 - -## Maximum MQTT/WebSocket/SSL connections per second. -## -## See: listener.tcp.$name.max_conn_rate -## -## Value: Number -listener.wss.external.max_conn_rate = 1000 - -## Simulate the {active, N} option for the MQTT/WebSocket/SSL connections. -## -## Value: Number -listener.wss.external.active_n = 100 - -## Zone of the external MQTT/WebSocket/SSL listener belonged to. -## -## Value: String -listener.wss.external.zone = external - -## The access control rules for the MQTT/WebSocket/SSL listener. -## -## See: listener.tcp.$name.access. -## -## Value: ACL Rule -listener.wss.external.access.1 = allow all - -## See: listener.ws.external.verify_protocol_header -## -## Value: on | off -listener.wss.external.verify_protocol_header = on - -## Enable the Proxy Protocol V1/2 support. -## -## See: listener.tcp.$name.proxy_protocol -## -## Value: on | off -## listener.wss.external.proxy_protocol = on - -## Sets the timeout for proxy protocol. -## -## See: listener.tcp.$name.proxy_protocol_timeout -## -## Value: Duration -## listener.wss.external.proxy_protocol_timeout = 3s - -## TLS versions only to protect from POODLE attack. -## -## See: listener.ssl.$name.tls_versions -## -## Value: String, seperated by ',' -## listener.wss.external.tls_versions = tlsv1.2,tlsv1.1,tlsv1 - -## Path to the file containing the user's private PEM-encoded key. -## -## See: listener.ssl.$name.keyfile -## -## Value: File -listener.wss.external.keyfile = {{ platform_etc_dir }}/certs/key.pem - -## Path to a file containing the user certificate. -## -## See: listener.ssl.$name.certfile -## -## Value: File -listener.wss.external.certfile = {{ platform_etc_dir }}/certs/cert.pem - -## Path to the file containing PEM-encoded CA certificates. -## -## See: listener.ssl.$name.cacert -## -## Value: File -## listener.wss.external.cacertfile = {{ platform_etc_dir }}/certs/cacert.pem - -## See: listener.ssl.$name.dhfile -## -## Value: File -## listener.ssl.external.dhfile = {{ platform_etc_dir }}/certs/dh-params.pem - -## See: listener.ssl.$name.vefify -## -## Value: vefify_peer | verify_none -## listener.wss.external.verify = verify_peer - -## See: listener.ssl.$name.fail_if_no_peer_cert -## -## Value: false | true -## listener.wss.external.fail_if_no_peer_cert = true - -## See: listener.ssl.$name.ciphers -## -## Value: Ciphers -listener.wss.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA - -## Ciphers for TLS PSK. -## Note that 'listener.wss.external.ciphers' and 'listener.wss.external.psk_ciphers' cannot -## be configured at the same time. -## See 'https://tools.ietf.org/html/rfc4279#section-2'. -## listener.wss.external.psk_ciphers = PSK-AES128-CBC-SHA,PSK-AES256-CBC-SHA,PSK-3DES-EDE-CBC-SHA,PSK-RC4-SHA - -## See: listener.ssl.$name.secure_renegotiate -## -## Value: on | off -## listener.wss.external.secure_renegotiate = off - -## See: listener.ssl.$name.reuse_sessions -## -## Value: on | off -## listener.wss.external.reuse_sessions = on - -## See: listener.ssl.$name.honor_cipher_order -## -## Value: on | off -## listener.wss.external.honor_cipher_order = on - -## See: listener.ssl.$name.peer_cert_as_username -## -## Value: cn | dn | crt -## listener.wss.external.peer_cert_as_username = cn - -## TCP backlog for the WebSocket/SSL connection. -## -## See: listener.tcp.$name.backlog -## -## Value: Number >= 0 -listener.wss.external.backlog = 1024 - -## The TCP send timeout for the WebSocket/SSL connection. -## -## See: listener.tcp.$name.send_timeout -## -## Value: Duration -listener.wss.external.send_timeout = 15s - -## Close the WebSocket/SSL connection if send timeout. -## -## See: listener.tcp.$name.send_timeout_close -## -## Value: on | off -listener.wss.external.send_timeout_close = on - -## The TCP receive buffer(os kernel) for the WebSocket/SSL connections. -## -## See: listener.tcp.$name.recbuf -## -## Value: Bytes -## listener.wss.external.recbuf = 4KB - -## The TCP send buffer(os kernel) for the WebSocket/SSL connections. -## -## See: listener.tcp.$name.sndbuf -## -## Value: Bytes -## listener.wss.external.sndbuf = 4KB - -## The size of the user-level software buffer used by the driver. -## -## See: listener.tcp.$name.buffer -## -## Value: Bytes -## listener.wss.external.buffer = 4KB - -## The TCP_NODELAY flag for WebSocket/SSL connections. -## -## See: listener.tcp.$name.nodelay -## -## Value: true | false -## listener.wss.external.nodelay = true - -## The compress flag for external WebSocket/SSL connections. -## -## If this Value is set true,the websocket message would be compressed -## -## Value: true | false -## listener.wss.external.compress = true - -## The level of deflate options for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.level -## -## Value: none | default | best_compression | best_speed -## listener.wss.external.deflate_opts.level = default - -## The mem_level of deflate options for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.mem_level -## -## Valid range is 1-9 -## listener.wss.external.deflate_opts.mem_level = 8 - -## The strategy of deflate options for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.strategy -## -## Value: default | filtered | huffman_only | rle -## listener.wss.external.deflate_opts.strategy = default - -## The deflate option for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.server_context_takeover -## -## Value: takeover | no_takeover -## listener.wss.external.deflate_opts.server_context_takeover = takeover - -## The deflate option for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.client_context_takeover -## -## Value: takeover | no_takeover -## listener.wss.external.deflate_opts.client_context_takeover = takeover - -## The deflate options for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.server_max_window_bits -## -## Valid range is 8-15 -## listener.wss.external.deflate_opts.server_max_window_bits = 15 - -## The deflate options for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.client_max_window_bits -## -## Valid range is 8-15 -## listener.wss.external.deflate_opts.client_max_window_bits = 15 - -## The idle timeout for external WebSocket/SSL connections. -## -## See: listener.wss.$name.idle_timeout -## -## Value: Duration -## listener.wss.external.idle_timeout = 60s - -## The max frame size for external WebSocket/SSL connections. -## -## Value: Number -## listener.wss.external.max_frame_size = 0 - -## Whether a WebSocket message is allowed to contain multiple MQTT packets -## -## Value: single | multiple -listener.wss.external.mqtt_piggyback = multiple - -##-------------------------------------------------------------------- -## Modules -##-------------------------------------------------------------------- -## The file to store loaded module names. -## -## Value: File -modules.loaded_file = {{ platform_data_dir }}/loaded_modules - -##-------------------------------------------------------------------- -## Presence Module - -## Sets the QoS for presence MQTT message. -## -## Value: 0 | 1 | 2 -module.presence.qos = 1 - -##-------------------------------------------------------------------- -## Subscription Module - -## Subscribe the Topics automatically when client connected. -## -## Value: String -## module.subscription.1.topic = connected/%c/%u - -## Qos of the proxy subscription. -## -## Value: 0 | 1 | 2 -## Default: 0 -## module.subscription.1.qos = 0 - -## No Local of the proxy subscription options. -## This configuration only takes effect in the MQTT V5 protocol. -## -## Value: 0 | 1 -## Default: 0 -## module.subscription.1.nl = 0 - -## Retain As Published of the proxy subscription options. -## This configuration only takes effect in the MQTT V5 protocol. -## -## Value: 0 | 1 -## Default: 0 -## module.subscription.1.rap = 0 - -## Retain Handling of the proxy subscription options. -## This configuration only takes effect in the MQTT V5 protocol. -## -## Value: 0 | 1 | 2 -## Default: 0 -## module.subscription.1.rh = 0 - -##-------------------------------------------------------------------- -## Rewrite Module - -## {rewrite, Topic, Re, Dest} -## module.rewrite.pub.rule.1 = x/# ^x/y/(.+)$ z/y/$1 -## module.rewrite.sub.rule.1 = y/+/z/# ^y/(.+)/z/(.+)$ y/z/$2 - -##------------------------------------------------------------------- -## Plugins -##------------------------------------------------------------------- - -## The etc dir for plugins' config. -## -## Value: Folder -plugins.etc_dir = {{ platform_etc_dir }}/plugins/ - -## The file to store loaded plugin names. -## -## Value: File -plugins.loaded_file = {{ platform_data_dir }}/loaded_plugins - -## The directory of extension plugins. -## -## Value: File -plugins.expand_plugins_dir = {{ platform_plugins_dir }}/ - ##-------------------------------------------------------------------- ## Broker ##-------------------------------------------------------------------- @@ -2069,153 +296,18 @@ broker.shared_dispatch_ack_enabled = false ## Value: Flag broker.route_batch_clean = off -##-------------------------------------------------------------------- -## System Monitor -##-------------------------------------------------------------------- +##------------------------------------------------------------------- +## Plugins +##------------------------------------------------------------------- -## Enable Long GC monitoring. Disable if the value is 0. -## Notice: don't enable the monitor in production for: -## https://github.com/erlang/otp/blob/feb45017da36be78d4c5784d758ede619fa7bfd3/erts/emulator/beam/erl_gc.c#L421 +## The etc dir for plugins' config. ## -## Value: Duration -## - h: hour -## - m: minute -## - s: second -## - ms: milliseconds -## -## Examples: -## - 2h: 2 hours -## - 30m: 30 minutes -## - 0.1s: 0.1 seconds -## - 100ms : 100 milliseconds -## -## Default: 0ms -sysmon.long_gc = 0 +## Value: Folder +plugins.etc_dir = {{ platform_etc_dir }}/plugins/ -## Enable Long Schedule(ms) monitoring. +## The file to store loaded plugin names. ## -## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 -## -## Value: Duration -## - h: hour -## - m: minute -## - s: second -## - ms: milliseconds -## -## Examples: -## - 2h: 2 hours -## - 30m: 30 minutes -## - 0.1s: 0.1 seconds -## - 100ms: 100 milliseconds -## -## Default: 0ms -sysmon.long_schedule = 240ms - -## Enable Large Heap monitoring. -## -## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 -## -## Value: bytes -## -## Default: 8M words. 32MB on 32-bit VM, 64MB on 64-bit VM. -sysmon.large_heap = 8MB - -## Enable Busy Port monitoring. -## -## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 -## -## Value: true | false -sysmon.busy_port = false - -## Enable Busy Dist Port monitoring. -## -## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 -## -## Value: true | false -sysmon.busy_dist_port = true - -## The time interval for the periodic cpu check -## -## Value: Duration -## -h: hour, e.g. '2h' for 2 hours -## -m: minute, e.g. '5m' for 5 minutes -## -s: second, e.g. '30s' for 30 seconds -## -## Default: 60s -os_mon.cpu_check_interval = 60s - -## The threshold, as percentage of system cpu, for how much system cpu can be used before the corresponding alarm is set. -## -## Default: 80% -os_mon.cpu_high_watermark = 80% - -## The threshold, as percentage of system cpu, for how much system cpu can be used before the corresponding alarm is clear. -## -## Default: 60% -os_mon.cpu_low_watermark = 60% - -## The time interval for the periodic memory check -## -## Value: Duration -## -h: hour, e.g. '2h' for 2 hours -## -m: minute, e.g. '5m' for 5 minutes -## -s: second, e.g. '30s' for 30 seconds -## -## Default: 60s -os_mon.mem_check_interval = 60s - -## The threshold, as percentage of system memory, for how much system memory can be allocated before the corresponding alarm is set. -## -## Default: 70% -os_mon.sysmem_high_watermark = 70% - -## The threshold, as percentage of system memory, for how much system memory can be allocated by one Erlang process before the corresponding alarm is set. -## -## Default: 5% -os_mon.procmem_high_watermark = 5% - -## The time interval for the periodic process limit check -## -## Value: Duration -## -## Default: 30s -vm_mon.check_interval = 30s - -## The threshold, as percentage of processes, for how many processes can simultaneously exist at the local node before the corresponding alarm is set. -## -## Default: 80% -vm_mon.process_high_watermark = 80% - -## The threshold, as percentage of processes, for how many processes can simultaneously exist at the local node before the corresponding alarm is clear. -## -## Default: 60% -vm_mon.process_low_watermark = 60% - -## Specifies the actions to take when an alarm is activated -## -## Value: String -## - log -## - publish -## -## Default: log,publish -alarm.actions = log,publish - -## The maximum number of deactivated alarms -## -## Value: Integer -## -## Default: 1000 -alarm.size_limit = 1000 - -## Validity Period of deactivated alarms -## -## Value: Duration -## - h: hour -## - m: minute -## - s: second -## - ms: milliseconds -## -## Default: 24h -alarm.validity_period = 24h +## Value: File +plugins.loaded_file = {{ platform_data_dir }}/loaded_plugins {{ additional_configs }} diff --git a/etc/listeners.conf b/etc/listeners.conf new file mode 100644 index 000000000..2f2f1b5a1 --- /dev/null +++ b/etc/listeners.conf @@ -0,0 +1,928 @@ +##-------------------------------------------------------------------- +## Listeners +##-------------------------------------------------------------------- + +##-------------------------------------------------------------------- +## MQTT/TCP - External TCP Listener for MQTT Protocol + +## listener.tcp.$name is the IP address and port that the MQTT/TCP +## listener will bind. +## +## Value: IP:Port | Port +## +## Examples: 1883, 127.0.0.1:1883, ::1:1883 +listener.tcp.external = 0.0.0.0:1883 + +## The acceptor pool for external MQTT/TCP listener. +## +## Value: Number +listener.tcp.external.acceptors = 8 + +## Maximum number of concurrent MQTT/TCP connections. +## +## Value: Number +listener.tcp.external.max_connections = 1024000 + +## Maximum external connections per second. +## +## Value: Number +listener.tcp.external.max_conn_rate = 1000 + +## Specify the {active, N} option for the external MQTT/TCP Socket. +## +## Value: Number +listener.tcp.external.active_n = 100 + +## Zone of the external MQTT/TCP listener belonged to. +## +## See: zone.$name.* +## +## Value: String +listener.tcp.external.zone = external + +## The access control rules for the MQTT/TCP listener. +## +## See: https://github.com/emqtt/esockd#allowdeny +## +## Value: ACL Rule +## +## Example: allow 192.168.0.0/24 +listener.tcp.external.access.1 = allow all + +## Enable the Proxy Protocol V1/2 if the EMQ X cluster is deployed +## behind HAProxy or Nginx. +## +## See: https://www.haproxy.com/blog/haproxy/proxy-protocol/ +## +## Value: on | off +## listener.tcp.external.proxy_protocol = on + +## Sets the timeout for proxy protocol. EMQ X will close the TCP connection +## if no proxy protocol packet recevied within the timeout. +## +## Value: Duration +## listener.tcp.external.proxy_protocol_timeout = 3s + +## Enable the option for X.509 certificate based authentication. +## EMQX will use the common name of certificate as MQTT username. +## +## Value: cn | dn | crt +## listener.tcp.external.peer_cert_as_username = cn + +## The TCP backlog defines the maximum length that the queue of pending +## connections can grow to. +## +## Value: Number >= 0 +listener.tcp.external.backlog = 1024 + +## The TCP send timeout for external MQTT connections. +## +## Value: Duration +listener.tcp.external.send_timeout = 15s + +## Close the TCP connection if send timeout. +## +## Value: on | off +listener.tcp.external.send_timeout_close = on + +## The TCP receive buffer(os kernel) for MQTT connections. +## +## See: http://erlang.org/doc/man/inet.html +## +## Value: Bytes +## listener.tcp.external.recbuf = 2KB + +## The TCP send buffer(os kernel) for MQTT connections. +## +## See: http://erlang.org/doc/man/inet.html +## +## Value: Bytes +## listener.tcp.external.sndbuf = 2KB + +## The size of the user-level software buffer used by the driver. +## Not to be confused with options sndbuf and recbuf, which correspond +## to the Kernel socket buffers. It is recommended to have val(buffer) +## >= max(val(sndbuf),val(recbuf)) to avoid performance issues because +## of unnecessary copying. val(buffer) is automatically set to the above +## maximum when values sndbuf or recbuf are set. +## +## See: http://erlang.org/doc/man/inet.html +## +## Value: Bytes +## listener.tcp.external.buffer = 2KB + +## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. +## +## Value: on | off +## listener.tcp.external.tune_buffer = off + +## The TCP_NODELAY flag for MQTT connections. Small amounts of data are +## sent immediately if the option is enabled. +## +## Value: true | false +listener.tcp.external.nodelay = true + +## The SO_REUSEADDR flag for TCP listener. +## +## Value: true | false +listener.tcp.external.reuseaddr = true + +##-------------------------------------------------------------------- +## Internal TCP Listener for MQTT Protocol + +## The IP address and port that the internal MQTT/TCP protocol listener +## will bind. +## +## Value: IP:Port, Port +## +## Examples: 11883, 127.0.0.1:11883, ::1:11883 +listener.tcp.internal = 127.0.0.1:11883 + +## The acceptor pool for internal MQTT/TCP listener. +## +## Value: Number +listener.tcp.internal.acceptors = 4 + +## Maximum number of concurrent MQTT/TCP connections. +## +## Value: Number +listener.tcp.internal.max_connections = 1024000 + +## Maximum internal connections per second. +## +## Value: Number +listener.tcp.internal.max_conn_rate = 1000 + +## Specify the {active, N} option for the internal MQTT/TCP Socket. +## +## Value: Number +listener.tcp.internal.active_n = 1000 + +## Zone of the internal MQTT/TCP listener belonged to. +## +## Value: String +listener.tcp.internal.zone = internal + +## The TCP backlog of internal MQTT/TCP Listener. +## +## See: listener.tcp.$name.backlog +## +## Value: Number >= 0 +listener.tcp.internal.backlog = 512 + +## The TCP send timeout for internal MQTT connections. +## +## See: listener.tcp.$name.send_timeout +## +## Value: Duration +listener.tcp.internal.send_timeout = 5s + +## Close the MQTT/TCP connection if send timeout. +## +## See: listener.tcp.$name.send_timeout_close +## +## Value: on | off +listener.tcp.internal.send_timeout_close = on + +## The TCP receive buffer(os kernel) for internal MQTT connections. +## +## See: listener.tcp.$name.recbuf +## +## Value: Bytes +listener.tcp.internal.recbuf = 64KB + +## The TCP send buffer(os kernel) for internal MQTT connections. +## +## See: http://erlang.org/doc/man/inet.html +## +## Value: Bytes +listener.tcp.internal.sndbuf = 64KB + +## The size of the user-level software buffer used by the driver. +## +## See: listener.tcp.$name.buffer +## +## Value: Bytes +## listener.tcp.internal.buffer = 16KB + +## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. +## +## See: listener.tcp.$name.tune_buffer +## +## Value: on | off +## listener.tcp.internal.tune_buffer = off + +## The TCP_NODELAY flag for internal MQTT connections. +## +## See: listener.tcp.$name.nodelay +## +## Value: true | false +listener.tcp.internal.nodelay = false + +## The SO_REUSEADDR flag for MQTT/TCP Listener. +## +## Value: true | false +listener.tcp.internal.reuseaddr = true + +##-------------------------------------------------------------------- +## MQTT/SSL - External SSL Listener for MQTT Protocol + +## listener.ssl.$name is the IP address and port that the MQTT/SSL +## listener will bind. +## +## Value: IP:Port | Port +## +## Examples: 8883, 127.0.0.1:8883, ::1:8883 +listener.ssl.external = 8883 + +## The acceptor pool for external MQTT/SSL listener. +## +## Value: Number +listener.ssl.external.acceptors = 16 + +## Maximum number of concurrent MQTT/SSL connections. +## +## Value: Number +listener.ssl.external.max_connections = 102400 + +## Maximum MQTT/SSL connections per second. +## +## Value: Number +listener.ssl.external.max_conn_rate = 500 + +## Specify the {active, N} option for the internal MQTT/SSL Socket. +## +## Value: Number +listener.ssl.external.active_n = 100 + +## Zone of the external MQTT/SSL listener belonged to. +## +## Value: String +listener.ssl.external.zone = external + +## The access control rules for the MQTT/SSL listener. +## +## See: listener.tcp.$name.access +## +## Value: ACL Rule +listener.ssl.external.access.1 = allow all + +## Enable the Proxy Protocol V1/2 if the EMQ cluster is deployed behind +## HAProxy or Nginx. +## +## See: listener.tcp.$name.proxy_protocol +## +## Value: on | off +## listener.ssl.external.proxy_protocol = on + +## Sets the timeout for proxy protocol. +## +## See: listener.tcp.$name.proxy_protocol_timeout +## +## Value: Duration +## listener.ssl.external.proxy_protocol_timeout = 3s + +## TLS versions only to protect from POODLE attack. +## +## See: http://erlang.org/doc/man/ssl.html +## +## Value: String, seperated by ',' +## listener.ssl.external.tls_versions = tlsv1.2,tlsv1.1,tlsv1 + +## TLS Handshake timeout. +## +## Value: Duration +listener.ssl.external.handshake_timeout = 15s + +## Path to the file containing the user's private PEM-encoded key. +## +## See: http://erlang.org/doc/man/ssl.html +## +## Value: File +listener.ssl.external.keyfile = {{ platform_etc_dir }}/certs/key.pem + +## Path to a file containing the user certificate. +## +## See: http://erlang.org/doc/man/ssl.html +## +## Value: File +listener.ssl.external.certfile = {{ platform_etc_dir }}/certs/cert.pem + +## Path to the file containing PEM-encoded CA certificates. The CA certificates +## are used during server authentication and when building the client certificate chain. +## +## Value: File +## listener.ssl.external.cacertfile = {{ platform_etc_dir }}/certs/cacert.pem + +## The Ephemeral Diffie-Helman key exchange is a very effective way of +## ensuring Forward Secrecy by exchanging a set of keys that never hit +## the wire. Since the DH key is effectively signed by the private key, +## it needs to be at least as strong as the private key. In addition, +## the default DH groups that most of the OpenSSL installations have +## are only a handful (since they are distributed with the OpenSSL +## package that has been built for the operating system it’s running on) +## and hence predictable (not to mention, 1024 bits only). +## In order to escape this situation, first we need to generate a fresh, +## strong DH group, store it in a file and then use the option above, +## to force our SSL application to use the new DH group. Fortunately, +## OpenSSL provides us with a tool to do that. Simply run: +## openssl dhparam -out dh-params.pem 2048 +## +## Value: File +## listener.ssl.external.dhfile = {{ platform_etc_dir }}/certs/dh-params.pem + +## A server only does x509-path validation in mode verify_peer, +## as it then sends a certificate request to the client (this +## message is not sent if the verify option is verify_none). +## You can then also want to specify option fail_if_no_peer_cert. +## More information at: http://erlang.org/doc/man/ssl.html +## +## Value: verify_peer | verify_none +## listener.ssl.external.verify = verify_peer + +## Used together with {verify, verify_peer} by an SSL server. If set to true, +## the server fails if the client does not have a certificate to send, that is, +## sends an empty certificate. +## +## Value: true | false +## listener.ssl.external.fail_if_no_peer_cert = true + +## This is the single most important configuration option of an Erlang SSL +## application. Ciphers (and their ordering) define the way the client and +## server encrypt information over the wire, from the initial Diffie-Helman +## key exchange, the session key encryption ## algorithm and the message +## digest algorithm. Selecting a good cipher suite is critical for the +## application’s data security, confidentiality and performance. +## +## The cipher list above offers: +## +## A good balance between compatibility with older browsers. +## It can get stricter for Machine-To-Machine scenarios. +## Perfect Forward Secrecy. +## No old/insecure encryption and HMAC algorithms +## +## Most of it was copied from Mozilla’s Server Side TLS article +## +## Value: Ciphers +listener.ssl.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA + +## Ciphers for TLS PSK. +## Note that 'listener.ssl.external.ciphers' and 'listener.ssl.external.psk_ciphers' cannot +## be configured at the same time. +## See 'https://tools.ietf.org/html/rfc4279#section-2'. +#listener.ssl.external.psk_ciphers = PSK-AES128-CBC-SHA,PSK-AES256-CBC-SHA,PSK-3DES-EDE-CBC-SHA,PSK-RC4-SHA + +## SSL parameter renegotiation is a feature that allows a client and a server +## to renegotiate the parameters of the SSL connection on the fly. +## RFC 5746 defines a more secure way of doing this. By enabling secure renegotiation, +## you drop support for the insecure renegotiation, prone to MitM attacks. +## +## Value: on | off +## listener.ssl.external.secure_renegotiate = off + +## A performance optimization setting, it allows clients to reuse +## pre-existing sessions, instead of initializing new ones. +## Read more about it here. +## +## See: http://erlang.org/doc/man/ssl.html +## +## Value: on | off +## listener.ssl.external.reuse_sessions = on + +## An important security setting, it forces the cipher to be set based +## on the server-specified order instead of the client-specified order, +## hence enforcing the (usually more properly configured) security +## ordering of the server administrator. +## +## Value: on | off +## listener.ssl.external.honor_cipher_order = on + +## Use the CN, DN or CRT field from the client certificate as a username. +## Notice that 'verify' should be set as 'verify_peer'. +## +## Value: cn | dn | crt +## listener.ssl.external.peer_cert_as_username = cn + +## TCP backlog for the SSL connection. +## +## See listener.tcp.$name.backlog +## +## Value: Number >= 0 +## listener.ssl.external.backlog = 1024 + +## The TCP send timeout for the SSL connection. +## +## See listener.tcp.$name.send_timeout +## +## Value: Duration +## listener.ssl.external.send_timeout = 15s + +## Close the SSL connection if send timeout. +## +## See: listener.tcp.$name.send_timeout_close +## +## Value: on | off +## listener.ssl.external.send_timeout_close = on + +## The TCP receive buffer(os kernel) for the SSL connections. +## +## See: listener.tcp.$name.recbuf +## +## Value: Bytes +## listener.ssl.external.recbuf = 4KB + +## The TCP send buffer(os kernel) for internal MQTT connections. +## +## See: listener.tcp.$name.sndbuf +## +## Value: Bytes +## listener.ssl.external.sndbuf = 4KB + +## The size of the user-level software buffer used by the driver. +## +## See: listener.tcp.$name.buffer +## +## Value: Bytes +## listener.ssl.external.buffer = 4KB + +## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. +## +## See: listener.tcp.$name.tune_buffer +## +## Value: on | off +## listener.ssl.external.tune_buffer = off + +## The TCP_NODELAY flag for SSL connections. +## +## See: listener.tcp.$name.nodelay +## +## Value: true | false +## listener.ssl.external.nodelay = true + +## The SO_REUSEADDR flag for MQTT/SSL Listener. +## +## Value: true | false +listener.ssl.external.reuseaddr = true + +##-------------------------------------------------------------------- +## External WebSocket listener for MQTT protocol + +## listener.ws.$name is the IP address and port that the MQTT/WebSocket +## listener will bind. +## +## Value: IP:Port | Port +## +## Examples: 8083, 127.0.0.1:8083, ::1:8083 +listener.ws.external = 8083 + +## The path of WebSocket MQTT endpoint +## +## Value: URL Path +listener.ws.external.mqtt_path = /mqtt + +## The acceptor pool for external MQTT/WebSocket listener. +## +## Value: Number +listener.ws.external.acceptors = 4 + +## Maximum number of concurrent MQTT/WebSocket connections. +## +## Value: Number +listener.ws.external.max_connections = 102400 + +## Maximum MQTT/WebSocket connections per second. +## +## Value: Number +listener.ws.external.max_conn_rate = 1000 + +## Simulate the {active, N} option for the MQTT/WebSocket connections. +## +## Value: Number +listener.ws.external.active_n = 100 + +## Zone of the external MQTT/WebSocket listener belonged to. +## +## Value: String +listener.ws.external.zone = external + +## The access control for the MQTT/WebSocket listener. +## +## See: listener.ws.$name.access +## +## Value: ACL Rule +listener.ws.external.access.1 = allow all + +## Verify if the protocol header is valid. Turn off for WeChat MiniApp. +## +## Value: on | off +listener.ws.external.verify_protocol_header = on + +## Enable the Proxy Protocol V1/2 if the EMQ cluster is deployed behind +## HAProxy or Nginx. +## +## See: listener.ws.$name.proxy_protocol +## +## Value: on | off +## listener.ws.external.proxy_protocol = on + +## Sets the timeout for proxy protocol. +## +## See: listener.ws.$name.proxy_protocol_timeout +## +## Value: Duration +## listener.ws.external.proxy_protocol_timeout = 3s + +## The TCP backlog of external MQTT/WebSocket Listener. +## +## See: listener.ws.$name.backlog +## +## Value: Number >= 0 +listener.ws.external.backlog = 1024 + +## The TCP send timeout for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.send_timeout +## +## Value: Duration +listener.ws.external.send_timeout = 15s + +## Close the MQTT/WebSocket connection if send timeout. +## +## See: listener.ws.$name.send_timeout_close +## +## Value: on | off +listener.ws.external.send_timeout_close = on + +## The TCP receive buffer(os kernel) for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.recbuf +## +## Value: Bytes +## listener.ws.external.recbuf = 2KB + +## The TCP send buffer(os kernel) for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.sndbuf +## +## Value: Bytes +## listener.ws.external.sndbuf = 2KB + +## The size of the user-level software buffer used by the driver. +## +## See: listener.ws.$name.buffer +## +## Value: Bytes +## listener.ws.external.buffer = 2KB + +## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. +## +## See: listener.ws.$name.tune_buffer +## +## Value: on | off +## listener.ws.external.tune_buffer = off + +## The TCP_NODELAY flag for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.nodelay +## +## Value: true | false +listener.ws.external.nodelay = true + +## The compress flag for external MQTT/WebSocket connections. +## +## If this Value is set true,the websocket message would be compressed +## +## Value: true | false +## listener.ws.external.compress = true + +## The level of deflate options for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.level +## +## Value: none | default | best_compression | best_speed +## listener.ws.external.deflate_opts.level = default + +## The mem_level of deflate options for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.mem_level +## +## Valid range is 1-9 +## listener.ws.external.deflate_opts.mem_level = 8 + +## The strategy of deflate options for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.strategy +## +## Value: default | filtered | huffman_only | rle +## listener.ws.external.deflate_opts.strategy = default + +## The deflate option for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.server_context_takeover +## +## Value: takeover | no_takeover +## listener.ws.external.deflate_opts.server_context_takeover = takeover + +## The deflate option for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.client_context_takeover +## +## Value: takeover | no_takeover +## listener.ws.external.deflate_opts.client_context_takeover = takeover + +## The deflate options for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.server_max_window_bits +## +## Valid range is 8-15 +## listener.ws.external.deflate_opts.server_max_window_bits = 15 + +## The deflate options for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.client_max_window_bits +## +## Valid range is 8-15 +## listener.ws.external.deflate_opts.client_max_window_bits = 15 + +## The idle timeout for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.idle_timeout +## +## Value: Duration +## listener.ws.external.idle_timeout = 60s + +## The max frame size for external MQTT/WebSocket connections. +## +## +## Value: Number +## listener.ws.external.max_frame_size = 0 + +## Whether a WebSocket message is allowed to contain multiple MQTT packets +## +## Value: single | multiple +listener.ws.external.mqtt_piggyback = multiple + +##-------------------------------------------------------------------- +## External WebSocket/SSL listener for MQTT Protocol + +## listener.wss.$name is the IP address and port that the MQTT/WebSocket/SSL +## listener will bind. +## +## Value: IP:Port | Port +## +## Examples: 8084, 127.0.0.1:8084, ::1:8084 +listener.wss.external = 8084 + +## The path of WebSocket MQTT endpoint +## +## Value: URL Path +listener.wss.external.mqtt_path = /mqtt + +## The acceptor pool for external MQTT/WebSocket/SSL listener. +## +## Value: Number +listener.wss.external.acceptors = 4 + +## Maximum number of concurrent MQTT/Webwocket/SSL connections. +## +## Value: Number +listener.wss.external.max_connections = 16 + +## Maximum MQTT/WebSocket/SSL connections per second. +## +## See: listener.tcp.$name.max_conn_rate +## +## Value: Number +listener.wss.external.max_conn_rate = 1000 + +## Simulate the {active, N} option for the MQTT/WebSocket/SSL connections. +## +## Value: Number +listener.wss.external.active_n = 100 + +## Zone of the external MQTT/WebSocket/SSL listener belonged to. +## +## Value: String +listener.wss.external.zone = external + +## The access control rules for the MQTT/WebSocket/SSL listener. +## +## See: listener.tcp.$name.access. +## +## Value: ACL Rule +listener.wss.external.access.1 = allow all + +## See: listener.ws.external.verify_protocol_header +## +## Value: on | off +listener.wss.external.verify_protocol_header = on + +## Enable the Proxy Protocol V1/2 support. +## +## See: listener.tcp.$name.proxy_protocol +## +## Value: on | off +## listener.wss.external.proxy_protocol = on + +## Sets the timeout for proxy protocol. +## +## See: listener.tcp.$name.proxy_protocol_timeout +## +## Value: Duration +## listener.wss.external.proxy_protocol_timeout = 3s + +## TLS versions only to protect from POODLE attack. +## +## See: listener.ssl.$name.tls_versions +## +## Value: String, seperated by ',' +## listener.wss.external.tls_versions = tlsv1.2,tlsv1.1,tlsv1 + +## Path to the file containing the user's private PEM-encoded key. +## +## See: listener.ssl.$name.keyfile +## +## Value: File +listener.wss.external.keyfile = {{ platform_etc_dir }}/certs/key.pem + +## Path to a file containing the user certificate. +## +## See: listener.ssl.$name.certfile +## +## Value: File +listener.wss.external.certfile = {{ platform_etc_dir }}/certs/cert.pem + +## Path to the file containing PEM-encoded CA certificates. +## +## See: listener.ssl.$name.cacert +## +## Value: File +## listener.wss.external.cacertfile = {{ platform_etc_dir }}/certs/cacert.pem + +## See: listener.ssl.$name.dhfile +## +## Value: File +## listener.ssl.external.dhfile = {{ platform_etc_dir }}/certs/dh-params.pem + +## See: listener.ssl.$name.vefify +## +## Value: vefify_peer | verify_none +## listener.wss.external.verify = verify_peer + +## See: listener.ssl.$name.fail_if_no_peer_cert +## +## Value: false | true +## listener.wss.external.fail_if_no_peer_cert = true + +## See: listener.ssl.$name.ciphers +## +## Value: Ciphers +listener.wss.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA + +## Ciphers for TLS PSK. +## Note that 'listener.wss.external.ciphers' and 'listener.wss.external.psk_ciphers' cannot +## be configured at the same time. +## See 'https://tools.ietf.org/html/rfc4279#section-2'. +## listener.wss.external.psk_ciphers = PSK-AES128-CBC-SHA,PSK-AES256-CBC-SHA,PSK-3DES-EDE-CBC-SHA,PSK-RC4-SHA + +## See: listener.ssl.$name.secure_renegotiate +## +## Value: on | off +## listener.wss.external.secure_renegotiate = off + +## See: listener.ssl.$name.reuse_sessions +## +## Value: on | off +## listener.wss.external.reuse_sessions = on + +## See: listener.ssl.$name.honor_cipher_order +## +## Value: on | off +## listener.wss.external.honor_cipher_order = on + +## See: listener.ssl.$name.peer_cert_as_username +## +## Value: cn | dn | crt +## listener.wss.external.peer_cert_as_username = cn + +## TCP backlog for the WebSocket/SSL connection. +## +## See: listener.tcp.$name.backlog +## +## Value: Number >= 0 +listener.wss.external.backlog = 1024 + +## The TCP send timeout for the WebSocket/SSL connection. +## +## See: listener.tcp.$name.send_timeout +## +## Value: Duration +listener.wss.external.send_timeout = 15s + +## Close the WebSocket/SSL connection if send timeout. +## +## See: listener.tcp.$name.send_timeout_close +## +## Value: on | off +listener.wss.external.send_timeout_close = on + +## The TCP receive buffer(os kernel) for the WebSocket/SSL connections. +## +## See: listener.tcp.$name.recbuf +## +## Value: Bytes +## listener.wss.external.recbuf = 4KB + +## The TCP send buffer(os kernel) for the WebSocket/SSL connections. +## +## See: listener.tcp.$name.sndbuf +## +## Value: Bytes +## listener.wss.external.sndbuf = 4KB + +## The size of the user-level software buffer used by the driver. +## +## See: listener.tcp.$name.buffer +## +## Value: Bytes +## listener.wss.external.buffer = 4KB + +## The TCP_NODELAY flag for WebSocket/SSL connections. +## +## See: listener.tcp.$name.nodelay +## +## Value: true | false +## listener.wss.external.nodelay = true + +## The compress flag for external WebSocket/SSL connections. +## +## If this Value is set true,the websocket message would be compressed +## +## Value: true | false +## listener.wss.external.compress = true + +## The level of deflate options for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.level +## +## Value: none | default | best_compression | best_speed +## listener.wss.external.deflate_opts.level = default + +## The mem_level of deflate options for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.mem_level +## +## Valid range is 1-9 +## listener.wss.external.deflate_opts.mem_level = 8 + +## The strategy of deflate options for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.strategy +## +## Value: default | filtered | huffman_only | rle +## listener.wss.external.deflate_opts.strategy = default + +## The deflate option for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.server_context_takeover +## +## Value: takeover | no_takeover +## listener.wss.external.deflate_opts.server_context_takeover = takeover + +## The deflate option for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.client_context_takeover +## +## Value: takeover | no_takeover +## listener.wss.external.deflate_opts.client_context_takeover = takeover + +## The deflate options for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.server_max_window_bits +## +## Valid range is 8-15 +## listener.wss.external.deflate_opts.server_max_window_bits = 15 + +## The deflate options for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.client_max_window_bits +## +## Valid range is 8-15 +## listener.wss.external.deflate_opts.client_max_window_bits = 15 + +## The idle timeout for external WebSocket/SSL connections. +## +## See: listener.wss.$name.idle_timeout +## +## Value: Duration +## listener.wss.external.idle_timeout = 60s + +## The max frame size for external WebSocket/SSL connections. +## +## Value: Number +## listener.wss.external.max_frame_size = 0 + +## Whether a WebSocket message is allowed to contain multiple MQTT packets +## +## Value: single | multiple +listener.wss.external.mqtt_piggyback = multiple \ No newline at end of file diff --git a/etc/logger.conf b/etc/logger.conf new file mode 100644 index 000000000..4fd0faf5f --- /dev/null +++ b/etc/logger.conf @@ -0,0 +1,170 @@ +##-------------------------------------------------------------------- +## Log +##-------------------------------------------------------------------- + +## Where to emit the logs. +## Enable the console (standard output) logs. +## +## Value: off | file | console | both +## - off: disable logs entirely +## - file: write logs only to file +## - console: write logs only to standard I/O +## - both: write logs both to file and standard I/O +log.to = both + +## The log severity level. +## +## Value: debug | info | notice | warning | error | critical | alert | emergency +## +## Note: Only the messages with severity level higher than or equal to +## this level will be logged. +## +## Default: warning +log.level = warning + +## The dir for log files. +## +## Value: Folder +log.dir = {{ platform_log_dir }} + +## The log filename for logs of level specified in "log.level". +## +## If `log.rotation` is enabled, this is the base name of the +## files. Each file in a rotated log is named .N, where N is an integer. +## +## Value: String +## Default: emqx.log +log.file = emqx.log + +## Limits the total number of characters printed for each log event. +## +## Value: Integer +## Default: No Limit +#log.chars_limit = 8192 + +## Enables the log rotation. +## With this enabled, new log files will be created when the current +## log file is full, max to `log.rotation.size` files will be created. +## +## Value: on | off +## Default: on +log.rotation = on + +## Maximum size of each log file. +## +## Value: Number +## Default: 10M +## Supported Unit: KB | MB | GB +log.rotation.size = 10MB + +## Maximum rotation count of log files. +## +## Value: Number +## Default: 5 +log.rotation.count = 5 + +## To create additional log files for specific log levels. +## +## Value: File Name +## Format: log.$level.file = $filename, +## where "$level" can be one of: debug, info, notice, warning, +## error, critical, alert, emergency +## Note: Log files for a specific log level will only contain all the logs +## that higher than or equal to that level +## +#log.info.file = info.log +#log.error.file = error.log + +## The max allowed queue length before switching to sync mode. +## +## Log overload protection parameter. If the message queue grows +## larger than this value the handler switches from anync to sync mode. +## +## Default: 100 +## +#log.sync_mode_qlen = 100 + +## The max allowed queue length before switching to drop mode. +## +## Log overload protection parameter. When the message queue grows +## larger than this threshold, the handler switches to a mode in which +## it drops all new events that senders want to log. +## +## Default: 3000 +## +#log.drop_mode_qlen = 3000 + +## The max allowed queue length before switching to flush mode. +## +## Log overload protection parameter. If the length of the message queue +## grows larger than this threshold, a flush (delete) operation takes place. +## To flush events, the handler discards the messages in the message queue +## by receiving them in a loop without logging. +## +## Default: 8000 +## +#log.flush_qlen = 8000 + +## Kill the log handler when it gets overloaded. +## +## Log overload protection parameter. It is possible that a handler, +## even if it can successfully manage peaks of high load without crashing, +## can build up a large message queue, or use a large amount of memory. +## We could kill the log handler in these cases and restart it after a +## few seconds. +## +## Default: on +## +#log.overload_kill = on + +## The max allowed queue length before killing the log hanlder. +## +## Log overload protection parameter. This is the maximum allowed queue +## length. If the message queue grows larger than this, the handler +## process is terminated. +## +## Default: 20000 +## +#log.overload_kill_qlen = 20000 + +## The max allowed memory size before killing the log hanlder. +## +## Log overload protection parameter. This is the maximum memory size +## that the handler process is allowed to use. If the handler grows +## larger than this, the process is terminated. +## +## Default: 30MB +## +#log.overload_kill_mem_size = 30MB + +## Restart the log hanlder after some seconds. +## +## Log overload protection parameter. If the handler is terminated, +## it restarts automatically after a delay specified in seconds. +## The value "infinity" prevents restarts. +## +## Default: 5s +## +#log.overload_kill_restart_after = 5s + +## Max burst count and time window for burst control. +## +## Log overload protection parameter. Large bursts of log events - many +## events received by the handler under a short period of time - can +## potentially cause problems. By specifying the maximum number of events +## to be handled within a certain time frame, the handler can avoid +## choking the log with massive amounts of printouts. +## +## This config controls the maximum number of events to handle within +## a time frame. After the limit is reached, successive events are +## dropped until the end of the time frame. +## +## Note that there would be no warning if any messages were +## dropped because of burst control. +## +## Comment this config out to disable the burst control feature. +## +## Value: MaxBurstCount,TimeWindow +## Default: disabled +## +#log.burst_limit = 20000, 1s \ No newline at end of file diff --git a/etc/rpc.conf b/etc/rpc.conf new file mode 100644 index 000000000..d86838e4f --- /dev/null +++ b/etc/rpc.conf @@ -0,0 +1,98 @@ +##-------------------------------------------------------------------- +## RPC +##-------------------------------------------------------------------- +## RPC Mode. +## +## Value: sync | async +rpc.mode = async + +## Max batch size of async RPC requests. +## +## Value: Integer +## Zero or negative value disables rpc batching. +## +## NOTE: RPC batch won't work when rpc.mode = sync +rpc.async_batch_size = 256 + +## RPC port discovery +## +## The strategy for discovering the RPC listening port of other nodes. +## +## Value: Enum +## - manual: discover ports by `tcp_server_port` and `tcp_client_port`. +## - stateless: discover ports in a stateless manner. +## If node name is `emqx@127.0.0.1`, where the `` is an integer, +## then the listening port will be `5370 + ` +## +## Defaults to `stateless`. +rpc.port_discovery = stateless + +## TCP server port for RPC. +## +## Only takes effect when `rpc.port_discovery` = `manual`. +## +## Value: Port [1024-65535] +#rpc.tcp_server_port = 5369 + +## TCP port for outgoing RPC connections. +## +## Only takes effect when `rpc.port_discovery` = `manual`. +## +## Value: Port [1024-65535] +#rpc.tcp_client_port = 5369 + +## Number of outgoing RPC connections. +## +## Value: Interger [1-256] +## Defaults to NumberOfCPUSchedulers / 2 +#rpc.tcp_client_num = 1 + +## RCP Client connect timeout. +## +## Value: Seconds +rpc.connect_timeout = 5s + +## TCP send timeout of RPC client and server. +## +## Value: Seconds +rpc.send_timeout = 5s + +## Authentication timeout +## +## Value: Seconds +rpc.authentication_timeout = 5s + +## Default receive timeout for call() functions +## +## Value: Seconds +rpc.call_receive_timeout = 15s + +## Socket idle keepalive. +## +## Value: Seconds +rpc.socket_keepalive_idle = 900s + +## TCP Keepalive probes interval. +## +## Value: Seconds +rpc.socket_keepalive_interval = 75s + +## Probes lost to close the connection +## +## Value: Integer +rpc.socket_keepalive_count = 9 + +## Size of TCP send buffer. +## +## Value: Bytes +rpc.socket_sndbuf = 1MB + +## Size of TCP receive buffer. +## +## Value: Seconds +rpc.socket_recbuf = 1MB + +## Size of user-level software socket buffer. +## +## Value: Seconds +rpc.socket_buffer = 1MB diff --git a/etc/sys_mon.conf b/etc/sys_mon.conf new file mode 100644 index 000000000..abd8baa04 --- /dev/null +++ b/etc/sys_mon.conf @@ -0,0 +1,148 @@ +##-------------------------------------------------------------------- +## System Monitor +##-------------------------------------------------------------------- + +## Enable Long GC monitoring. Disable if the value is 0. +## Notice: don't enable the monitor in production for: +## https://github.com/erlang/otp/blob/feb45017da36be78d4c5784d758ede619fa7bfd3/erts/emulator/beam/erl_gc.c#L421 +## +## Value: Duration +## - h: hour +## - m: minute +## - s: second +## - ms: milliseconds +## +## Examples: +## - 2h: 2 hours +## - 30m: 30 minutes +## - 0.1s: 0.1 seconds +## - 100ms : 100 milliseconds +## +## Default: 0ms +sysmon.long_gc = 0 + +## Enable Long Schedule(ms) monitoring. +## +## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 +## +## Value: Duration +## - h: hour +## - m: minute +## - s: second +## - ms: milliseconds +## +## Examples: +## - 2h: 2 hours +## - 30m: 30 minutes +## - 0.1s: 0.1 seconds +## - 100ms: 100 milliseconds +## +## Default: 0ms +sysmon.long_schedule = 240ms + +## Enable Large Heap monitoring. +## +## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 +## +## Value: bytes +## +## Default: 8M words. 32MB on 32-bit VM, 64MB on 64-bit VM. +sysmon.large_heap = 8MB + +## Enable Busy Port monitoring. +## +## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 +## +## Value: true | false +sysmon.busy_port = false + +## Enable Busy Dist Port monitoring. +## +## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 +## +## Value: true | false +sysmon.busy_dist_port = true + +## The time interval for the periodic cpu check +## +## Value: Duration +## -h: hour, e.g. '2h' for 2 hours +## -m: minute, e.g. '5m' for 5 minutes +## -s: second, e.g. '30s' for 30 seconds +## +## Default: 60s +os_mon.cpu_check_interval = 60s + +## The threshold, as percentage of system cpu, for how much system cpu can be used before the corresponding alarm is set. +## +## Default: 80% +os_mon.cpu_high_watermark = 80% + +## The threshold, as percentage of system cpu, for how much system cpu can be used before the corresponding alarm is clear. +## +## Default: 60% +os_mon.cpu_low_watermark = 60% + +## The time interval for the periodic memory check +## +## Value: Duration +## -h: hour, e.g. '2h' for 2 hours +## -m: minute, e.g. '5m' for 5 minutes +## -s: second, e.g. '30s' for 30 seconds +## +## Default: 60s +os_mon.mem_check_interval = 60s + +## The threshold, as percentage of system memory, for how much system memory can be allocated before the corresponding alarm is set. +## +## Default: 70% +os_mon.sysmem_high_watermark = 70% + +## The threshold, as percentage of system memory, for how much system memory can be allocated by one Erlang process before the corresponding alarm is set. +## +## Default: 5% +os_mon.procmem_high_watermark = 5% + +## The time interval for the periodic process limit check +## +## Value: Duration +## +## Default: 30s +vm_mon.check_interval = 30s + +## The threshold, as percentage of processes, for how many processes can simultaneously exist at the local node before the corresponding alarm is set. +## +## Default: 80% +vm_mon.process_high_watermark = 80% + +## The threshold, as percentage of processes, for how many processes can simultaneously exist at the local node before the corresponding alarm is clear. +## +## Default: 60% +vm_mon.process_low_watermark = 60% + +## Specifies the actions to take when an alarm is activated +## +## Value: String +## - log +## - publish +## +## Default: log,publish +alarm.actions = log,publish + +## The maximum number of deactivated alarms +## +## Value: Integer +## +## Default: 1000 +alarm.size_limit = 1000 + +## Validity Period of deactivated alarms +## +## Value: Duration +## - h: hour +## - m: minute +## - s: second +## - ms: milliseconds +## +## Default: 24h +alarm.validity_period = 24h \ No newline at end of file diff --git a/etc/zones.conf b/etc/zones.conf new file mode 100644 index 000000000..ea1e1807c --- /dev/null +++ b/etc/zones.conf @@ -0,0 +1,327 @@ +##-------------------------------------------------------------------- +## Zones +##-------------------------------------------------------------------- + +##-------------------------------------------------------------------- +## External Zone + +## Idle timeout of the external MQTT connections. +## +## Value: duration +zone.external.idle_timeout = 15s + +## Enable ACL check. +## +## Value: Flag +zone.external.enable_acl = on + +## Enable ban check. +## +## Value: Flag +zone.external.enable_ban = on + +## Enable per connection statistics. +## +## Value: on | off +zone.external.enable_stats = on + +## The action when acl check reject current operation +## +## Value: ignore | disconnect +## Default: ignore +zone.external.acl_deny_action = ignore + +## Force the MQTT connection process GC after this number of +## messages | bytes passed through. +## +## Numbers delimited by `|'. Zero or negative is to disable. +zone.external.force_gc_policy = 16000|16MB + +## Max message queue length and total heap size to force shutdown +## connection/session process. +## Message queue here is the Erlang process mailbox, but not the number +## of queued MQTT messages of QoS 1 and 2. +## +## Numbers delimited by `|'. Zero or negative is to disable. +zone.external.force_shutdown_policy = 10000|32MB + +## Maximum MQTT packet size allowed. +## +## Value: Bytes +## Default: 1MB +## zone.external.max_packet_size = 64KB + +## Maximum length of MQTT clientId allowed. +## +## Value: Number [23-65535] +## zone.external.max_clientid_len = 1024 + +## Maximum topic levels allowed. 0 means no limit. +## +## Value: Number +## zone.external.max_topic_levels = 7 + +## Maximum QoS allowed. +## +## Value: 0 | 1 | 2 +## zone.external.max_qos_allowed = 2 + +## Maximum Topic Alias, 0 means no limit. +## +## Value: 0-65535 +## zone.external.max_topic_alias = 65535 + +## Whether the Server supports retained messages. +## +## Value: boolean +## zone.external.retain_available = true + +## Whether the Server supports Wildcard Subscriptions +## +## Value: boolean +## zone.external.wildcard_subscription = false + +## Whether the Server supports Shared Subscriptions +## +## Value: boolean +## zone.external.shared_subscription = false + +## Server Keep Alive +## +## Value: Number +## zone.external.server_keepalive = 0 + +## The backoff for MQTT keepalive timeout. The broker will kick a connection out +## until 'Keepalive * backoff * 2' timeout. +## +## Value: Float > 0.5 +zone.external.keepalive_backoff = 0.75 + +## Maximum number of subscriptions allowed, 0 means no limit. +## +## Value: Number +zone.external.max_subscriptions = 0 + +## Force to upgrade QoS according to subscription. +## +## Value: on | off +zone.external.upgrade_qos = off + +## Maximum size of the Inflight Window storing QoS1/2 messages delivered but unacked. +## +## Value: Number +zone.external.max_inflight = 32 + +## Retry interval for QoS1/2 message delivering. +## +## Value: Duration +zone.external.retry_interval = 30s + +## Maximum QoS2 packets (Client -> Broker) awaiting PUBREL, 0 means no limit. +## +## Value: Number +zone.external.max_awaiting_rel = 100 + +## The QoS2 messages (Client -> Broker) will be dropped if awaiting PUBREL timeout. +## +## Value: Duration +zone.external.await_rel_timeout = 300s + +## Default session expiry interval for MQTT V3.1.1 connections. +## +## Value: Duration +## -d: day +## -h: hour +## -m: minute +## -s: second +## +## Default: 2h, 2 hours +zone.external.session_expiry_interval = 2h + +## Maximum queue length. Enqueued messages when persistent client disconnected, +## or inflight window is full. 0 means no limit. +## +## Value: Number >= 0 +zone.external.max_mqueue_len = 1000 + +## Topic priorities. +## 'none' to indicate no priority table (by default), hence all messages +## are treated equal +## +## Priority number [1-255] +## Example: topic/1=10,topic/2=8 +## NOTE: comma and equal signs are not allowed for priority topic names +## NOTE: messages for topics not in the priority table are treated as +## either highest or lowest priority depending on the configured +## value for mqueue_default_priority +## +zone.external.mqueue_priorities = none + +## Default to highest priority for topics not matching priority table +## +## Value: highest | lowest +zone.external.mqueue_default_priority = highest + +## Whether to enqueue QoS0 messages. +## +## Value: false | true +zone.external.mqueue_store_qos0 = true + +## Whether to turn on flapping detect +## +## Value: on | off +zone.external.enable_flapping_detect = off + +## Message limit for the a external MQTT connection. +## +## Value: Number,Duration +## Example: 100 messages per 10 seconds. +#zone.external.rate_limit.conn_messages_in = 100,10s + +## Bytes limit for a external MQTT connections. +## +## Value: Number,Duration +## Example: 100KB incoming per 10 seconds. +#zone.external.rate_limit.conn_bytes_in = 100KB,10s + +## Messages quota for the each of external MQTT connection. +## This value consumed by the number of recipient on a message. +## +## Value: Number, Duration +## +## Example: 100 messaegs per 1s +#zone.external.quota.conn_messages_routing = 100,1s + +## Messages quota for the all of external MQTT connections. +## This value consumed by the number of recipient on a message. +## +## Value: Number, Duration +## +## Example: 200000 messaegs per 1s +#zone.external.quota.overall_messages_routing = 200000,1s + +## All the topics will be prefixed with the mountpoint path if this option is enabled. +## +## Variables in mountpoint path: +## - %c: clientid +## - %u: username +## +## Value: String +## zone.external.mountpoint = devicebound/ + +## Whether use username replace client id +## +## Value: boolean +## Default: false +zone.external.use_username_as_clientid = false + +## Whether to ignore loop delivery of messages.(for mqtt v3.1.1) +## +## Value: true | false +zone.external.ignore_loop_deliver = false + +## Whether to parse the MQTT frame in strict mode +## +## Value: true | false +zone.external.strict_mode = false + +## Specify the response information returned to the client +## +## Value: String +## zone.external.response_information = example + +##-------------------------------------------------------------------- +## Internal Zone + +zone.internal.allow_anonymous = true + +## Enable per connection stats. +## +## Value: Flag +zone.internal.enable_stats = on + +## Enable ACL check. +## +## Value: Flag +zone.internal.enable_acl = off + +## The action when acl check reject current operation +## +## Value: ignore | disconnect +## Default: ignore +zone.internal.acl_deny_action = ignore + +## See zone.$name.force_gc_policy +## zone.internal.force_gc_policy = 128000|128MB + +## See zone.$name.wildcard_subscription. +## +## Value: boolean +## zone.internal.wildcard_subscription = true + +## See zone.$name.shared_subscription. +## +## Value: boolean +## zone.internal.shared_subscription = true + +## See zone.$name.max_subscriptions. +## +## Value: Integer +zone.internal.max_subscriptions = 0 + +## See zone.$name.max_inflight +## +## Value: Number +zone.internal.max_inflight = 128 + +## See zone.$name.max_awaiting_rel +## +## Value: Number +zone.internal.max_awaiting_rel = 1000 + +## See zone.$name.max_mqueue_len +## +## Value: Number >= 0 +zone.internal.max_mqueue_len = 10000 + +## Whether to enqueue Qos0 messages. +## +## Value: false | true +zone.internal.mqueue_store_qos0 = true + +## Whether to turn on flapping detect +## +## Value: on | off +zone.internal.enable_flapping_detect = off + +## See zone.$name.force_shutdown_policy +zone.internal.force_shutdown_policy = 128000|128MB + +## All the topics will be prefixed with the mountpoint path if this option is enabled. +## +## Variables in mountpoint path: +## - %c: clientid +## - %u: username +## +## Value: String +## zone.internal.mountpoint = cloudbound/ + +## Whether to ignore loop delivery of messages.(for mqtt v3.1.1) +## +## Value: true | false +zone.internal.ignore_loop_deliver = false + +## Whether to parse the MQTT frame in strict mode +## +## Value: true | false +zone.internal.strict_mode = false + +## Specify the response information returned to the client +## +## Value: String +## zone.internal.response_information = example + +## Allow the zone's clients to bypass authentication step +## +## Value: true | false +zone.internal.bypass_auth_plugins = true diff --git a/priv/emqx.schema b/priv/emqx.schema index 7ca1f06ff..6f4e7012e 100644 --- a/priv/emqx.schema +++ b/priv/emqx.schema @@ -689,12 +689,6 @@ end}. {datatype, {enum, [allow, deny]}} ]}. -%% @doc Default ACL file. -{mapping, "acl_file", "emqx.acl_file", [ - {datatype, string}, - hidden -]}. - %% @doc Enable ACL cache for publish. {mapping, "enable_acl_cache", "emqx.enable_acl_cache", [ {default, on}, @@ -1026,6 +1020,7 @@ end}. %% of queued MQTT messages of QoS 1 and 2. %% Zero or negative is to disable. {mapping, "zone.$name.force_shutdown_policy", "emqx.zones", [ + {default, "default"}, {datatype, string} ]}. @@ -1082,6 +1077,17 @@ end}. count => list_to_integer(Count)} end, {force_gc_policy, GcPolicy}; + (["force_shutdown_policy"], "default") -> + {DefaultLen, DefaultSize} = + case WordSize = erlang:system_info(wordsize) of + 8 -> % arch_64 + {10000, cuttlefish_bytesize:parse("32MB")}; + 4 -> % arch_32 + {10000, cuttlefish_bytesize:parse("16MB")} + end, + {force_shutdown_policy, #{message_queue_len => DefaultLen, + max_heap_size => DefaultSize div WordSize + }}; (["force_shutdown_policy"], Val) -> [Len, Siz] = string:tokens(Val, "| "), MaxSiz = case WordSize = erlang:system_info(wordsize) of @@ -1551,6 +1557,10 @@ end}. hidden ]}. +{mapping, "listener.ws.$name.peer_cert_as_username", "emqx.listeners", [ + {datatype, {enum, [cn, dn, crt]}} +]}. + %%-------------------------------------------------------------------- %% MQTT/WebSocket/SSL Listeners @@ -1675,6 +1685,9 @@ end}. {mapping, "listener.wss.$name.cacertfile", "emqx.listeners", [ {datatype, string} ]}. +{mapping, "listener.wss.$name.dhfile", "emqx.listeners", [ + {datatype, string} +]}. {mapping, "listener.wss.$name.verify", "emqx.listeners", [ {datatype, atom} @@ -1915,93 +1928,6 @@ end}. ++ cuttlefish_variable:filter_by_prefix("listener.wss", Conf)]) end}. -%%-------------------------------------------------------------------- -%% Modules -%%-------------------------------------------------------------------- - -{mapping, "modules.loaded_file", "emqx.modules_loaded_file", [ - {datatype, string} -]}. - -{mapping, "module.presence.qos", "emqx.modules", [ - {default, 1}, - {datatype, integer}, - {validators, ["range:0-2"]} -]}. - -{mapping, "module.subscription.$id.topic", "emqx.modules", [ - {datatype, string} -]}. - -{mapping, "module.subscription.$id.qos", "emqx.modules", [ - {default, 1}, - {datatype, integer}, - {validators, ["range:0-2"]} -]}. - -{mapping, "module.subscription.$id.nl", "emqx.modules", [ - {default, 0}, - {datatype, integer}, - {validators, ["range:0-1"]} -]}. - -{mapping, "module.subscription.$id.rap", "emqx.modules", [ - {default, 0}, - {datatype, integer}, - {validators, ["range:0-1"]} -]}. - -{mapping, "module.subscription.$id.rh", "emqx.modules", [ - {default, 0}, - {datatype, integer}, - {validators, ["range:0-2"]} -]}. - -{mapping, "module.rewrite.rule.$id", "emqx.modules", [ - {datatype, string} -]}. - -{mapping, "module.rewrite.pub.rule.$id", "emqx.modules", [ - {datatype, string} -]}. - -{mapping, "module.rewrite.sub.rule.$id", "emqx.modules", [ - {datatype, string} -]}. - -{translation, "emqx.modules", fun(Conf, _, Conf1) -> - Subscriptions = fun() -> - List = cuttlefish_variable:filter_by_prefix("module.subscription", Conf), - TopicList = [{N, Topic}|| {[_,"subscription",N,"topic"], Topic} <- List], - [{iolist_to_binary(T), #{ qos => cuttlefish:conf_get("module.subscription." ++ N ++ ".qos", Conf, 0), - nl => cuttlefish:conf_get("module.subscription." ++ N ++ ".nl", Conf, 0), - rap => cuttlefish:conf_get("module.subscription." ++ N ++ ".rap", Conf, 0), - rh => cuttlefish:conf_get("module.subscription." ++ N ++ ".rh", Conf, 0) - }} || {N, T} <- TopicList] - end, - Rewrites = fun() -> - Rules = cuttlefish_variable:filter_by_prefix("module.rewrite.rule", Conf), - PubRules = cuttlefish_variable:filter_by_prefix("module.rewrite.pub.rule", Conf), - SubRules = cuttlefish_variable:filter_by_prefix("module.rewrite.sub.rule", Conf), - TotalRules = lists:append( - [ {["module", "rewrite", "pub", "rule", I], Rule} || {["module", "rewrite", "rule", I], Rule} <- Rules] ++ PubRules, - [ {["module", "rewrite", "sub", "rule", I], Rule} || {["module", "rewrite", "rule", I], Rule} <- Rules] ++ SubRules - ), - lists:map(fun({[_, "rewrite", PubOrSub, "rule", I], Rule}) -> - [Topic, Re, Dest] = string:tokens(Rule, " "), - {rewrite, list_to_atom(PubOrSub), list_to_binary(Topic), list_to_binary(Re), list_to_binary(Dest)} - end, TotalRules) - end, - lists:append([ - [{emqx_mod_presence, [{qos, cuttlefish:conf_get("module.presence.qos", Conf, 1)}]}], - [{emqx_mod_subscription, Subscriptions()}], - [{emqx_mod_rewrite, Rewrites()}], - [{emqx_mod_topic_metrics, []}], - [{emqx_mod_delayed, []}], - [{emqx_mod_acl_internal, [{acl_file, cuttlefish:conf_get("acl_file", Conf1)}]}] - ]) -end}. - %%------------------------------------------------------------------- %% Plugins %%------------------------------------------------------------------- diff --git a/rebar.config b/rebar.config index 048a89e98..be7d01148 100644 --- a/rebar.config +++ b/rebar.config @@ -6,7 +6,7 @@ [{gproc, {git, "https://github.com/uwiger/gproc", {tag, "0.8.0"}}}, {jiffy, {git, "https://github.com/emqx/jiffy", {tag, "1.0.5"}}}, {cowboy, {git, "https://github.com/emqx/cowboy", {tag, "2.7.1"}}}, - {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.7.2"}}}, + {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.7.3"}}}, {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.7.4"}}}, {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.5.0"}}}, {cuttlefish, {git, "https://github.com/emqx/cuttlefish", {tag, "v3.0.0"}}} diff --git a/src/emqx_access_rule.erl b/src/emqx_access_rule.erl deleted file mode 100644 index 89943cdbd..000000000 --- a/src/emqx_access_rule.erl +++ /dev/null @@ -1,155 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_access_rule). - --include("emqx.hrl"). - -%% APIs --export([ match/3 - , compile/1 - ]). - --export_type([rule/0]). - --type(acl_result() :: allow | deny). - --type(who() :: all | binary() | - {client, binary()} | - {user, binary()} | - {ipaddr, esockd_cidr:cidr_string()}). - --type(access() :: subscribe | publish | pubsub). - --type(rule() :: {acl_result(), all} | - {acl_result(), who(), access(), list(emqx_topic:topic())}). - --define(ALLOW_DENY(A), ((A =:= allow) orelse (A =:= deny))). --define(PUBSUB(A), ((A =:= subscribe) orelse (A =:= publish) orelse (A =:= pubsub))). - -%% @doc Compile Access Rule. -compile({A, all}) when ?ALLOW_DENY(A) -> - {A, all}; - -compile({A, Who, Access, Topic}) when ?ALLOW_DENY(A), ?PUBSUB(Access), is_binary(Topic) -> - {A, compile(who, Who), Access, [compile(topic, Topic)]}; - -compile({A, Who, Access, TopicFilters}) when ?ALLOW_DENY(A), ?PUBSUB(Access) -> - {A, compile(who, Who), Access, [compile(topic, Topic) || Topic <- TopicFilters]}. - -compile(who, all) -> - all; -compile(who, {ipaddr, CIDR}) -> - {ipaddr, esockd_cidr:parse(CIDR, true)}; -compile(who, {client, all}) -> - {client, all}; -compile(who, {client, ClientId}) -> - {client, bin(ClientId)}; -compile(who, {user, all}) -> - {user, all}; -compile(who, {user, Username}) -> - {user, bin(Username)}; -compile(who, {'and', Conds}) when is_list(Conds) -> - {'and', [compile(who, Cond) || Cond <- Conds]}; -compile(who, {'or', Conds}) when is_list(Conds) -> - {'or', [compile(who, Cond) || Cond <- Conds]}; - -compile(topic, {eq, Topic}) -> - {eq, emqx_topic:words(bin(Topic))}; -compile(topic, Topic) -> - Words = emqx_topic:words(bin(Topic)), - case 'pattern?'(Words) of - true -> {pattern, Words}; - false -> Words - end. - -'pattern?'(Words) -> - lists:member(<<"%u">>, Words) - orelse lists:member(<<"%c">>, Words). - -bin(L) when is_list(L) -> - list_to_binary(L); -bin(B) when is_binary(B) -> - B. - -%% @doc Match access rule --spec(match(emqx_types:clientinfo(), emqx_types:topic(), rule()) - -> {matched, allow} | {matched, deny} | nomatch). -match(_ClientInfo, _Topic, {AllowDeny, all}) when ?ALLOW_DENY(AllowDeny) -> - {matched, AllowDeny}; -match(ClientInfo, Topic, {AllowDeny, Who, _PubSub, TopicFilters}) - when ?ALLOW_DENY(AllowDeny) -> - case match_who(ClientInfo, Who) - andalso match_topics(ClientInfo, Topic, TopicFilters) of - true -> {matched, AllowDeny}; - false -> nomatch - end. - -match_who(_ClientInfo, all) -> - true; -match_who(_ClientInfo, {user, all}) -> - true; -match_who(_ClientInfo, {client, all}) -> - true; -match_who(#{clientid := ClientId}, {client, ClientId}) -> - true; -match_who(#{username := Username}, {user, Username}) -> - true; -match_who(#{peerhost := undefined}, {ipaddr, _Tup}) -> - false; -match_who(#{peerhost := IP}, {ipaddr, CIDR}) -> - esockd_cidr:match(IP, CIDR); -match_who(ClientInfo, {'and', Conds}) when is_list(Conds) -> - lists:foldl(fun(Who, Allow) -> - match_who(ClientInfo, Who) andalso Allow - end, true, Conds); -match_who(ClientInfo, {'or', Conds}) when is_list(Conds) -> - lists:foldl(fun(Who, Allow) -> - match_who(ClientInfo, Who) orelse Allow - end, false, Conds); -match_who(_ClientInfo, _Who) -> - false. - -match_topics(_ClientInfo, _Topic, []) -> - false; -match_topics(ClientInfo, Topic, [{pattern, PatternFilter}|Filters]) -> - TopicFilter = feed_var(ClientInfo, PatternFilter), - match_topic(emqx_topic:words(Topic), TopicFilter) - orelse match_topics(ClientInfo, Topic, Filters); -match_topics(ClientInfo, Topic, [TopicFilter|Filters]) -> - match_topic(emqx_topic:words(Topic), TopicFilter) - orelse match_topics(ClientInfo, Topic, Filters). - -match_topic(Topic, {eq, TopicFilter}) -> - Topic == TopicFilter; -match_topic(Topic, TopicFilter) -> - emqx_topic:match(Topic, TopicFilter). - -feed_var(ClientInfo, Pattern) -> - feed_var(ClientInfo, Pattern, []). -feed_var(_ClientInfo, [], Acc) -> - lists:reverse(Acc); -feed_var(ClientInfo = #{clientid := undefined}, [<<"%c">>|Words], Acc) -> - feed_var(ClientInfo, Words, [<<"%c">>|Acc]); -feed_var(ClientInfo = #{clientid := ClientId}, [<<"%c">>|Words], Acc) -> - feed_var(ClientInfo, Words, [ClientId |Acc]); -feed_var(ClientInfo = #{username := undefined}, [<<"%u">>|Words], Acc) -> - feed_var(ClientInfo, Words, [<<"%u">>|Acc]); -feed_var(ClientInfo = #{username := Username}, [<<"%u">>|Words], Acc) -> - feed_var(ClientInfo, Words, [Username|Acc]); -feed_var(ClientInfo, [W|Words], Acc) -> - feed_var(ClientInfo, Words, [W|Acc]). - diff --git a/src/emqx_alarm.erl b/src/emqx_alarm.erl index 510de9a4c..37d6fe1e8 100644 --- a/src/emqx_alarm.erl +++ b/src/emqx_alarm.erl @@ -200,10 +200,10 @@ handle_call({deactivate_alarm, Name}, _From, State = #state{actions = Actions, ok end, Alarm = #deactivated_alarm{activate_at = ActivateAt, - name = Name, - details = Details, - message = Message, - deactivate_at = erlang:system_time(microsecond)}, + name = Name, + details = Details, + message = Message, + deactivate_at = erlang:system_time(microsecond)}, mnesia:dirty_delete(?ACTIVATED_ALARM, Name), mnesia:dirty_write(?DEACTIVATED_ALARM, Alarm), do_actions(deactivate, Alarm, Actions), diff --git a/src/emqx_app.erl b/src/emqx_app.erl index 689a1b69e..881a1ee99 100644 --- a/src/emqx_app.erl +++ b/src/emqx_app.erl @@ -32,12 +32,11 @@ start(_Type, _Args) -> print_banner(), ekka:start(), {ok, Sup} = emqx_sup:start_link(), - ok = emqx_modules:load(), - ok = emqx_plugins:init(), - emqx_plugins:load(), + start_autocluster(), emqx_boot:is_enabled(listeners) andalso (ok = emqx_listeners:start()), - start_autocluster(), + ok = emqx_plugins:init(), + emqx_plugins:load(), register(emqx, self()), emqx_alarm_handler:load(), print_vsn(), @@ -47,8 +46,7 @@ start(_Type, _Args) -> stop(_State) -> emqx_alarm_handler:unload(), emqx_boot:is_enabled(listeners) - andalso emqx_listeners:stop(), - emqx_modules:unload(). + andalso emqx_listeners:stop(). %%-------------------------------------------------------------------- %% Print Banner diff --git a/src/emqx_channel.erl b/src/emqx_channel.erl index 2a3e35ccd..289ed50f0 100644 --- a/src/emqx_channel.erl +++ b/src/emqx_channel.erl @@ -648,17 +648,21 @@ maybe_update_expiry_interval(_Properties, Channel) -> Channel. -spec(handle_deliver(list(emqx_types:deliver()), channel()) -> {ok, channel()} | {ok, replies(), channel()}). handle_deliver(Delivers, Channel = #channel{conn_state = disconnected, - session = Session}) -> - NSession = emqx_session:enqueue(maybe_nack(Delivers), Session), + session = Session, + clientinfo = #{clientid := ClientId}}) -> + NSession = emqx_session:enqueue(ignore_local(maybe_nack(Delivers), ClientId, Session), Session), {ok, Channel#channel{session = NSession}}; handle_deliver(Delivers, Channel = #channel{takeover = true, - pendings = Pendings}) -> - NPendings = lists:append(Pendings, maybe_nack(Delivers)), + pendings = Pendings, + session = Session, + clientinfo = #{clientid := ClientId}}) -> + NPendings = lists:append(Pendings, ignore_local(maybe_nack(Delivers), ClientId, Session)), {ok, Channel#channel{pendings = NPendings}}; -handle_deliver(Delivers, Channel = #channel{session = Session}) -> - case emqx_session:deliver(Delivers, Session) of +handle_deliver(Delivers, Channel = #channel{session = Session, + clientinfo = #{clientid := ClientId}}) -> + case emqx_session:deliver(ignore_local(Delivers, ClientId, Session), Session) of {ok, Publishes, NSession} -> NChannel = Channel#channel{session = NSession}, handle_out(publish, Publishes, ensure_timer(retry_timer, NChannel)); @@ -666,6 +670,19 @@ handle_deliver(Delivers, Channel = #channel{session = Session}) -> {ok, Channel#channel{session = NSession}} end. +ignore_local(Delivers, Subscriber, Session) -> + Subs = emqx_session:info(subscriptions, Session), + lists:dropwhile(fun({deliver, Topic, #message{from = Publisher}}) -> + case maps:find(Topic, Subs) of + {ok, #{nl := 1}} when Subscriber =:= Publisher -> + ok = emqx_metrics:inc('delivery.dropped'), + ok = emqx_metrics:inc('delivery.dropped.no_local'), + true; + _ -> + false + end + end, Delivers). + %% Nack delivers from shared subscription maybe_nack(Delivers) -> lists:filter(fun not_nacked/1, Delivers). @@ -782,22 +799,15 @@ do_deliver({pubrel, PacketId}, Channel) -> do_deliver({PacketId, Msg}, Channel = #channel{clientinfo = ClientInfo = #{mountpoint := MountPoint}}) -> - case ignore_local(Msg, ClientInfo) of - true -> - ok = emqx_metrics:inc('delivery.dropped'), - ok = emqx_metrics:inc('delivery.dropped.no_local'), - {[], Channel}; - false -> - ok = emqx_metrics:inc('messages.delivered'), - Msg1 = emqx_hooks:run_fold('message.delivered', - [ClientInfo], - emqx_message:update_expiry(Msg) - ), - Msg2 = emqx_mountpoint:unmount(MountPoint, Msg1), - Packet = emqx_message:to_packet(PacketId, Msg2), - {NPacket, NChannel} = packing_alias(Packet, Channel), - {[NPacket], NChannel} - end; + ok = emqx_metrics:inc('messages.delivered'), + Msg1 = emqx_hooks:run_fold('message.delivered', + [ClientInfo], + emqx_message:update_expiry(Msg) + ), + Msg2 = emqx_mountpoint:unmount(MountPoint, Msg1), + Packet = emqx_message:to_packet(PacketId, Msg2), + {NPacket, NChannel} = packing_alias(Packet, Channel), + {[NPacket], NChannel}; do_deliver([Publish], Channel) -> do_deliver(Publish, Channel); @@ -810,11 +820,6 @@ do_deliver(Publishes, Channel) when is_list(Publishes) -> end, {[], Channel}, Publishes), {lists:reverse(Packets), NChannel}. -ignore_local(#message{flags = #{nl := true}, from = ClientId}, - #{clientid := ClientId}) -> - true; -ignore_local(_Msg, _ClientInfo) -> false. - %%-------------------------------------------------------------------- %% Handle out suback %%-------------------------------------------------------------------- diff --git a/src/emqx_cm_locker.erl b/src/emqx_cm_locker.erl index 708d3d23c..b5979c706 100644 --- a/src/emqx_cm_locker.erl +++ b/src/emqx_cm_locker.erl @@ -60,7 +60,7 @@ lock(ClientId, Piggyback) -> unlock(ClientId) -> ekka_locker:release(?MODULE, ClientId, strategy()). --spec(strategy() -> local | one | quorum | all). +-spec(strategy() -> local | leader | quorum | all). strategy() -> emqx:get_env(session_locking_strategy, quorum). diff --git a/src/emqx_gen_mod.erl b/src/emqx_gen_mod.erl deleted file mode 100644 index 26a3c13cb..000000000 --- a/src/emqx_gen_mod.erl +++ /dev/null @@ -1,23 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_gen_mod). - --callback(load(Opts :: any()) -> ok | {error, term()}). - --callback(unload(State :: term()) -> term()). - --callback(description() -> any()). diff --git a/src/emqx_mod_acl_internal.erl b/src/emqx_mod_acl_internal.erl deleted file mode 100644 index 7d5dd82c6..000000000 --- a/src/emqx_mod_acl_internal.erl +++ /dev/null @@ -1,122 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_acl_internal). - --behaviour(emqx_gen_mod). - --include("emqx.hrl"). --include("logger.hrl"). - --logger_header("[ACL_INTERNAL]"). - -%% APIs --export([ check_acl/5 - , rules_from_file/1 - ]). - -%% emqx_gen_mod callbacks --export([ load/1 - , unload/1 - , reload/1 - , description/0 - ]). - --type(acl_rules() :: #{publish => [emqx_access_rule:rule()], - subscribe => [emqx_access_rule:rule()]}). - -%%-------------------------------------------------------------------- -%% API -%%-------------------------------------------------------------------- - -load(Env) -> - Rules = rules_from_file(proplists:get_value(acl_file, Env)), - emqx_hooks:add('client.check_acl', {?MODULE, check_acl, [Rules]}, -1). - -unload(_Env) -> - emqx_hooks:del('client.check_acl', {?MODULE, check_acl}). - -reload(Env) -> - emqx_acl_cache:is_enabled() andalso ( - lists:foreach( - fun(Pid) -> erlang:send(Pid, clean_acl_cache) end, - emqx_cm:all_channels())), - unload(Env), load(Env). - -description() -> - "EMQ X Internal ACL Module". -%%-------------------------------------------------------------------- -%% ACL callbacks -%%-------------------------------------------------------------------- - -%% @doc Check ACL --spec(check_acl(emqx_types:clientinfo(), emqx_types:pubsub(), emqx_topic:topic(), - emqx_access_rule:acl_result(), acl_rules()) - -> {ok, allow} | {ok, deny} | ok). -check_acl(Client, PubSub, Topic, _AclResult, Rules) -> - case match(Client, Topic, lookup(PubSub, Rules)) of - {matched, allow} -> {ok, allow}; - {matched, deny} -> {ok, deny}; - nomatch -> ok - end. - -%%-------------------------------------------------------------------- -%% Internal Functions -%%-------------------------------------------------------------------- -lookup(PubSub, Rules) -> - maps:get(PubSub, Rules, []). - -match(_Client, _Topic, []) -> - nomatch; -match(Client, Topic, [Rule|Rules]) -> - case emqx_access_rule:match(Client, Topic, Rule) of - nomatch -> - match(Client, Topic, Rules); - {matched, AllowDeny} -> - {matched, AllowDeny} - end. - --spec(rules_from_file(file:filename()) -> map()). -rules_from_file(AclFile) -> - case file:consult(AclFile) of - {ok, Terms} -> - Rules = [emqx_access_rule:compile(Term) || Term <- Terms], - #{publish => [Rule || Rule <- Rules, filter(publish, Rule)], - subscribe => [Rule || Rule <- Rules, filter(subscribe, Rule)]}; - {error, eacces} -> - ?LOG(alert, "Insufficient permissions to read the ~s file", [AclFile]), - #{}; - {error, enoent} -> - ?LOG(alert, "The ~s file does not exist", [AclFile]), - #{}; - {error, Reason} -> - ?LOG(alert, "Failed to read ~s: ~p", [AclFile, Reason]), - #{} - end. - -filter(_PubSub, {allow, all}) -> - true; -filter(_PubSub, {deny, all}) -> - true; -filter(publish, {_AllowDeny, _Who, publish, _Topics}) -> - true; -filter(_PubSub, {_AllowDeny, _Who, pubsub, _Topics}) -> - true; -filter(subscribe, {_AllowDeny, _Who, subscribe, _Topics}) -> - true; -filter(_PubSub, {_AllowDeny, _Who, _, _Topics}) -> - false. - diff --git a/src/emqx_mod_delayed.erl b/src/emqx_mod_delayed.erl deleted file mode 100644 index 208da68ca..000000000 --- a/src/emqx_mod_delayed.erl +++ /dev/null @@ -1,204 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_delayed). - --behaviour(gen_server). --behaviour(emqx_gen_mod). - --include_lib("emqx/include/emqx.hrl"). --include_lib("emqx/include/logger.hrl"). - -%% Mnesia bootstrap --export([mnesia/1]). - --boot_mnesia({mnesia, [boot]}). --copy_mnesia({mnesia, [copy]}). - -%% emqx_gen_mod callbacks --export([ load/1 - , unload/1 - , description/0 - ]). - --export([ start_link/0 - , on_message_publish/1 - ]). - -%% gen_server callbacks --export([ init/1 - , handle_call/3 - , handle_cast/2 - , handle_info/2 - , terminate/2 - , code_change/3 - ]). - --record(delayed_message, - { key - , msg - }). - --define(TAB, ?MODULE). --define(SERVER, ?MODULE). --define(MAX_INTERVAL, 4294967). - -%%-------------------------------------------------------------------- -%% Mnesia bootstrap -%%-------------------------------------------------------------------- - -mnesia(boot) -> - ok = ekka_mnesia:create_table(?TAB, [ - {type, ordered_set}, - {disc_copies, [node()]}, - {local_content, true}, - {record_name, delayed_message}, - {attributes, record_info(fields, delayed_message)}]); -mnesia(copy) -> - ok = ekka_mnesia:copy_table(?TAB, disc_copies). - -%%-------------------------------------------------------------------- -%% Load/Unload -%%-------------------------------------------------------------------- - --spec(load(list()) -> ok). -load(_Env) -> - emqx_mod_sup:start_child(?MODULE, worker), - emqx:hook('message.publish', {?MODULE, on_message_publish, []}). - --spec(unload(list()) -> ok). -unload(_Env) -> - emqx:unhook('message.publish', {?MODULE, on_message_publish}), - emqx_mod_sup:stop_child(?MODULE). - -description() -> - "EMQ X Delayed Publish Module". -%%-------------------------------------------------------------------- -%% Hooks -%%-------------------------------------------------------------------- - -on_message_publish(Msg = #message{id = Id, topic = <<"$delayed/", Topic/binary>>, timestamp = Ts}) -> - [Delay, Topic1] = binary:split(Topic, <<"/">>), - PubAt = case binary_to_integer(Delay) of - Interval when Interval < ?MAX_INTERVAL -> - Interval + erlang:round(Ts / 1000); - Timestamp -> - %% Check malicious timestamp? - case (Timestamp - erlang:round(Ts / 1000)) > ?MAX_INTERVAL of - true -> error(invalid_delayed_timestamp); - false -> Timestamp - end - end, - PubMsg = Msg#message{topic = Topic1}, - Headers = PubMsg#message.headers, - ok = store(#delayed_message{key = {PubAt, Id}, msg = PubMsg}), - {stop, PubMsg#message{headers = Headers#{allow_publish => false}}}; - -on_message_publish(Msg) -> - {ok, Msg}. - -%%-------------------------------------------------------------------- -%% Start delayed publish server -%%-------------------------------------------------------------------- - --spec(start_link() -> emqx_types:startlink_ret()). -start_link() -> - gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). - --spec(store(#delayed_message{}) -> ok). -store(DelayedMsg) -> - gen_server:call(?SERVER, {store, DelayedMsg}, infinity). - -%%-------------------------------------------------------------------- -%% gen_server callback -%%-------------------------------------------------------------------- - -init([]) -> - {ok, ensure_publish_timer(#{timer => undefined, publish_at => 0})}. - -handle_call({store, DelayedMsg = #delayed_message{key = Key}}, _From, State) -> - ok = mnesia:dirty_write(?TAB, DelayedMsg), - emqx_metrics:set('messages.delayed', delayed_count()), - {reply, ok, ensure_publish_timer(Key, State)}; - -handle_call(Req, _From, State) -> - ?LOG(error, "[Delayed] Unexpected call: ~p", [Req]), - {reply, ignored, State}. - -handle_cast(Msg, State) -> - ?LOG(error, "[Delayed] Unexpected cast: ~p", [Msg]), - {noreply, State}. - -%% Do Publish... -handle_info({timeout, TRef, do_publish}, State = #{timer := TRef}) -> - DeletedKeys = do_publish(mnesia:dirty_first(?TAB), os:system_time(seconds)), - lists:foreach(fun(Key) -> mnesia:dirty_delete(?TAB, Key) end, DeletedKeys), - emqx_metrics:set('messages.delayed', delayed_count()), - {noreply, ensure_publish_timer(State#{timer := undefined, publish_at := 0})}; - -handle_info(Info, State) -> - ?LOG(error, "[Delayed] Unexpected info: ~p", [Info]), - {noreply, State}. - -terminate(_Reason, #{timer := TRef}) -> - emqx_misc:cancel_timer(TRef). - -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - -%%-------------------------------------------------------------------- -%% Internal functions -%%-------------------------------------------------------------------- - -%% Ensure publish timer -ensure_publish_timer(State) -> - ensure_publish_timer(mnesia:dirty_first(?TAB), State). - -ensure_publish_timer('$end_of_table', State) -> - State#{timer := undefined, publish_at := 0}; -ensure_publish_timer({Ts, _Id}, State = #{timer := undefined}) -> - ensure_publish_timer(Ts, os:system_time(seconds), State); -ensure_publish_timer({Ts, _Id}, State = #{timer := TRef, publish_at := PubAt}) - when Ts < PubAt -> - ok = emqx_misc:cancel_timer(TRef), - ensure_publish_timer(Ts, os:system_time(seconds), State); -ensure_publish_timer(_Key, State) -> - State. - -ensure_publish_timer(Ts, Now, State) -> - Interval = max(1, Ts - Now), - TRef = emqx_misc:start_timer(timer:seconds(Interval), do_publish), - State#{timer := TRef, publish_at := Now + Interval}. - -do_publish(Key, Now) -> - do_publish(Key, Now, []). - -%% Do publish -do_publish('$end_of_table', _Now, Acc) -> - Acc; -do_publish({Ts, _Id}, Now, Acc) when Ts > Now -> - Acc; -do_publish(Key = {Ts, _Id}, Now, Acc) when Ts =< Now -> - case mnesia:dirty_read(?TAB, Key) of - [] -> ok; - [#delayed_message{msg = Msg}] -> - emqx_pool:async_submit(fun emqx:publish/1, [Msg]) - end, - do_publish(mnesia:dirty_next(?TAB, Key), Now, [Key|Acc]). - --spec(delayed_count() -> non_neg_integer()). -delayed_count() -> mnesia:table_info(?TAB, size). - diff --git a/src/emqx_mod_presence.erl b/src/emqx_mod_presence.erl deleted file mode 100644 index f5aa2279e..000000000 --- a/src/emqx_mod_presence.erl +++ /dev/null @@ -1,130 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_presence). - --behaviour(emqx_gen_mod). - --include("emqx.hrl"). --include("logger.hrl"). - --logger_header("[Presence]"). - -%% emqx_gen_mod callbacks --export([ load/1 - , unload/1 - , description/0 - ]). - --export([ on_client_connected/3 - , on_client_disconnected/4 - ]). - --ifdef(TEST). --export([reason/1]). --endif. - -load(Env) -> - emqx_hooks:add('client.connected', {?MODULE, on_client_connected, [Env]}), - emqx_hooks:add('client.disconnected', {?MODULE, on_client_disconnected, [Env]}). - -unload(_Env) -> - emqx_hooks:del('client.connected', {?MODULE, on_client_connected}), - emqx_hooks:del('client.disconnected', {?MODULE, on_client_disconnected}). - -description() -> - "EMQ X Presence Module". -%%-------------------------------------------------------------------- -%% Callbacks -%%-------------------------------------------------------------------- - -on_client_connected(ClientInfo = #{clientid := ClientId}, ConnInfo, Env) -> - Presence = connected_presence(ClientInfo, ConnInfo), - case emqx_json:safe_encode(Presence) of - {ok, Payload} -> - emqx_broker:safe_publish( - make_msg(qos(Env), topic(connected, ClientId), Payload)); - {error, _Reason} -> - ?LOG(error, "Failed to encode 'connected' presence: ~p", [Presence]) - end. - -on_client_disconnected(_ClientInfo = #{clientid := ClientId, username := Username}, - Reason, _ConnInfo = #{disconnected_at := DisconnectedAt}, Env) -> - Presence = #{clientid => ClientId, - username => Username, - reason => reason(Reason), - disconnected_at => DisconnectedAt, - ts => erlang:system_time(millisecond) - }, - case emqx_json:safe_encode(Presence) of - {ok, Payload} -> - emqx_broker:safe_publish( - make_msg(qos(Env), topic(disconnected, ClientId), Payload)); - {error, _Reason} -> - ?LOG(error, "Failed to encode 'disconnected' presence: ~p", [Presence]) - end. - -%%-------------------------------------------------------------------- -%% Helper functions -%%-------------------------------------------------------------------- - -connected_presence(#{peerhost := PeerHost, - sockport := SockPort, - clientid := ClientId, - username := Username - }, - #{clean_start := CleanStart, - proto_name := ProtoName, - proto_ver := ProtoVer, - keepalive := Keepalive, - connected_at := ConnectedAt, - expiry_interval := ExpiryInterval - }) -> - #{clientid => ClientId, - username => Username, - ipaddress => ntoa(PeerHost), - sockport => SockPort, - proto_name => ProtoName, - proto_ver => ProtoVer, - keepalive => Keepalive, - connack => 0, %% Deprecated? - clean_start => CleanStart, - expiry_interval => ExpiryInterval, - connected_at => ConnectedAt, - ts => erlang:system_time(millisecond) - }. - -make_msg(QoS, Topic, Payload) -> - emqx_message:set_flag( - sys, emqx_message:make( - ?MODULE, QoS, Topic, iolist_to_binary(Payload))). - -topic(connected, ClientId) -> - emqx_topic:systop(iolist_to_binary(["clients/", ClientId, "/connected"])); -topic(disconnected, ClientId) -> - emqx_topic:systop(iolist_to_binary(["clients/", ClientId, "/disconnected"])). - -qos(Env) -> proplists:get_value(qos, Env, 0). - --compile({inline, [reason/1]}). -reason(Reason) when is_atom(Reason) -> Reason; -reason({shutdown, Reason}) when is_atom(Reason) -> Reason; -reason({Error, _}) when is_atom(Error) -> Error; -reason(_) -> internal_error. - --compile({inline, [ntoa/1]}). -ntoa(IpAddr) -> iolist_to_binary(inet:ntoa(IpAddr)). - diff --git a/src/emqx_mod_rewrite.erl b/src/emqx_mod_rewrite.erl deleted file mode 100644 index f5e343eed..000000000 --- a/src/emqx_mod_rewrite.erl +++ /dev/null @@ -1,103 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_rewrite). - --behaviour(emqx_gen_mod). - --include_lib("emqx.hrl"). --include_lib("emqx_mqtt.hrl"). - --ifdef(TEST). --export([ compile/1 - , match_and_rewrite/2 - ]). --endif. - -%% APIs --export([ rewrite_subscribe/4 - , rewrite_unsubscribe/4 - , rewrite_publish/2 - ]). - -%% emqx_gen_mod callbacks --export([ load/1 - , unload/1 - , description/0 - ]). - -%%-------------------------------------------------------------------- -%% Load/Unload -%%-------------------------------------------------------------------- - -load(RawRules) -> - {PubRules, SubRules} = compile(RawRules), - emqx_hooks:add('client.subscribe', {?MODULE, rewrite_subscribe, [SubRules]}), - emqx_hooks:add('client.unsubscribe', {?MODULE, rewrite_unsubscribe, [SubRules]}), - emqx_hooks:add('message.publish', {?MODULE, rewrite_publish, [PubRules]}). - -rewrite_subscribe(_ClientInfo, _Properties, TopicFilters, Rules) -> - {ok, [{match_and_rewrite(Topic, Rules), Opts} || {Topic, Opts} <- TopicFilters]}. - -rewrite_unsubscribe(_ClientInfo, _Properties, TopicFilters, Rules) -> - {ok, [{match_and_rewrite(Topic, Rules), Opts} || {Topic, Opts} <- TopicFilters]}. - -rewrite_publish(Message = #message{topic = Topic}, Rules) -> - {ok, Message#message{topic = match_and_rewrite(Topic, Rules)}}. - -unload(_) -> - emqx_hooks:del('client.subscribe', {?MODULE, rewrite_subscribe}), - emqx_hooks:del('client.unsubscribe', {?MODULE, rewrite_unsubscribe}), - emqx_hooks:del('message.publish', {?MODULE, rewrite_publish}). - -description() -> - "EMQ X Topic Rewrite Module". -%%-------------------------------------------------------------------- -%% Internal functions -%%-------------------------------------------------------------------- - -compile(Rules) -> - PubRules = [ begin - {ok, MP} = re:compile(Re), - {rewrite, Topic, MP, Dest} - end || {rewrite, pub, Topic, Re, Dest}<- Rules ], - SubRules = [ begin - {ok, MP} = re:compile(Re), - {rewrite, Topic, MP, Dest} - end || {rewrite, sub, Topic, Re, Dest}<- Rules ], - {PubRules, SubRules}. - -match_and_rewrite(Topic, []) -> - Topic; - -match_and_rewrite(Topic, [{rewrite, Filter, MP, Dest} | Rules]) -> - case emqx_topic:match(Topic, Filter) of - true -> rewrite(Topic, MP, Dest); - false -> match_and_rewrite(Topic, Rules) - end. - -rewrite(Topic, MP, Dest) -> - case re:run(Topic, MP, [{capture, all_but_first, list}]) of - {match, Captured} -> - Vars = lists:zip(["\\$" ++ integer_to_list(I) - || I <- lists:seq(1, length(Captured))], Captured), - iolist_to_binary(lists:foldl( - fun({Var, Val}, Acc) -> - re:replace(Acc, Var, Val, [global]) - end, Dest, Vars)); - nomatch -> Topic - end. - diff --git a/src/emqx_mod_subscription.erl b/src/emqx_mod_subscription.erl deleted file mode 100644 index b6d04528b..000000000 --- a/src/emqx_mod_subscription.erl +++ /dev/null @@ -1,65 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_subscription). - --behaviour(emqx_gen_mod). - --include_lib("emqx.hrl"). --include_lib("emqx_mqtt.hrl"). - -%% emqx_gen_mod callbacks --export([ load/1 - , unload/1 - , description/0 - ]). - -%% APIs --export([on_client_connected/3]). - -%%-------------------------------------------------------------------- -%% Load/Unload Hook -%%-------------------------------------------------------------------- - -load(Topics) -> - emqx_hooks:add('client.connected', {?MODULE, on_client_connected, [Topics]}). - -on_client_connected(#{clientid := ClientId, username := Username}, _ConnInfo = #{proto_ver := ProtoVer}, Topics) -> - Replace = fun(Topic) -> - rep(<<"%u">>, Username, rep(<<"%c">>, ClientId, Topic)) - end, - TopicFilters = case ProtoVer of - ?MQTT_PROTO_V5 -> [{Replace(Topic), SubOpts} || {Topic, SubOpts} <- Topics]; - _ -> [{Replace(Topic), #{qos => Qos}} || {Topic, #{qos := Qos}} <- Topics] - end, - self() ! {subscribe, TopicFilters}. - -unload(_) -> - emqx_hooks:del('client.connected', {?MODULE, on_client_connected}). - -description() -> - "EMQ X Subscription Module". -%%-------------------------------------------------------------------- -%% Internal functions -%%-------------------------------------------------------------------- - -rep(<<"%c">>, ClientId, Topic) -> - emqx_topic:feed_var(<<"%c">>, ClientId, Topic); -rep(<<"%u">>, undefined, Topic) -> - Topic; -rep(<<"%u">>, Username, Topic) -> - emqx_topic:feed_var(<<"%u">>, Username, Topic). - diff --git a/src/emqx_mod_sup.erl b/src/emqx_mod_sup.erl deleted file mode 100644 index b5512013c..000000000 --- a/src/emqx_mod_sup.erl +++ /dev/null @@ -1,63 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_sup). - --behaviour(supervisor). - --include("types.hrl"). - --export([ start_link/0 - , start_child/1 - , start_child/2 - , stop_child/1 - ]). - --export([init/1]). - -%% Helper macro for declaring children of supervisor --define(CHILD(Mod, Type), #{id => Mod, - start => {Mod, start_link, []}, - restart => permanent, - shutdown => 5000, - type => Type, - modules => [Mod]}). - --spec(start_link() -> startlink_ret()). -start_link() -> - supervisor:start_link({local, ?MODULE}, ?MODULE, []). - -start_child(ChildSpec) when is_map(ChildSpec) -> - supervisor:start_child(?MODULE, ChildSpec). - -start_child(Mod, Type) when is_atom(Mod) andalso is_atom(Type) -> - supervisor:start_child(?MODULE, ?CHILD(Mod, Type)). - --spec(stop_child(any()) -> ok | {error, term()}). -stop_child(ChildId) -> - case supervisor:terminate_child(?MODULE, ChildId) of - ok -> supervisor:delete_child(?MODULE, ChildId); - Error -> Error - end. - -%%-------------------------------------------------------------------- -%% Supervisor callbacks -%%-------------------------------------------------------------------- - -init([]) -> - ok = emqx_tables:new(emqx_modules, [set, public, {write_concurrency, true}]), - {ok, {{one_for_one, 10, 100}, []}}. - diff --git a/src/emqx_mod_topic_metrics.erl b/src/emqx_mod_topic_metrics.erl deleted file mode 100644 index 813d8d059..000000000 --- a/src/emqx_mod_topic_metrics.erl +++ /dev/null @@ -1,382 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_topic_metrics). - --behaviour(gen_server). --behaviour(emqx_gen_mod). - --include("emqx.hrl"). --include("logger.hrl"). --include("emqx_mqtt.hrl"). - --logger_header("[TOPIC_METRICS]"). - --export([ load/1 - , unload/1 - , description/0 - ]). - --export([ on_message_publish/1 - , on_message_delivered/2 - , on_message_dropped/3 - ]). - -%% API functions --export([ start_link/0 - , stop/0 - ]). - --export([ inc/2 - , inc/3 - , val/2 - , rate/2 - , metrics/1 - , register/1 - , unregister/1 - , unregister_all/0 - , is_registered/1 - , all_registered_topics/0 - ]). - -%% gen_server callbacks --export([ init/1 - , handle_call/3 - , handle_info/2 - , handle_cast/2 - , terminate/2 - ]). - --define(CRefID(Topic), {?MODULE, Topic}). - --define(MAX_TOPICS, 512). --define(TAB, ?MODULE). - --define(TOPIC_METRICS, - ['messages.in', - 'messages.out', - 'messages.qos0.in', - 'messages.qos0.out', - 'messages.qos1.in', - 'messages.qos1.out', - 'messages.qos2.in', - 'messages.qos2.out', - 'messages.dropped' - ]). - --define(TICKING_INTERVAL, 1). - --record(speed, { - last = 0 :: number(), - tick = 1 :: number(), - last_v = 0 :: number(), - acc = 0 :: number(), - samples = [] :: list() - }). - --record(state, { - speeds :: #{{binary(), atom()} => #speed{}} - }). - -%%------------------------------------------------------------------------------ -%% APIs -%%------------------------------------------------------------------------------ - -load(_Env) -> - emqx_mod_sup:start_child(?MODULE, worker), - emqx:hook('message.publish', {?MODULE, on_message_publish, []}), - emqx:hook('message.dropped', {?MODULE, on_message_dropped, []}), - emqx:hook('message.delivered', {?MODULE, on_message_delivered, []}). - -unload(_Env) -> - emqx:unhook('message.publish', {?MODULE, on_message_publish}), - emqx:unhook('message.dropped', {?MODULE, on_message_dropped}), - emqx:unhook('message.delivered', {?MODULE, on_message_delivered}), - emqx_mod_sup:stop_child(?MODULE). - -description() -> - "EMQ X Topic Metrics Module". - -on_message_publish(#message{topic = Topic, qos = QoS}) -> - case is_registered(Topic) of - true -> - inc(Topic, 'messages.in'), - case QoS of - ?QOS_0 -> inc(Topic, 'messages.qos0.in'); - ?QOS_1 -> inc(Topic, 'messages.qos1.in'); - ?QOS_2 -> inc(Topic, 'messages.qos2.in') - end; - false -> - ok - end. - -on_message_delivered(_, #message{topic = Topic, qos = QoS}) -> - case is_registered(Topic) of - true -> - inc(Topic, 'messages.out'), - case QoS of - ?QOS_0 -> inc(Topic, 'messages.qos0.out'); - ?QOS_1 -> inc(Topic, 'messages.qos1.out'); - ?QOS_2 -> inc(Topic, 'messages.qos2.out') - end; - false -> - ok - end. - -on_message_dropped(#message{topic = Topic}, _, _) -> - case is_registered(Topic) of - true -> - inc(Topic, 'messages.dropped'); - false -> - ok - end. - -start_link() -> - gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). - -stop() -> - gen_server:stop(?MODULE). - -inc(Topic, Metric) -> - inc(Topic, Metric, 1). - -inc(Topic, Metric, Val) -> - case get_counters(Topic) of - {error, topic_not_found} -> - {error, topic_not_found}; - CRef -> - case metric_idx(Metric) of - {error, invalid_metric} -> - {error, invalid_metric}; - Idx -> - counters:add(CRef, Idx, Val) - end - end. - -val(Topic, Metric) -> - case ets:lookup(?TAB, Topic) of - [] -> - {error, topic_not_found}; - [{Topic, CRef}] -> - case metric_idx(Metric) of - {error, invalid_metric} -> - {error, invalid_metric}; - Idx -> - counters:get(CRef, Idx) - end - end. - -rate(Topic, Metric) -> - gen_server:call(?MODULE, {get_rate, Topic, Metric}). - -metrics(Topic) -> - case ets:lookup(?TAB, Topic) of - [] -> - {error, topic_not_found}; - [{Topic, CRef}] -> - lists:foldl(fun(Metric, Acc) -> - [{to_count(Metric), counters:get(CRef, metric_idx(Metric))}, - {to_rate(Metric), rate(Topic, Metric)} | Acc] - end, [], ?TOPIC_METRICS) - end. - -register(Topic) when is_binary(Topic) -> - gen_server:call(?MODULE, {register, Topic}). - -unregister(Topic) when is_binary(Topic) -> - gen_server:call(?MODULE, {unregister, Topic}). - -unregister_all() -> - gen_server:call(?MODULE, {unregister, all}). - -is_registered(Topic) -> - ets:member(?TAB, Topic). - -all_registered_topics() -> - [Topic || {Topic, _CRef} <- ets:tab2list(?TAB)]. - -%%-------------------------------------------------------------------- -%% gen_server callbacks -%%-------------------------------------------------------------------- - -init([]) -> - erlang:process_flag(trap_exit, true), - ok = emqx_tables:new(?TAB, [{read_concurrency, true}]), - erlang:send_after(timer:seconds(?TICKING_INTERVAL), self(), ticking), - {ok, #state{speeds = #{}}, hibernate}. - -handle_call({register, Topic}, _From, State = #state{speeds = Speeds}) -> - case is_registered(Topic) of - true -> - {reply, {error, already_existed}, State}; - false -> - case number_of_registered_topics() < ?MAX_TOPICS of - true -> - CRef = counters:new(counters_size(), [write_concurrency]), - true = ets:insert(?TAB, {Topic, CRef}), - [counters:put(CRef, Idx, 0) || Idx <- lists:seq(1, counters_size())], - NSpeeds = lists:foldl(fun(Metric, Acc) -> - maps:put({Topic, Metric}, #speed{}, Acc) - end, Speeds, ?TOPIC_METRICS), - {reply, ok, State#state{speeds = NSpeeds}}; - false -> - {reply, {error, quota_exceeded}, State} - end - end; - -handle_call({unregister, all}, _From, State) -> - [delete_counters(Topic) || {Topic, _CRef} <- ets:tab2list(?TAB)], - {reply, ok, State#state{speeds = #{}}}; - -handle_call({unregister, Topic}, _From, State = #state{speeds = Speeds}) -> - case is_registered(Topic) of - false -> - {reply, ok, State}; - true -> - ok = delete_counters(Topic), - NSpeeds = lists:foldl(fun(Metric, Acc) -> - maps:remove({Topic, Metric}, Acc) - end, Speeds, ?TOPIC_METRICS), - {reply, ok, State#state{speeds = NSpeeds}} - end; - -handle_call({get_rate, Topic, Metric}, _From, State = #state{speeds = Speeds}) -> - case is_registered(Topic) of - false -> - {reply, {error, topic_not_found}, State}; - true -> - case maps:get({Topic, Metric}, Speeds, undefined) of - undefined -> - {reply, {error, invalid_metric}, State}; - #speed{last = Last} -> - {reply, Last, State} - end - end. - -handle_cast(Msg, State) -> - ?LOG(error, "Unexpected cast: ~p", [Msg]), - {noreply, State}. - -handle_info(ticking, State = #state{speeds = Speeds}) -> - NSpeeds = maps:map( - fun({Topic, Metric}, Speed) -> - case val(Topic, Metric) of - {error, topic_not_found} -> maps:remove({Topic, Metric}, Speeds); - Val -> calculate_speed(Val, Speed) - end - end, Speeds), - erlang:send_after(timer:seconds(5), self(), ticking), - {noreply, State#state{speeds = NSpeeds}}; - -handle_info(Info, State) -> - ?LOG(error, "Unexpected info: ~p", [Info]), - {noreply, State}. - -terminate(_Reason, _State) -> - ok. - -%%------------------------------------------------------------------------------ -%% Internal Functions -%%------------------------------------------------------------------------------ - -metric_idx('messages.in') -> 01; -metric_idx('messages.out') -> 02; -metric_idx('messages.qos0.in') -> 03; -metric_idx('messages.qos0.out') -> 04; -metric_idx('messages.qos1.in') -> 05; -metric_idx('messages.qos1.out') -> 06; -metric_idx('messages.qos2.in') -> 07; -metric_idx('messages.qos2.out') -> 08; -metric_idx('messages.dropped') -> 09; -metric_idx(_) -> - {error, invalid_metric}. - -to_count('messages.in') -> - 'messages.in.count'; -to_count('messages.out') -> - 'messages.out.count'; -to_count('messages.qos0.in') -> - 'messages.qos0.in.count'; -to_count('messages.qos0.out') -> - 'messages.qos0.out.count'; -to_count('messages.qos1.in') -> - 'messages.qos1.in.count'; -to_count('messages.qos1.out') -> - 'messages.qos1.out.count'; -to_count('messages.qos2.in') -> - 'messages.qos2.in.count'; -to_count('messages.qos2.out') -> - 'messages.qos2.out.count'; -to_count('messages.dropped') -> - 'messages.dropped.count'. - -to_rate('messages.in') -> - 'messages.in.rate'; -to_rate('messages.out') -> - 'messages.out.rate'; -to_rate('messages.qos0.in') -> - 'messages.qos0.in.rate'; -to_rate('messages.qos0.out') -> - 'messages.qos0.out.rate'; -to_rate('messages.qos1.in') -> - 'messages.qos1.in.rate'; -to_rate('messages.qos1.out') -> - 'messages.qos1.out.rate'; -to_rate('messages.qos2.in') -> - 'messages.qos2.in.rate'; -to_rate('messages.qos2.out') -> - 'messages.qos2.out.rate'; -to_rate('messages.dropped') -> - 'messages.dropped.rate'. - -delete_counters(Topic) -> - true = ets:delete(?TAB, Topic), - ok. - -get_counters(Topic) -> - case ets:lookup(?TAB, Topic) of - [] -> {error, topic_not_found}; - [{Topic, CRef}] -> CRef - end. - -counters_size() -> - length(?TOPIC_METRICS). - -number_of_registered_topics() -> - proplists:get_value(size, ets:info(?TAB)). - -calculate_speed(CurVal, #speed{last_v = LastVal, tick = Tick, acc = Acc, samples = Samples}) -> - %% calculate the current speed based on the last value of the counter - CurSpeed = (CurVal - LastVal) / ?TICKING_INTERVAL, - - %% calculate the average speed in last 5 seconds - case Tick =< 5 of - true -> - Acc1 = Acc + CurSpeed, - #speed{last = Acc1 / Tick, - last_v = CurVal, - acc = Acc1, - samples = Samples ++ [CurSpeed], - tick = Tick + 1}; - false -> - [FirstSpeed | Speeds] = Samples, - Acc1 = Acc + CurSpeed - FirstSpeed, - #speed{last = Acc1 / Tick, - last_v = CurVal, - acc = Acc1, - samples = Speeds ++ [CurSpeed], - tick = Tick} - end. diff --git a/src/emqx_modules.erl b/src/emqx_modules.erl deleted file mode 100644 index 55fb44001..000000000 --- a/src/emqx_modules.erl +++ /dev/null @@ -1,169 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_modules). - --include("logger.hrl"). - --logger_header("[Modules]"). - --export([ list/0 - , load/0 - , load/1 - , unload/0 - , unload/1 - , reload/1 - , find_module/1 - , load_module/2 - ]). - -%% @doc List all available plugins --spec(list() -> [{atom(), boolean()}]). -list() -> - ets:tab2list(?MODULE). - -%% @doc Load all the extended modules. --spec(load() -> ok). -load() -> - case emqx:get_env(modules_loaded_file) of - undefined -> ok; - File -> - load_modules(File) - end. - -load(ModuleName) -> - case find_module(ModuleName) of - [] -> - ?LOG(alert, "Module ~s not found, cannot load it", [ModuleName]), - {error, not_found}; - [{ModuleName, true}] -> - ?LOG(notice, "Module ~s is already started", [ModuleName]), - {error, already_started}; - [{ModuleName, false}] -> - emqx_modules:load_module(ModuleName, true) - end. - -%% @doc Unload all the extended modules. --spec(unload() -> ok). -unload() -> - case emqx:get_env(modules_loaded_file) of - undefined -> ignore; - File -> - unload_modules(File) - end. - -unload(ModuleName) -> - case find_module(ModuleName) of - [] -> - ?LOG(alert, "Module ~s not found, cannot load it", [ModuleName]), - {error, not_found}; - [{ModuleName, false}] -> - ?LOG(error, "Module ~s is not started", [ModuleName]), - {error, not_started}; - [{ModuleName, true}] -> - unload_module(ModuleName, true) - end. - -reload(emqx_mod_acl_internal) -> - Modules = emqx:get_env(modules, []), - Env = proplists:get_value(emqx_mod_acl_internal, Modules, undefined), - case emqx_mod_acl_internal:reload(Env) of - ok -> - ?LOG(info, "Reload ~s module successfully.", [emqx_mod_acl_internal]); - {error, Error} -> - ?LOG(error, "Reload module ~s failed, cannot start for ~0p", [emqx_mod_acl_internal, Error]) - end; -reload(_) -> - ignore. - -find_module(ModuleName) -> - ets:lookup(?MODULE, ModuleName). - -filter_module(ModuleNames) -> - filter_module(ModuleNames, emqx:get_env(modules, [])). -filter_module([], Acc) -> - Acc; -filter_module([{ModuleName, true} | ModuleNames], Acc) -> - filter_module(ModuleNames, lists:keydelete(ModuleName, 1, Acc)); -filter_module([{_, false} | ModuleNames], Acc) -> - filter_module(ModuleNames, Acc). - -load_modules(File) -> - case file:consult(File) of - {ok, ModuleNames} -> - lists:foreach(fun({ModuleName, _}) -> - ets:insert(?MODULE, {ModuleName, false}) - end, filter_module(ModuleNames)), - lists:foreach(fun load_module/1, ModuleNames); - {error, Error} -> - ?LOG(alert, "Failed to read: ~p, error: ~p", [File, Error]) - end. - -load_module({ModuleName, true}) -> - emqx_modules:load_module(ModuleName, false); -load_module({ModuleName, false}) -> - ets:insert(?MODULE, {ModuleName, false}); -load_module(ModuleName) -> - load_module({ModuleName, true}). - -load_module(ModuleName, Persistent) -> - Modules = emqx:get_env(modules, []), - Env = proplists:get_value(ModuleName, Modules, undefined), - case ModuleName:load(Env) of - ok -> - ets:insert(?MODULE, {ModuleName, true}), - write_loaded(Persistent), - ?LOG(info, "Load ~s module successfully.", [ModuleName]); - {error, Error} -> - ?LOG(error, "Load module ~s failed, cannot load for ~0p", [ModuleName, Error]), - {error, Error} - end. - -unload_modules(File) -> - case file:consult(File) of - {ok, ModuleNames} -> - lists:foreach(fun unload_module/1, ModuleNames); - {error, Error} -> - ?LOG(alert, "Failed to read: ~p, error: ~p", [File, Error]) - end. -unload_module({ModuleName, true}) -> - unload_module(ModuleName, false); -unload_module({ModuleName, false}) -> - ets:insert(?MODULE, {ModuleName, false}); -unload_module(ModuleName) -> - unload_module({ModuleName, true}). - -unload_module(ModuleName, Persistent) -> - Modules = emqx:get_env(modules, []), - Env = proplists:get_value(ModuleName, Modules, undefined), - case ModuleName:unload(Env) of - ok -> - ets:insert(?MODULE, {ModuleName, false}), - write_loaded(Persistent), - ?LOG(info, "Unload ~s module successfully.", [ModuleName]); - {error, Error} -> - ?LOG(error, "Unload module ~s failed, cannot unload for ~0p", [ModuleName, Error]) - end. - -write_loaded(true) -> - FilePath = emqx:get_env(modules_loaded_file), - case file:write_file(FilePath, [io_lib:format("~p.~n", [Name]) || Name <- list()]) of - ok -> ok; - {error, Error} -> - ?LOG(error, "Write File ~p Error: ~p", [FilePath, Error]), - {error, Error} - end; -write_loaded(false) -> ok. diff --git a/src/emqx_session.erl b/src/emqx_session.erl index 88664e028..e89943f2a 100644 --- a/src/emqx_session.erl +++ b/src/emqx_session.erl @@ -429,7 +429,7 @@ deliver(Delivers, Session) -> deliver([], Publishes, Session) -> {ok, lists:reverse(Publishes), Session}; -deliver([Msg|More], Acc, Session) -> +deliver([Msg | More], Acc, Session) -> case deliver_msg(Msg, Session) of {ok, Session1} -> deliver(More, Acc, Session1); diff --git a/src/emqx_sup.erl b/src/emqx_sup.erl index c0aa3a2a8..1782b64a0 100644 --- a/src/emqx_sup.erl +++ b/src/emqx_sup.erl @@ -67,12 +67,11 @@ init([]) -> BrokerSup = child_spec(emqx_broker_sup, supervisor), CMSup = child_spec(emqx_cm_sup, supervisor), SysSup = child_spec(emqx_sys_sup, supervisor), - ModSup = child_spec(emqx_mod_sup, supervisor), Childs = [KernelSup] ++ [RouterSup || emqx_boot:is_enabled(router)] ++ [BrokerSup || emqx_boot:is_enabled(broker)] ++ [CMSup || emqx_boot:is_enabled(broker)] ++ - [SysSup] ++ [ModSup], + [SysSup], SupFlags = #{strategy => one_for_all, intensity => 0, period => 1 diff --git a/src/emqx_types.erl b/src/emqx_types.erl index 9bc1d2e87..291e35538 100644 --- a/src/emqx_types.erl +++ b/src/emqx_types.erl @@ -121,6 +121,7 @@ conn_props := properties(), connected := boolean(), connected_at := non_neg_integer(), + disconnected_at => non_neg_integer(), keepalive := 0..16#FFFF, receive_maximum := non_neg_integer(), expiry_interval := non_neg_integer(), diff --git a/test/emqx_access_SUITE_data/acl_temp.conf b/test/emqx_access_SUITE_data/acl_temp.conf new file mode 100644 index 000000000..ca1d4381b --- /dev/null +++ b/test/emqx_access_SUITE_data/acl_temp.conf @@ -0,0 +1 @@ +{deny, {client, "batch_test"}, subscribe, ["t1", "t2", "t3"]}. diff --git a/test/emqx_access_rule_SUITE.erl b/test/emqx_access_rule_SUITE.erl deleted file mode 100644 index d99a1fd78..000000000 --- a/test/emqx_access_rule_SUITE.erl +++ /dev/null @@ -1,97 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_access_rule_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include_lib("eunit/include/eunit.hrl"). - -all() -> emqx_ct:all(?MODULE). - -init_per_suite(Config) -> - emqx_ct_helpers:boot_modules([router, broker]), - emqx_ct_helpers:start_apps([]), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -t_compile(_) -> - Rule1 = {allow, all, pubsub, <<"%u">>}, - Compile1 = {allow, all, pubsub, [{pattern,[<<"%u">>]}]}, - - Rule2 = {allow, {ipaddr, "127.0.0.1"}, pubsub, <<"%c">>}, - Compile2 = {allow, {ipaddr, {{127,0,0,1}, {127,0,0,1}, 32}}, pubsub, [{pattern,[<<"%c">>]}]}, - - Rule3 = {allow, {'and', [{client, <<"testClient">>}, {user, <<"testUser">>}]}, pubsub, [<<"testTopics1">>, <<"testTopics2">>]}, - Compile3 = {allow, {'and', [{client, <<"testClient">>}, {user, <<"testUser">>}]}, pubsub, [[<<"testTopics1">>], [<<"testTopics2">>]]}, - - Rule4 = {allow, {'or', [{client, all}, {user, all}]}, pubsub, [ <<"testTopics1">>, <<"testTopics2">>]}, - Compile4 = {allow, {'or', [{client, all}, {user, all}]}, pubsub, [[<<"testTopics1">>], [<<"testTopics2">>]]}, - - ?assertEqual(Compile1, emqx_access_rule:compile(Rule1)), - ?assertEqual(Compile2, emqx_access_rule:compile(Rule2)), - ?assertEqual(Compile3, emqx_access_rule:compile(Rule3)), - ?assertEqual(Compile4, emqx_access_rule:compile(Rule4)). - -t_match(_) -> - ClientInfo1 = #{zone => external, - clientid => <<"testClient">>, - username => <<"TestUser">>, - peerhost => {127,0,0,1} - }, - ClientInfo2 = #{zone => external, - clientid => <<"testClient">>, - username => <<"TestUser">>, - peerhost => {192,168,0,10} - }, - ClientInfo3 = #{zone => external, - clientid => <<"testClient">>, - username => <<"TestUser">>, - peerhost => undefined - }, - ?assertEqual({matched, deny}, emqx_access_rule:match([], [], {deny, all})), - ?assertEqual({matched, allow}, emqx_access_rule:match([], [], {allow, all})), - ?assertEqual(nomatch, emqx_access_rule:match(ClientInfo1, <<"Test/Topic">>, - emqx_access_rule:compile({allow, {user, all}, pubsub, []}))), - ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"Test/Topic">>, - emqx_access_rule:compile({allow, {client, all}, pubsub, ["$SYS/#", "#"]}))), - ?assertEqual(nomatch, emqx_access_rule:match(ClientInfo3, <<"Test/Topic">>, - emqx_access_rule:compile({allow, {ipaddr, "127.0.0.1"}, pubsub, ["$SYS/#", "#"]}))), - ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"Test/Topic">>, - emqx_access_rule:compile({allow, {ipaddr, "127.0.0.1"}, subscribe, ["$SYS/#", "#"]}))), - ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo2, <<"Test/Topic">>, - emqx_access_rule:compile({allow, {ipaddr, "192.168.0.1/24"}, subscribe, ["$SYS/#", "#"]}))), - ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"d/e/f/x">>, - emqx_access_rule:compile({allow, {user, "TestUser"}, subscribe, ["a/b/c", "d/e/f/#"]}))), - ?assertEqual(nomatch, emqx_access_rule:match(ClientInfo1, <<"d/e/f/x">>, - emqx_access_rule:compile({allow, {user, "admin"}, pubsub, ["d/e/f/#"]}))), - ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"testTopics/testClient">>, - emqx_access_rule:compile({allow, {client, "testClient"}, publish, ["testTopics/testClient"]}))), - ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"clients/testClient">>, - emqx_access_rule:compile({allow, all, pubsub, ["clients/%c"]}))), - ?assertEqual({matched, allow}, emqx_access_rule:match(#{username => <<"user2">>}, <<"users/user2/abc/def">>, - emqx_access_rule:compile({allow, all, subscribe, ["users/%u/#"]}))), - ?assertEqual({matched, deny}, emqx_access_rule:match(ClientInfo1, <<"d/e/f">>, - emqx_access_rule:compile({deny, all, subscribe, ["$SYS/#", "#"]}))), - ?assertEqual(nomatch, emqx_access_rule:match(ClientInfo1, <<"Topic">>, - emqx_access_rule:compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, <<"Topic">>}))), - ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"Topic">>, - emqx_access_rule:compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"TestUser">>}]}, publish, <<"Topic">>}))), - ?assertEqual({matched, allow}, emqx_access_rule:match(ClientInfo1, <<"Topic">>, - emqx_access_rule:compile({allow, {'or', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, ["Topic"]}))). diff --git a/test/emqx_acl_cache_SUITE.erl b/test/emqx_acl_cache_SUITE.erl index 6d314598c..2adbed03c 100644 --- a/test/emqx_acl_cache_SUITE.erl +++ b/test/emqx_acl_cache_SUITE.erl @@ -56,7 +56,7 @@ t_clean_acl_cache(_) -> emqtt:stop(Client). % optimize?? -t_reload_aclfile_and_cleanall(Config) -> +t_reload_aclfile_and_cleanall(_Config) -> RasieMsg = fun() -> Self = self(), #{puback => fun(Msg) -> Self ! {puback, Msg} end, disconnected => fun(_) -> ok end, @@ -78,27 +78,6 @@ t_reload_aclfile_and_cleanall(Config) -> %% Check acl cache list [ClientPid] = emqx_cm:lookup_channels(<<"emqx_c">>), ?assert(length(gen_server:call(ClientPid, list_acl_cache)) > 0), - - %% Update acl file and reload mod_acl_internal - Path = filename:join([testdir(proplists:get_value(data_dir, Config)), "acl2.conf"]), - ok = file:write_file(Path, <<"{deny, all}.">>), - OldPath = emqx:get_env(acl_file), - % application:set_env(emqx, acl_file, Path), - emqx_mod_acl_internal:reload([{acl_file, Path}]), - - ?assert(length(gen_server:call(ClientPid, list_acl_cache)) == 0), - {ok, PktId2} = emqtt:publish(Client, <<"t1">>, <<"{\"x\":1}">>, qos1), - - receive - {puback, #{packet_id := PktId2, reason_code := Rc2}} -> - %% Not authorized - ?assertEqual(16#87, Rc2); - _ -> - ?assert(false) - end, - application:set_env(emqx, acl_file, OldPath), - file:delete(Path), - emqx_mod_acl_internal:reload([{acl_file, OldPath}]), emqtt:stop(Client). %% @private diff --git a/test/emqx_acl_test_mod.erl b/test/emqx_acl_test_mod.erl deleted file mode 100644 index 5d36cce78..000000000 --- a/test/emqx_acl_test_mod.erl +++ /dev/null @@ -1,33 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_acl_test_mod). - -%% ACL callbacks --export([ init/1 - , check_acl/2 - , description/0 - ]). - -init(AclOpts) -> - {ok, AclOpts}. - -check_acl({_User, _PubSub, _Topic}, _State) -> - allow. - -description() -> - "Test ACL Mod". - diff --git a/test/emqx_channel_SUITE.erl b/test/emqx_channel_SUITE.erl index 3f282ba6a..c90c7510c 100644 --- a/test/emqx_channel_SUITE.erl +++ b/test/emqx_channel_SUITE.erl @@ -417,6 +417,14 @@ t_handle_deliver(_) -> {ok, {outgoing, Packets}, _Ch} = emqx_channel:handle_deliver(Delivers, channel()), ?assertEqual([?QOS_1, ?QOS_2], [emqx_packet:qos(Pkt)|| Pkt <- Packets]). +t_handle_deliver_nl(_) -> + ClientInfo = clientinfo(#{clientid => <<"clientid">>}), + Session = session(#{subscriptions => #{<<"t1">> => #{nl => 1}}}), + Channel = channel(#{clientinfo => ClientInfo, session => Session}), + Msg = emqx_message:make(<<"clientid">>, ?QOS_1, <<"t1">>, <<"qos1">>), + NMsg = emqx_message:set_flag(nl, Msg), + {ok, Channel} = emqx_channel:handle_deliver([{deliver, <<"t1">>, NMsg}], Channel). + %%-------------------------------------------------------------------- %% Test cases for handle_out %%-------------------------------------------------------------------- @@ -434,13 +442,6 @@ t_handle_out_publish_1(_) -> {ok, {outgoing, [?PUBLISH_PACKET(?QOS_1, <<"t">>, 1, <<"payload">>)]}, _Chan} = emqx_channel:handle_out(publish, [{1, Msg}], channel()). -t_handle_out_publish_nl(_) -> - ClientInfo = clientinfo(#{clientid => <<"clientid">>}), - Channel = channel(#{clientinfo => ClientInfo}), - Msg = emqx_message:make(<<"clientid">>, ?QOS_1, <<"t1">>, <<"qos1">>), - Pubs = [{1, emqx_message:set_flag(nl, Msg)}], - {ok, {outgoing,[]}, Channel} = emqx_channel:handle_out(publish, Pubs, Channel). - t_handle_out_connack_sucess(_) -> {ok, [{event, connected}, {connack, ?CONNACK_PACKET(?RC_SUCCESS, 0, _)}], Channel} = emqx_channel:handle_out(connack, {?RC_SUCCESS, 0, #{}}, channel()), diff --git a/test/emqx_mod_acl_internal_SUITE.erl b/test/emqx_mod_acl_internal_SUITE.erl deleted file mode 100644 index bd9a0bf5a..000000000 --- a/test/emqx_mod_acl_internal_SUITE.erl +++ /dev/null @@ -1,64 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_acl_internal_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include("emqx_mqtt.hrl"). --include_lib("eunit/include/eunit.hrl"). - -all() -> emqx_ct:all(?MODULE). - -init_per_suite(Config) -> - emqx_ct_helpers:boot_modules(all), - emqx_ct_helpers:start_apps([]), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -t_load_unload(_) -> - ?assertEqual(ok, emqx_mod_acl_internal:unload([])), - ?assertEqual(ok, emqx_mod_acl_internal:load([])), - ?assertEqual({error,already_exists}, emqx_mod_acl_internal:load([])). - -t_check_acl(_) -> - Rules=#{publish => [{allow,all}], subscribe => [{deny, all}]}, - ?assertEqual({ok, allow}, emqx_mod_acl_internal:check_acl(clientinfo(), publish, <<"t">>, [], Rules)), - ?assertEqual({ok, deny}, emqx_mod_acl_internal:check_acl(clientinfo(), subscribe, <<"t">>, [], Rules)), - ?assertEqual(ok, emqx_mod_acl_internal:check_acl(clientinfo(), connect, <<"t">>, [], Rules)). - -t_reload_acl(_) -> - ?assertEqual(ok, emqx_mod_acl_internal:reload([])). - -%%-------------------------------------------------------------------- -%% Helper functions -%%-------------------------------------------------------------------- - -clientinfo() -> clientinfo(#{}). -clientinfo(InitProps) -> - maps:merge(#{zone => zone, - protocol => mqtt, - peerhost => {127,0,0,1}, - clientid => <<"clientid">>, - username => <<"username">>, - password => <<"passwd">>, - is_superuser => false, - peercert => undefined, - mountpoint => undefined - }, InitProps). diff --git a/test/emqx_mod_delayed_SUITE.erl b/test/emqx_mod_delayed_SUITE.erl deleted file mode 100644 index 3759e8c4d..000000000 --- a/test/emqx_mod_delayed_SUITE.erl +++ /dev/null @@ -1,78 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_delayed_SUITE). - --import(emqx_mod_delayed, [on_message_publish/1]). - --compile(export_all). --compile(nowarn_export_all). - --record(delayed_message, {key, msg}). - --include_lib("common_test/include/ct.hrl"). --include_lib("eunit/include/eunit.hrl"). --include_lib("emqx/include/emqx.hrl"). - -%%-------------------------------------------------------------------- -%% Setups -%%-------------------------------------------------------------------- - -all() -> - emqx_ct:all(?MODULE). - -init_per_suite(Config) -> - emqx_ct_helpers:start_apps([], fun set_special_configs/1), - Config. - -end_per_suite(_) -> - emqx_ct_helpers:stop_apps([]). - -set_special_configs(emqx) -> - application:set_env(emqx, modules, [{emqx_mod_delayed, []}]), - application:set_env(emqx, allow_anonymous, false), - application:set_env(emqx, enable_acl_cache, false); -set_special_configs(_App) -> - ok. - -%%-------------------------------------------------------------------- -%% Test cases -%%-------------------------------------------------------------------- - -t_load_case(_) -> - UnHooks = emqx_hooks:lookup('message.publish'), - ?assertEqual([], UnHooks), - ok = emqx_mod_delayed:load([]), - Hooks = emqx_hooks:lookup('message.publish'), - ?assertEqual(1, length(Hooks)), - ok. - -t_delayed_message(_) -> - ok = emqx_mod_delayed:load([]), - DelayedMsg = emqx_message:make(?MODULE, 1, <<"$delayed/1/publish">>, <<"delayed_m">>), - ?assertEqual({stop, DelayedMsg#message{topic = <<"publish">>, headers = #{allow_publish => false}}}, on_message_publish(DelayedMsg)), - - Msg = emqx_message:make(?MODULE, 1, <<"no_delayed_msg">>, <<"no_delayed">>), - ?assertEqual({ok, Msg}, on_message_publish(Msg)), - - [Key] = mnesia:dirty_all_keys(emqx_mod_delayed), - [#delayed_message{msg = #message{payload = Payload}}] = mnesia:dirty_read({emqx_mod_delayed, Key}), - ?assertEqual(<<"delayed_m">>, Payload), - timer:sleep(5000), - - EmptyKey = mnesia:dirty_all_keys(emqx_mod_delayed), - ?assertEqual([], EmptyKey), - ok = emqx_mod_delayed:unload([]). diff --git a/test/emqx_mod_presence_SUITE.erl b/test/emqx_mod_presence_SUITE.erl deleted file mode 100644 index 49d5d206b..000000000 --- a/test/emqx_mod_presence_SUITE.erl +++ /dev/null @@ -1,88 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_presence_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include("emqx_mqtt.hrl"). --include_lib("eunit/include/eunit.hrl"). - -all() -> emqx_ct:all(?MODULE). - -init_per_suite(Config) -> - emqx_ct_helpers:boot_modules(all), - emqx_ct_helpers:start_apps([]), - %% Ensure all the modules unloaded. - ok = emqx_modules:unload(), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -%% Test case for emqx_mod_presence -t_mod_presence(_) -> - ok = emqx_mod_presence:load([{qos, ?QOS_1}]), - {ok, C1} = emqtt:start_link([{clientid, <<"monsys">>}]), - {ok, _} = emqtt:connect(C1), - {ok, _Props, [?QOS_1]} = emqtt:subscribe(C1, <<"$SYS/brokers/+/clients/#">>, qos1), - %% Connected Presence - {ok, C2} = emqtt:start_link([{clientid, <<"clientid">>}, - {username, <<"username">>}]), - {ok, _} = emqtt:connect(C2), - ok = recv_and_check_presence(<<"clientid">>, <<"connected">>), - %% Disconnected Presence - ok = emqtt:disconnect(C2), - ok = recv_and_check_presence(<<"clientid">>, <<"disconnected">>), - ok = emqtt:disconnect(C1), - ok = emqx_mod_presence:unload([{qos, ?QOS_1}]). - -t_mod_presence_reason(_) -> - ?assertEqual(normal, emqx_mod_presence:reason(normal)), - ?assertEqual(discarded, emqx_mod_presence:reason({shutdown, discarded})), - ?assertEqual(tcp_error, emqx_mod_presence:reason({tcp_error, einval})), - ?assertEqual(internal_error, emqx_mod_presence:reason(<<"unknown error">>)). - -recv_and_check_presence(ClientId, Presence) -> - {ok, #{qos := ?QOS_1, topic := Topic, payload := Payload}} = receive_publish(100), - ?assertMatch([<<"$SYS">>, <<"brokers">>, _Node, <<"clients">>, ClientId, Presence], - binary:split(Topic, <<"/">>, [global])), - case Presence of - <<"connected">> -> - ?assertMatch(#{<<"clientid">> := <<"clientid">>, - <<"username">> := <<"username">>, - <<"ipaddress">> := <<"127.0.0.1">>, - <<"proto_name">> := <<"MQTT">>, - <<"proto_ver">> := ?MQTT_PROTO_V4, - <<"connack">> := ?RC_SUCCESS, - <<"clean_start">> := true}, emqx_json:decode(Payload, [return_maps])); - <<"disconnected">> -> - ?assertMatch(#{<<"clientid">> := <<"clientid">>, - <<"username">> := <<"username">>, - <<"reason">> := <<"normal">>}, emqx_json:decode(Payload, [return_maps])) - end. - -%%-------------------------------------------------------------------- -%% Internal functions -%%-------------------------------------------------------------------- - -receive_publish(Timeout) -> - receive - {publish, Publish} -> {ok, Publish} - after - Timeout -> {error, timeout} - end. diff --git a/test/emqx_mod_rewrite_SUITE.erl b/test/emqx_mod_rewrite_SUITE.erl deleted file mode 100644 index e3c19200e..000000000 --- a/test/emqx_mod_rewrite_SUITE.erl +++ /dev/null @@ -1,93 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_rewrite_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include("emqx_mqtt.hrl"). --include_lib("eunit/include/eunit.hrl"). - --define(RULES, [{rewrite, pub, <<"x/#">>,<<"^x/y/(.+)$">>,<<"z/y/$1">>}, - {rewrite, sub, <<"y/+/z/#">>,<<"^y/(.+)/z/(.+)$">>,<<"y/z/$2">>} - ]). - -all() -> emqx_ct:all(?MODULE). - -init_per_suite(Config) -> - emqx_ct_helpers:boot_modules(all), - emqx_ct_helpers:start_apps([]), - %% Ensure all the modules unloaded. - ok = emqx_modules:unload(), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -%% Test case for emqx_mod_write -t_mod_rewrite(_Config) -> - ok = emqx_mod_rewrite:load(?RULES), - {ok, C} = emqtt:start_link([{clientid, <<"rewrite_client">>}]), - {ok, _} = emqtt:connect(C), - PubOrigTopics = [<<"x/y/2">>, <<"x/1/2">>], - PubDestTopics = [<<"z/y/2">>, <<"x/1/2">>], - SubOrigTopics = [<<"y/a/z/b">>, <<"y/def">>], - SubDestTopics = [<<"y/z/b">>, <<"y/def">>], - %% Sub Rules - {ok, _Props, _} = emqtt:subscribe(C, [{Topic, ?QOS_1} || Topic <- SubOrigTopics]), - timer:sleep(100), - Subscriptions = emqx_broker:subscriptions(<<"rewrite_client">>), - ?assertEqual(SubDestTopics, [Topic || {Topic, _SubOpts} <- Subscriptions]), - RecvTopics1 = [begin - ok = emqtt:publish(C, Topic, <<"payload">>), - {ok, #{topic := RecvTopic}} = receive_publish(100), - RecvTopic - end || Topic <- SubDestTopics], - ?assertEqual(SubDestTopics, RecvTopics1), - {ok, _, _} = emqtt:unsubscribe(C, SubOrigTopics), - timer:sleep(100), - ?assertEqual([], emqx_broker:subscriptions(<<"rewrite_client">>)), - %% Pub Rules - {ok, _Props, _} = emqtt:subscribe(C, [{Topic, ?QOS_1} || Topic <- PubDestTopics]), - RecvTopics2 = [begin - ok = emqtt:publish(C, Topic, <<"payload">>), - {ok, #{topic := RecvTopic}} = receive_publish(100), - RecvTopic - end || Topic <- PubOrigTopics], - ?assertEqual(PubDestTopics, RecvTopics2), - {ok, _, _} = emqtt:unsubscribe(C, PubDestTopics), - - ok = emqtt:disconnect(C), - ok = emqx_mod_rewrite:unload(?RULES). - -t_rewrite_rule(_Config) -> - {PubRules, SubRules} = emqx_mod_rewrite:compile(?RULES), - ?assertEqual(<<"z/y/2">>, emqx_mod_rewrite:match_and_rewrite(<<"x/y/2">>, PubRules)), - ?assertEqual(<<"x/1/2">>, emqx_mod_rewrite:match_and_rewrite(<<"x/1/2">>, PubRules)), - ?assertEqual(<<"y/z/b">>, emqx_mod_rewrite:match_and_rewrite(<<"y/a/z/b">>, SubRules)), - ?assertEqual(<<"y/def">>, emqx_mod_rewrite:match_and_rewrite(<<"y/def">>, SubRules)). - -%%-------------------------------------------------------------------- -%% Internal functions -%%-------------------------------------------------------------------- - -receive_publish(Timeout) -> - receive - {publish, Publish} -> {ok, Publish} - after - Timeout -> {error, timeout} - end. diff --git a/test/emqx_mod_subscription_SUITE.erl b/test/emqx_mod_subscription_SUITE.erl deleted file mode 100644 index 06cd17cea..000000000 --- a/test/emqx_mod_subscription_SUITE.erl +++ /dev/null @@ -1,92 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_subscription_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include("emqx_mqtt.hrl"). --include_lib("eunit/include/eunit.hrl"). - -all() -> emqx_ct:all(?MODULE). - -init_per_suite(Config) -> - emqx_ct_helpers:boot_modules(all), - emqx_ct_helpers:start_apps([]), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -t_on_client_connected(_) -> - ?assertEqual(ok, emqx_mod_subscription:load([{<<"connected/%c/%u">>, #{qos => ?QOS_0}}])), - {ok, C} = emqtt:start_link([{host, "localhost"}, - {clientid, "myclient"}, - {username, "admin"}]), - {ok, _} = emqtt:connect(C), - emqtt:publish(C, <<"connected/myclient/admin">>, <<"Hello world">>, ?QOS_0), - {ok, #{topic := Topic, payload := Payload}} = receive_publish(100), - ?assertEqual(<<"connected/myclient/admin">>, Topic), - ?assertEqual(<<"Hello world">>, Payload), - ok = emqtt:disconnect(C), - ?assertEqual(ok, emqx_mod_subscription:unload([{<<"connected/%c/%u">>, #{qos => ?QOS_0}}])). - -t_on_undefined_client_connected(_) -> - ?assertEqual(ok, emqx_mod_subscription:load([{<<"connected/undefined">>, #{qos => ?QOS_1}}])), - {ok, C} = emqtt:start_link([{host, "localhost"}]), - {ok, _} = emqtt:connect(C), - emqtt:publish(C, <<"connected/undefined">>, <<"Hello world">>, ?QOS_1), - {ok, #{topic := Topic, payload := Payload}} = receive_publish(100), - ?assertEqual(<<"connected/undefined">>, Topic), - ?assertEqual(<<"Hello world">>, Payload), - ok = emqtt:disconnect(C), - ?assertEqual(ok, emqx_mod_subscription:unload([{<<"connected/undefined">>, #{qos => ?QOS_1}}])). - -t_suboption(_) -> - Client_info = fun(Key, Client) -> maps:get(Key, maps:from_list(emqtt:info(Client)), undefined) end, - Suboption = #{qos => ?QOS_2, nl => 1, rap => 1, rh => 2}, - ?assertEqual(ok, emqx_mod_subscription:load([{<<"connected/%c/%u">>, Suboption}])), - {ok, C1} = emqtt:start_link([{proto_ver, v5}]), - {ok, _} = emqtt:connect(C1), - timer:sleep(200), - [CPid1] = emqx_cm:lookup_channels(Client_info(clientid, C1)), - [ Sub1 | _ ] = ets:lookup(emqx_subscription,CPid1), - [ Suboption1 | _ ] = ets:lookup(emqx_suboption,Sub1), - ?assertMatch({Sub1, #{qos := 2, nl := 1, rap := 1, rh := 2, subid := _}}, Suboption1), - ok = emqtt:disconnect(C1), - %% The subscription option is not valid for MQTT V3.1.1 - {ok, C2} = emqtt:start_link([{proto_ver, v4}]), - {ok, _} = emqtt:connect(C2), - timer:sleep(200), - [CPid2] = emqx_cm:lookup_channels(Client_info(clientid, C2)), - [ Sub2 | _ ] = ets:lookup(emqx_subscription,CPid2), - [ Suboption2 | _ ] = ets:lookup(emqx_suboption,Sub2), - ok = emqtt:disconnect(C2), - ?assertMatch({Sub2, #{qos := 2, nl := 0, rap := 0, rh := 0, subid := _}}, Suboption2), - - ?assertEqual(ok, emqx_mod_subscription:unload([{<<"connected/undefined">>, Suboption}])). - -%%-------------------------------------------------------------------- -%% Internal functions -%%-------------------------------------------------------------------- - -receive_publish(Timeout) -> - receive - {publish, Publish} -> {ok, Publish} - after - Timeout -> {error, timeout} - end. diff --git a/test/emqx_mod_sup_SUITE.erl b/test/emqx_mod_sup_SUITE.erl deleted file mode 100644 index cd4c868ee..000000000 --- a/test/emqx_mod_sup_SUITE.erl +++ /dev/null @@ -1,51 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_sup_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include_lib("eunit/include/eunit.hrl"). - -all() -> emqx_ct:all(?MODULE). - -%%-------------------------------------------------------------------- -%% Test cases -%%-------------------------------------------------------------------- - -t_start(_) -> - {ok, _} = emqx_mod_sup:start_link(), - ?assertEqual([], supervisor:which_children(emqx_mod_sup)). - -t_start_child(_) -> - %% Set the emqx_mod_sup child with emqx_hooks for test - Mod = emqx_hooks, - Spec = #{id => Mod, - start => {Mod, start_link, []}, - restart => permanent, - shutdown => 5000, - type => worker, - modules => [Mod]}, - - {ok, _} = emqx_mod_sup:start_link(), - {ok, _} = emqx_mod_sup:start_child(Mod, worker), - {error, {already_started, _}} = emqx_mod_sup:start_child(Spec), - - ok = emqx_mod_sup:stop_child(Mod), - {error, not_found} = emqx_mod_sup:stop_child(Mod), - ok. - diff --git a/test/emqx_mod_topic_metrics_SUITE.erl b/test/emqx_mod_topic_metrics_SUITE.erl deleted file mode 100644 index 4ac1b00eb..000000000 --- a/test/emqx_mod_topic_metrics_SUITE.erl +++ /dev/null @@ -1,92 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_mod_topic_metrics_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include_lib("eunit/include/eunit.hrl"). - -all() -> emqx_ct:all(?MODULE). - -init_per_suite(Config) -> - emqx_ct_helpers:boot_modules(all), - emqx_ct_helpers:start_apps([]), - Config. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -t_nonexistent_topic_metrics(_) -> - emqx_mod_topic_metrics:load([]), - ?assertEqual({error, topic_not_found}, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.in')), - ?assertEqual({error, topic_not_found}, emqx_mod_topic_metrics:inc(<<"a/b/c">>, 'messages.in')), - ?assertEqual({error, topic_not_found}, emqx_mod_topic_metrics:rate(<<"a/b/c">>, 'messages.in')), - emqx_mod_topic_metrics:register(<<"a/b/c">>), - ?assertEqual(0, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.in')), - ?assertEqual({error, invalid_metric}, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'invalid.metrics')), - ?assertEqual({error, invalid_metric}, emqx_mod_topic_metrics:inc(<<"a/b/c">>, 'invalid.metrics')), - ?assertEqual({error, invalid_metric}, emqx_mod_topic_metrics:rate(<<"a/b/c">>, 'invalid.metrics')), - emqx_mod_topic_metrics:unregister(<<"a/b/c">>), - emqx_mod_topic_metrics:unload([]). - -t_topic_metrics(_) -> - emqx_mod_topic_metrics:load([]), - - ?assertEqual(false, emqx_mod_topic_metrics:is_registered(<<"a/b/c">>)), - ?assertEqual([], emqx_mod_topic_metrics:all_registered_topics()), - emqx_mod_topic_metrics:register(<<"a/b/c">>), - ?assertEqual(true, emqx_mod_topic_metrics:is_registered(<<"a/b/c">>)), - ?assertEqual([<<"a/b/c">>], emqx_mod_topic_metrics:all_registered_topics()), - - ?assertEqual(0, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.in')), - ?assertEqual(ok, emqx_mod_topic_metrics:inc(<<"a/b/c">>, 'messages.in')), - ?assertEqual(1, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.in')), - ?assert(emqx_mod_topic_metrics:rate(<<"a/b/c">>, 'messages.in') =:= 0), - emqx_mod_topic_metrics:unregister(<<"a/b/c">>), - emqx_mod_topic_metrics:unload([]). - -t_hook(_) -> - emqx_mod_topic_metrics:load([]), - emqx_mod_topic_metrics:register(<<"a/b/c">>), - - ?assertEqual(0, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.in')), - ?assertEqual(0, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.qos0.in')), - ?assertEqual(0, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.out')), - ?assertEqual(0, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.qos0.out')), - ?assertEqual(0, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.dropped')), - - {ok, C} = emqtt:start_link([{host, "localhost"}, - {clientid, "myclient"}, - {username, "myuser"}]), - {ok, _} = emqtt:connect(C), - emqtt:publish(C, <<"a/b/c">>, <<"Hello world">>, 0), - ct:sleep(100), - ?assertEqual(1, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.in')), - ?assertEqual(1, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.qos0.in')), - ?assertEqual(1, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.dropped')), - - emqtt:subscribe(C, <<"a/b/c">>), - emqtt:publish(C, <<"a/b/c">>, <<"Hello world">>, 0), - ct:sleep(100), - ?assertEqual(2, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.in')), - ?assertEqual(2, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.qos0.in')), - ?assertEqual(1, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.out')), - ?assertEqual(1, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.qos0.out')), - ?assertEqual(1, emqx_mod_topic_metrics:val(<<"a/b/c">>, 'messages.dropped')), - emqx_mod_topic_metrics:unregister(<<"a/b/c">>), - emqx_mod_topic_metrics:unload([]). \ No newline at end of file diff --git a/test/emqx_modules_SUITE.erl b/test/emqx_modules_SUITE.erl deleted file mode 100644 index 3fe7864c3..000000000 --- a/test/emqx_modules_SUITE.erl +++ /dev/null @@ -1,47 +0,0 @@ -%%-------------------------------------------------------------------- -%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%%-------------------------------------------------------------------- - --module(emqx_modules_SUITE). - --compile(export_all). --compile(nowarn_export_all). - --include_lib("eunit/include/eunit.hrl"). - -all() -> emqx_ct:all(?MODULE). - -init_per_suite(Config) -> - emqx_ct_helpers:start_apps([], fun set_sepecial_cfg/1), - Config. - -set_sepecial_cfg(_) -> - application:set_env(emqx, modules_loaded_file, emqx_ct_helpers:deps_path(emqx, "test/emqx_SUITE_data/loaded_modules")), - ok. - -end_per_suite(_Config) -> - emqx_ct_helpers:stop_apps([]). - -t_load(_) -> - ?assertEqual(ok, emqx_modules:unload()), - ?assertEqual(ok, emqx_modules:load()), - ?assertEqual({error, not_found}, emqx_modules:load(not_existed_module)), - ?assertEqual({error, not_started}, emqx_modules:unload(emqx_mod_rewrite)), - ?assertEqual(ignore, emqx_modules:reload(emqx_mod_rewrite)), - ?assertEqual(ok, emqx_modules:reload(emqx_mod_acl_internal)). - -t_list(_) -> - ?assertMatch([{_, _} | _ ], emqx_modules:list()). - diff --git a/test/mqtt_protocol_v5_SUITE.erl b/test/mqtt_protocol_v5_SUITE.erl index 50fc9c04d..f0a0cc3dc 100644 --- a/test/mqtt_protocol_v5_SUITE.erl +++ b/test/mqtt_protocol_v5_SUITE.erl @@ -179,10 +179,7 @@ t_batch_subscribe(_) -> {ok, Client} = emqtt:start_link([{proto_ver, v5}, {clientid, <<"batch_test">>}]), {ok, _} = emqtt:connect(Client), application:set_env(emqx, enable_acl_cache, false), - TempAcl = emqx_ct_helpers:deps_path(emqx, "test/emqx_access_SUITE_data/acl_temp.conf"), - file:write_file(TempAcl, "{deny, {client, \"batch_test\"}, subscribe, [\"t1\", \"t2\", \"t3\"]}.\n"), - timer:sleep(10), - emqx_mod_acl_internal:reload([{acl_file, TempAcl}]), + application:set_env(emqx, acl_nomatch, deny), {ok, _, [?RC_NOT_AUTHORIZED, ?RC_NOT_AUTHORIZED, ?RC_NOT_AUTHORIZED]} = emqtt:subscribe(Client, [{<<"t1">>, qos1}, @@ -193,8 +190,9 @@ t_batch_subscribe(_) -> ?RC_NO_SUBSCRIPTION_EXISTED]} = emqtt:unsubscribe(Client, [<<"t1">>, <<"t2">>, <<"t3">>]), - file:delete(TempAcl), + application:set_env(emqx, acl_nomatch, allow), emqtt:disconnect(Client). + t_connect_will_retain(_) -> Topic = nth(1, ?TOPICS), From 827c92c430cb05848841602e835c8955b900574b Mon Sep 17 00:00:00 2001 From: Rory Z Date: Sun, 11 Oct 2020 11:13:39 +0800 Subject: [PATCH 02/41] Auto-pull-request-on-2020-10-11 (#3770) * feature(confs): Split emqx.conf * optimize(application): Optimize emqx module startup sequence * feature: remove the emqx_modules related code * feature: ws/wss add more params * chore: update esockd version to fix ssl:getstat/2 for dtls connection * fix: fix session_locking_strategy enum typos * fix(ignore-loop-deliver): fix issue#3738 (#3741) * chore(paths): cherry-pick v4.2.0 commits and patch it * chore(types): Add the disconnected_at field definition in conninfo (#3764) From 9595b4978965e0f1206a361224e912099a6b1921 Mon Sep 17 00:00:00 2001 From: turtleDeng Date: Mon, 12 Oct 2020 20:07:41 +0800 Subject: [PATCH 03/41] chore(vars) update vars --- vars | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vars b/vars index 359c27c22..914938fb8 100644 --- a/vars +++ b/vars @@ -1,8 +1,8 @@ %% vars here are for test only, not intended for release -{platform_bin_dir, "bin"}. -{platform_data_dir, "data"}. -{platform_etc_dir, "etc"}. -{platform_lib_dir, "lib"}. -{platform_log_dir, "log"}. -{platform_plugins_dir, "plugins"}. +{platform_bin_dir, "../../lib/emqx/bin"}. +{platform_data_dir, "../../lib/emqx/data"}. +{platform_etc_dir, "../../lib/emqx/etc"}. +{platform_lib_dir, "../../lib/emqx/lib"}. +{platform_log_dir, "../../lib/emqx/log"}. +{platform_plugins_dir, "../../lib/emqx/plugins"}. From b883e238bfe638ee286104594c32baddf78420ae Mon Sep 17 00:00:00 2001 From: JianBo He Date: Mon, 12 Oct 2020 17:05:06 +0800 Subject: [PATCH 04/41] fix(ws): take ws_cookie to clientinfo see: https://github.com/emqx/emqx/issues/3747#issuecomment-702268570 --- src/emqx_channel.erl | 13 +++++++++++-- test/emqx_channel_SUITE.erl | 12 ++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/emqx_channel.erl b/src/emqx_channel.erl index 289ed50f0..71b89f153 100644 --- a/src/emqx_channel.erl +++ b/src/emqx_channel.erl @@ -183,8 +183,9 @@ init(ConnInfo = #{peername := {PeerHost, _Port}, is_bridge => false, is_superuser => false }, Options), - #channel{conninfo = ConnInfo, - clientinfo = ClientInfo, + {NClientInfo, NConnInfo} = take_ws_cookie(ClientInfo, ConnInfo), + #channel{conninfo = NConnInfo, + clientinfo = NClientInfo, topic_aliases = #{inbound => #{}, outbound => #{} }, @@ -213,6 +214,14 @@ setting_peercert_infos(Peercert, ClientInfo, Options) -> end, ClientInfo#{username => Username, dn => DN, cn => CN}. +take_ws_cookie(ClientInfo, ConnInfo) -> + case maps:take(ws_cookie, ConnInfo) of + {WsCookie, NConnInfo} -> + {ClientInfo#{ws_cookie => WsCookie}, NConnInfo}; + _ -> + {ClientInfo, ConnInfo} + end. + %%-------------------------------------------------------------------- %% Handle incoming packet %%-------------------------------------------------------------------- diff --git a/test/emqx_channel_SUITE.erl b/test/emqx_channel_SUITE.erl index c90c7510c..613da40ac 100644 --- a/test/emqx_channel_SUITE.erl +++ b/test/emqx_channel_SUITE.erl @@ -687,6 +687,18 @@ t_terminate(_) -> ok = emqx_channel:terminate(sock_error, channel(#{conn_state => connected})), ok = emqx_channel:terminate({shutdown, kicked}, channel(#{conn_state => connected})). +t_ws_cookie_init(_) -> + WsCookie = [{<<"session_id">>, <<"xyz">>}], + ConnInfo = #{socktype => ws, + peername => {{127,0,0,1}, 3456}, + sockname => {{127,0,0,1}, 1883}, + peercert => nossl, + conn_mod => emqx_ws_connection, + ws_cookie => WsCookie + }, + Channel = emqx_channel:init(ConnInfo, [{zone, zone}]), + ?assertMatch(#{ws_cookie := WsCookie}, emqx_channel:info(clientinfo, Channel)). + %%-------------------------------------------------------------------- %% Helper functions %%-------------------------------------------------------------------- From 139306b61cb22e5bdd411173fb6696b57eefcbe9 Mon Sep 17 00:00:00 2001 From: JianBo He Date: Sat, 24 Oct 2020 11:26:56 +0800 Subject: [PATCH 05/41] fix(json): fix decoding/encoding empty object error --- src/emqx_json.erl | 5 ++++- test/emqx_json_SUITE.erl | 36 ++++++++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/emqx_json.erl b/src/emqx_json.erl index f7caaf727..e79cf09d3 100644 --- a/src/emqx_json.erl +++ b/src/emqx_json.erl @@ -103,6 +103,8 @@ safe_decode(Json, Opts) -> , from_ejson/1 ]}). +to_ejson([{}]) -> + {[]}; to_ejson([{_, _}|_] = L) -> {[{K, to_ejson(V)} || {K, V} <- L ]}; to_ejson(L) when is_list(L) -> @@ -111,6 +113,8 @@ to_ejson(T) -> T. from_ejson(L) when is_list(L) -> [from_ejson(E) || E <- L]; +from_ejson({[]}) -> + [{}]; from_ejson({L}) -> [{Name, from_ejson(Value)} || {Name, Value} <- L]; from_ejson(T) -> T. @@ -118,4 +122,3 @@ from_ejson(T) -> T. to_binary(B) when is_binary(B) -> B; to_binary(L) when is_list(L) -> iolist_to_binary(L). - diff --git a/test/emqx_json_SUITE.erl b/test/emqx_json_SUITE.erl index 67f8108c5..fa544ffbb 100644 --- a/test/emqx_json_SUITE.erl +++ b/test/emqx_json_SUITE.erl @@ -27,6 +27,7 @@ , decode/2 ]). +%% copied jiffy/readme %%-------------------------------------------------------------------- %% Erlang JSON Erlang %% ------------------------------------------------------------------- @@ -45,10 +46,27 @@ %% {[{foo, bar}]} -> {"foo": "bar"} -> {[{<<"foo">>, <<"bar">>}]} %% {[{<<"foo">>, <<"bar">>}]} -> {"foo": "bar"} -> {[{<<"foo">>, <<"bar">>}]} %% #{<<"foo">> => <<"bar">>} -> {"foo": "bar"} -> #{<<"foo">> => <<"bar">>} +%%-------------------------------------------------------------------- + +%% but in emqx_json, we use the jsx style for it: +%%-------------------------------------------------------------------- +%% Erlang JSON Erlang +%% ------------------------------------------------------------------- %% -%% Extension: -%% [{<<"foo">>, <<"bar">>}] -> {"foo": "bar"} -> [{<<"foo">>, <<"bar">>}] -%% +%% null -> null -> null +%% true -> true -> true +%% false -> false -> false +%% "hi" -> [104, 105] -> [104, 105] +%% <<"hi">> -> "hi" -> <<"hi">> +%% hi -> "hi" -> <<"hi">> +%% 1 -> 1 -> 1 +%% 1.25 -> 1.25 -> 1.25 +%% [] -> [] -> [] +%% [true, 1.0] -> [true, 1.0] -> [true, 1.0] +%m [{}] -> {} -> [{}] +%a [{<<"foo">>, <<"bar">>}] -> {"foo": "bar"} -> [{<<"foo">>, <<"bar">>}] +%% #{<<"foo">> => <<"bar">>} -> {"foo": "bar"} -> #{<<"foo">> => <<"bar">>} +%m #{<<"foo">> => [{}]} NOT SUPPORT %%-------------------------------------------------------------------- all() -> emqx_ct:all(?MODULE). @@ -63,9 +81,8 @@ t_decode_encode(_) -> 1.25 = decode(encode(1.25)), [] = decode(encode([])), [true, 1] = decode(encode([true, 1])), - [] = decode(encode({[]})), - [{<<"foo">>, <<"bar">>}] = decode(encode({[{foo, bar}]})), - [{<<"foo">>, <<"bar">>}] = decode(encode({[{<<"foo">>, <<"bar">>}]})), + [{}] = decode(encode([{}])), + [{<<"foo">>, <<"bar">>}] = decode(encode([{foo, bar}])), [{<<"foo">>, <<"bar">>}] = decode(encode([{<<"foo">>, <<"bar">>}])), [[{<<"foo">>, <<"bar">>}]] = decode(encode([[{<<"foo">>, <<"bar">>}]])), [[{<<"foo">>, <<"bar">>}, @@ -92,10 +109,10 @@ t_safe_decode_encode(_) -> 1.25 = safe_encode_decode(1.25), [] = safe_encode_decode([]), [true, 1] = safe_encode_decode([true, 1]), - [] = safe_encode_decode({[]}), - [{<<"foo">>, <<"bar">>}] = safe_encode_decode({[{foo, bar}]}), - [{<<"foo">>, <<"bar">>}] = safe_encode_decode({[{<<"foo">>, <<"bar">>}]}), + [{}] = decode(encode([{}])), + [{<<"foo">>, <<"bar">>}] = safe_encode_decode([{foo, bar}]), [{<<"foo">>, <<"bar">>}] = safe_encode_decode([{<<"foo">>, <<"bar">>}]), + [[{<<"foo">>, <<"bar">>}]] = safe_encode_decode([[{<<"foo">>, <<"bar">>}]]), {ok, Json} = emqx_json:safe_encode(#{<<"foo">> => <<"bar">>}), {ok, #{<<"foo">> := <<"bar">>}} = emqx_json:safe_decode(Json, [return_maps]). @@ -105,4 +122,3 @@ safe_encode_decode(Term) -> {ok, {NTerm}} -> NTerm; {ok, NTerm} -> NTerm end. - From cb50156194ed771f5fb6d1b3cb2371eedf40b2dc Mon Sep 17 00:00:00 2001 From: JianBo He Date: Sat, 24 Oct 2020 13:49:18 +0800 Subject: [PATCH 06/41] chore(esockd): upgrade esockd to 5.7.4 --- rebar.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rebar.config b/rebar.config index be7d01148..df71f9762 100644 --- a/rebar.config +++ b/rebar.config @@ -6,7 +6,7 @@ [{gproc, {git, "https://github.com/uwiger/gproc", {tag, "0.8.0"}}}, {jiffy, {git, "https://github.com/emqx/jiffy", {tag, "1.0.5"}}}, {cowboy, {git, "https://github.com/emqx/cowboy", {tag, "2.7.1"}}}, - {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.7.3"}}}, + {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.7.4"}}}, {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.7.4"}}}, {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.5.0"}}}, {cuttlefish, {git, "https://github.com/emqx/cuttlefish", {tag, "v3.0.0"}}} From cc69225b6d5ae30e60f6ff401c837595113db975 Mon Sep 17 00:00:00 2001 From: Shawn <506895667@qq.com> Date: Tue, 10 Nov 2020 19:07:02 +0800 Subject: [PATCH 07/41] feature(tcp): alarm when tcp connection congested (#3818) --- etc/listeners.conf | 7 ++++++ priv/emqx.schema | 11 +++++++++ src/emqx.appup.src | 14 ++++++++++++ src/emqx_alarm.erl | 2 ++ src/emqx_connection.erl | 41 +++++++++++++++++++++++++++++++--- test/emqx_connection_SUITE.erl | 5 +++++ 6 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/emqx.appup.src diff --git a/etc/listeners.conf b/etc/listeners.conf index 2f2f1b5a1..c7d11967d 100644 --- a/etc/listeners.conf +++ b/etc/listeners.conf @@ -116,6 +116,13 @@ listener.tcp.external.send_timeout_close = on ## Value: on | off ## listener.tcp.external.tune_buffer = off +## The socket is set to a busy state when the amount of data queued internally +## by the ERTS socket implementation reaches this limit. +## +## Value: on | off +## Defaults to 1MB +## listener.tcp.external.high_watermark = 1MB + ## The TCP_NODELAY flag for MQTT connections. Small amounts of data are ## sent immediately if the option is enabled. ## diff --git a/priv/emqx.schema b/priv/emqx.schema index 6f4e7012e..21047aaaa 100644 --- a/priv/emqx.schema +++ b/priv/emqx.schema @@ -1238,6 +1238,11 @@ end}. hidden ]}. +{mapping, "listener.tcp.$name.high_watermark", "emqx.listeners", [ + {datatype, bytesize}, + {default, "1MB"} +]}. + {mapping, "listener.tcp.$name.tune_buffer", "emqx.listeners", [ {datatype, flag}, hidden @@ -1330,6 +1335,11 @@ end}. hidden ]}. +{mapping, "listener.ssl.$name.high_watermark", "emqx.listeners", [ + {datatype, bytesize}, + {default, "1MB"} +]}. + {mapping, "listener.ssl.$name.tune_buffer", "emqx.listeners", [ {datatype, flag}, hidden @@ -1840,6 +1850,7 @@ end}. {recbuf, cuttlefish:conf_get(Prefix ++ ".recbuf", Conf, undefined)}, {sndbuf, cuttlefish:conf_get(Prefix ++ ".sndbuf", Conf, undefined)}, {buffer, cuttlefish:conf_get(Prefix ++ ".buffer", Conf, undefined)}, + {high_watermark, cuttlefish:conf_get(Prefix ++ ".high_watermark", Conf, undefined)}, {nodelay, cuttlefish:conf_get(Prefix ++ ".nodelay", Conf, true)}, {reuseaddr, cuttlefish:conf_get(Prefix ++ ".reuseaddr", Conf, undefined)}]) end, diff --git a/src/emqx.appup.src b/src/emqx.appup.src new file mode 100644 index 000000000..cdf2ac0c1 --- /dev/null +++ b/src/emqx.appup.src @@ -0,0 +1,14 @@ +{"4.2.1", + [ + {"4.2.0", [ + {load_module, emqx_alarm, brutal_purge, soft_purge, []}, + {load_module, emqx_connection, brutal_purge, soft_purge, []} + ]} + ], + [ + {"4.2.0", [ + {load_module, emqx_alarm, brutal_purge, soft_purge, []}, + {load_module, emqx_connection, brutal_purge, soft_purge, []} + ]} + ] +}. diff --git a/src/emqx_alarm.erl b/src/emqx_alarm.erl index 37d6fe1e8..ec2cb4338 100644 --- a/src/emqx_alarm.erl +++ b/src/emqx_alarm.erl @@ -344,6 +344,8 @@ normalize_message(partition, #{occurred := Node}) -> list_to_binary(io_lib:format("Partition occurs at node ~s", [Node])); normalize_message(<<"resource", _/binary>>, #{type := Type, id := ID}) -> list_to_binary(io_lib:format("Resource ~s(~s) is down", [Type, ID])); +normalize_message(<<"mqtt_conn/congested/", ClientId/binary>>, _) -> + list_to_binary(io_lib:format("MQTT connection for clientid '~s' is congested", [ClientId])); normalize_message(_Name, _UnknownDetails) -> <<"Unknown alarm">>. diff --git a/src/emqx_connection.erl b/src/emqx_connection.erl index 2ab7f6c1e..f8bbd29fe 100644 --- a/src/emqx_connection.erl +++ b/src/emqx_connection.erl @@ -103,6 +103,9 @@ -define(ENABLED(X), (X =/= undefined)). +-define(ALARM_TCP_CONGEST(Channel), + list_to_binary(io_lib:format("mqtt_conn/congested/~s", [emqx_channel:info(clientid, Channel)]))). + -dialyzer({no_match, [info/2]}). -dialyzer({nowarn_function, [ init/4 , init_state/3 @@ -428,6 +431,7 @@ handle_msg(Msg, State) -> terminate(Reason, State = #state{channel = Channel}) -> ?LOG(debug, "Terminated due to ~p", [Reason]), + emqx_alarm:deactivate(?ALARM_TCP_CONGEST(Channel)), emqx_channel:terminate(Reason, Channel), close_socket(State), exit(Reason). @@ -594,11 +598,12 @@ serialize_and_inc_stats_fun(#state{serialize = Serialize}) -> %% Send data -spec(send(iodata(), state()) -> ok). -send(IoData, #state{transport = Transport, socket = Socket}) -> +send(IoData, #state{transport = Transport, socket = Socket, channel = Channel}) -> Oct = iolist_size(IoData), ok = emqx_metrics:inc('bytes.sent', Oct), emqx_pd:inc_counter(outgoing_bytes, Oct), - case Transport:async_send(Socket, IoData) of + maybe_warn_congestion(Socket, Transport, Channel), + case Transport:async_send(Socket, IoData, [nosuspend]) of ok -> ok; Error = {error, _Reason} -> %% Send an inet_reply to postpone handling the error @@ -606,6 +611,36 @@ send(IoData, #state{transport = Transport, socket = Socket}) -> ok end. +maybe_warn_congestion(Socket, Transport, Channel) -> + IsCongestAlarmSet = is_congestion_alarm_set(), + case is_congested(Socket, Transport) of + true when not IsCongestAlarmSet -> + {ok, Stat} = Transport:getstat(Socket, [recv_cnt, recv_oct, send_cnt, send_oct]), + {ok, Opts} = Transport:getopts(Socket, [high_watermark,high_msgq_watermark, sndbuf, recbuf, buffer]), + ok = set_congestion_alarm(), + emqx_alarm:activate(?ALARM_TCP_CONGEST(Channel), maps:from_list(Stat++Opts)); + false when IsCongestAlarmSet -> + ok = clear_congestion_alarm(), + emqx_alarm:deactivate(?ALARM_TCP_CONGEST(Channel)); + _ -> ok + end. + +is_congested(Socket, Transport) -> + case Transport:getstat(Socket, [send_pend]) of + {ok, [{send_pend, N}]} when N > 0 -> true; + _ -> false + end. + +is_congestion_alarm_set() -> + case erlang:get(conn_congested) of + true -> true; + _ -> false + end. +set_congestion_alarm() -> + erlang:put(conn_congested, true), ok. +clear_congestion_alarm() -> + erlang:put(conn_congested, false), ok. + %%-------------------------------------------------------------------- %% Handle Info @@ -621,7 +656,7 @@ handle_info(activate_socket, State = #state{sockstate = OldSst}) -> end; handle_info({sock_error, Reason}, State) -> - ?LOG(debug, "Socket error: ~p", [Reason]), + Reason =/= closed andalso ?LOG(error, "Socket error: ~p", [Reason]), handle_info({sock_closed, Reason}, close_socket(State)); handle_info(Info, State) -> diff --git a/test/emqx_connection_SUITE.erl b/test/emqx_connection_SUITE.erl index b908fe4ab..2538aeecb 100644 --- a/test/emqx_connection_SUITE.erl +++ b/test/emqx_connection_SUITE.erl @@ -52,6 +52,9 @@ init_per_suite(Config) -> ok = meck:expect(emqx_channel, ensure_disconnected, fun(_, Channel) -> Channel end), + ok = meck:expect(emqx_alarm, activate, fun(_, _) -> ok end), + ok = meck:expect(emqx_alarm, deactivate, fun(_) -> ok end), + Config. end_per_suite(_Config) -> @@ -62,6 +65,7 @@ end_per_suite(_Config) -> ok = meck:unload(emqx_pd), ok = meck:unload(emqx_metrics), ok = meck:unload(emqx_hooks), + ok = meck:unload(emqx_alarm), ok. init_per_testcase(_TestCase, Config) -> @@ -77,6 +81,7 @@ init_per_testcase(_TestCase, Config) -> {ok, [{K, 0} || K <- Options]} end), ok = meck:expect(emqx_transport, async_send, fun(_Sock, _Data) -> ok end), + ok = meck:expect(emqx_transport, async_send, fun(_Sock, _Data, _Opts) -> ok end), ok = meck:expect(emqx_transport, fast_close, fun(_Sock) -> ok end), Config. From e100b0a5e96ae303882dc41fd992ce4ef94f7630 Mon Sep 17 00:00:00 2001 From: zhanghongtong Date: Tue, 10 Nov 2020 21:44:39 +0800 Subject: [PATCH 08/41] feat(emqx_metrics): add new functions to count message received --- src/emqx.appup.src | 6 ++++-- src/emqx_metrics.erl | 13 ++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/emqx.appup.src b/src/emqx.appup.src index cdf2ac0c1..23a383d77 100644 --- a/src/emqx.appup.src +++ b/src/emqx.appup.src @@ -2,13 +2,15 @@ [ {"4.2.0", [ {load_module, emqx_alarm, brutal_purge, soft_purge, []}, - {load_module, emqx_connection, brutal_purge, soft_purge, []} + {load_module, emqx_connection, brutal_purge, soft_purge, []}, + {load_module, emqx_metrics, brutal_purge, soft_purge, []} ]} ], [ {"4.2.0", [ {load_module, emqx_alarm, brutal_purge, soft_purge, []}, - {load_module, emqx_connection, brutal_purge, soft_purge, []} + {load_module, emqx_connection, brutal_purge, soft_purge, []}, + {load_module, emqx_metrics, brutal_purge, soft_purge, []} ]} ] }. diff --git a/src/emqx_metrics.erl b/src/emqx_metrics.erl index 2a5a82749..4bd529a2e 100644 --- a/src/emqx_metrics.erl +++ b/src/emqx_metrics.erl @@ -21,6 +21,7 @@ -include("logger.hrl"). -include("types.hrl"). -include("emqx_mqtt.hrl"). +-include("emqx.hrl"). -logger_header("[Metrics]"). @@ -49,7 +50,8 @@ ]). %% Inc received/sent metrics --export([ inc_recv/1 +-export([ inc_msg/1 + , inc_recv/1 , inc_sent/1 ]). @@ -313,6 +315,15 @@ update_counter(Name, Value) -> %% Inc received/sent metrics %%-------------------------------------------------------------------- +-spec(inc_msg(emqx_types:massage()) -> ok). +inc_msg(Msg) -> + case Msg#message.qos of + 0 -> inc('messages.qos0.received'); + 1 -> inc('messages.qos1.received'); + 2 -> inc('messages.qos2.received') + end, + inc('messages.received'). + %% @doc Inc packets received. -spec(inc_recv(emqx_types:packet()) -> ok). inc_recv(Packet) -> From 26c03aaa43c0e1e788ba8bb3eca1bb01eb665688 Mon Sep 17 00:00:00 2001 From: turtled Date: Wed, 11 Nov 2020 09:37:39 +0800 Subject: [PATCH 09/41] feat(connection): update alarm info --- src/emqx_connection.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/emqx_connection.erl b/src/emqx_connection.erl index f8bbd29fe..d52e79358 100644 --- a/src/emqx_connection.erl +++ b/src/emqx_connection.erl @@ -104,7 +104,8 @@ -define(ENABLED(X), (X =/= undefined)). -define(ALARM_TCP_CONGEST(Channel), - list_to_binary(io_lib:format("mqtt_conn/congested/~s", [emqx_channel:info(clientid, Channel)]))). + list_to_binary(io_lib:format("mqtt_conn/congested/~s/~s", [emqx_channel:info(clientid, Channel), maps:get(username, emqx_channel:info(clientinfo, Channel), <<"undefined">>)]))). + -dialyzer({no_match, [info/2]}). -dialyzer({nowarn_function, [ init/4 From 8cc69e639f0891278d0fd0707040d0c174cff73a Mon Sep 17 00:00:00 2001 From: terry-xiaoyu <506895667@qq.com> Date: Wed, 11 Nov 2020 14:35:21 +0800 Subject: [PATCH 10/41] fix(congestion): change the conn congestion alarm msg body --- src/emqx.appup.src | 6 ++++-- src/emqx_channel.erl | 14 ++++++++++++++ src/emqx_connection.erl | 25 ++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/emqx.appup.src b/src/emqx.appup.src index 23a383d77..39c79d773 100644 --- a/src/emqx.appup.src +++ b/src/emqx.appup.src @@ -2,14 +2,16 @@ [ {"4.2.0", [ {load_module, emqx_alarm, brutal_purge, soft_purge, []}, - {load_module, emqx_connection, brutal_purge, soft_purge, []}, + {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, + {load_module, emqx_channel, brutal_purge, soft_purge, []}, {load_module, emqx_metrics, brutal_purge, soft_purge, []} ]} ], [ {"4.2.0", [ {load_module, emqx_alarm, brutal_purge, soft_purge, []}, - {load_module, emqx_connection, brutal_purge, soft_purge, []}, + {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, + {load_module, emqx_channel, brutal_purge, soft_purge, []}, {load_module, emqx_metrics, brutal_purge, soft_purge, []} ]} ] diff --git a/src/emqx_channel.erl b/src/emqx_channel.erl index 71b89f153..d9356ccd7 100644 --- a/src/emqx_channel.erl +++ b/src/emqx_channel.erl @@ -131,6 +131,20 @@ info(zone, #channel{clientinfo = #{zone := Zone}}) -> Zone; info(clientid, #channel{clientinfo = #{clientid := ClientId}}) -> ClientId; +info(username, #channel{clientinfo = #{username := Username}}) -> + Username; +info(socktype, #channel{conninfo = #{socktype := SockType}}) -> + SockType; +info(peername, #channel{conninfo = #{peername := Peername}}) -> + Peername; +info(sockname, #channel{conninfo = #{sockname := Sockname}}) -> + Sockname; +info(proto_name, #channel{conninfo = #{proto_name := ProtoName}}) -> + ProtoName; +info(proto_ver, #channel{conninfo = #{proto_ver := ProtoVer}}) -> + ProtoVer; +info(connected_at, #channel{conninfo = #{connected_at := ConnectedAt}}) -> + ConnectedAt; info(clientinfo, #channel{clientinfo = ClientInfo}) -> ClientInfo; info(session, #channel{session = Session}) -> diff --git a/src/emqx_connection.erl b/src/emqx_connection.erl index d52e79358..3078ebd91 100644 --- a/src/emqx_connection.erl +++ b/src/emqx_connection.erl @@ -107,6 +107,13 @@ list_to_binary(io_lib:format("mqtt_conn/congested/~s/~s", [emqx_channel:info(clientid, Channel), maps:get(username, emqx_channel:info(clientinfo, Channel), <<"undefined">>)]))). +-define(ALARM_CONN_INFO_KEYS, [ + socktype, sockname, peername, + clientid, username, proto_name, proto_ver, connected_at +]). +-define(ALARM_SOCK_STATS_KEYS, [send_pend, recv_cnt, recv_oct, send_cnt, send_oct]). +-define(ALARM_SOCK_OPTS_KEYS, [high_watermark, high_msgq_watermark, sndbuf, recbuf, buffer]). + -dialyzer({no_match, [info/2]}). -dialyzer({nowarn_function, [ init/4 , init_state/3 @@ -616,10 +623,9 @@ maybe_warn_congestion(Socket, Transport, Channel) -> IsCongestAlarmSet = is_congestion_alarm_set(), case is_congested(Socket, Transport) of true when not IsCongestAlarmSet -> - {ok, Stat} = Transport:getstat(Socket, [recv_cnt, recv_oct, send_cnt, send_oct]), - {ok, Opts} = Transport:getopts(Socket, [high_watermark,high_msgq_watermark, sndbuf, recbuf, buffer]), ok = set_congestion_alarm(), - emqx_alarm:activate(?ALARM_TCP_CONGEST(Channel), maps:from_list(Stat++Opts)); + emqx_alarm:activate(?ALARM_TCP_CONGEST(Channel), + tcp_congestion_alarm_details(Socket, Transport, Channel)); false when IsCongestAlarmSet -> ok = clear_congestion_alarm(), emqx_alarm:deactivate(?ALARM_TCP_CONGEST(Channel)); @@ -642,6 +648,19 @@ set_congestion_alarm() -> clear_congestion_alarm() -> erlang:put(conn_congested, false), ok. +tcp_congestion_alarm_details(Socket, Transport, Channel) -> + {ok, Stat} = Transport:getstat(Socket, ?ALARM_SOCK_STATS_KEYS), + {ok, Opts} = Transport:getopts(Socket, ?ALARM_SOCK_OPTS_KEYS), + SockInfo = maps:from_list(Stat ++ Opts), + ConnInfo = maps:from_list([conn_info(Key, Channel) || Key <- ?ALARM_CONN_INFO_KEYS]), + maps:merge(ConnInfo, SockInfo). + +conn_info(Key, Channel) when Key =:= sockname; Key =:= peername -> + {IPStr, Port} = emqx_channel:info(Key, Channel), + {Key, iolist_to_binary([inet:ntoa(IPStr),":",integer_to_list(Port)])}; +conn_info(Key, Channel) -> + {Key, emqx_channel:info(Key, Channel)}. + %%-------------------------------------------------------------------- %% Handle Info From 77d777fd116d5878b3f9a8cd11a1962d1b3d14e3 Mon Sep 17 00:00:00 2001 From: turtled Date: Fri, 13 Nov 2020 10:40:14 +0800 Subject: [PATCH 11/41] chore(acl): rollback emqx_access_rule module --- src/emqx_access_rule.erl | 153 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 src/emqx_access_rule.erl diff --git a/src/emqx_access_rule.erl b/src/emqx_access_rule.erl new file mode 100644 index 000000000..f0c6bcea9 --- /dev/null +++ b/src/emqx_access_rule.erl @@ -0,0 +1,153 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +-module(emqx_access_rule). + +%% APIs +-export([ match/3 + , compile/1 + ]). + +-export_type([rule/0]). + +-type(acl_result() :: allow | deny). + +-type(who() :: all | binary() | + {client, binary()} | + {user, binary()} | + {ipaddr, esockd_cidr:cidr_string()}). + +-type(access() :: subscribe | publish | pubsub). + +-type(rule() :: {acl_result(), all} | + {acl_result(), who(), access(), list(emqx_topic:topic())}). + +-define(ALLOW_DENY(A), ((A =:= allow) orelse (A =:= deny))). +-define(PUBSUB(A), ((A =:= subscribe) orelse (A =:= publish) orelse (A =:= pubsub))). + +%% @doc Compile Access Rule. +compile({A, all}) when ?ALLOW_DENY(A) -> + {A, all}; + +compile({A, Who, Access, Topic}) when ?ALLOW_DENY(A), ?PUBSUB(Access), is_binary(Topic) -> + {A, compile(who, Who), Access, [compile(topic, Topic)]}; + +compile({A, Who, Access, TopicFilters}) when ?ALLOW_DENY(A), ?PUBSUB(Access) -> + {A, compile(who, Who), Access, [compile(topic, Topic) || Topic <- TopicFilters]}. + +compile(who, all) -> + all; +compile(who, {ipaddr, CIDR}) -> + {ipaddr, esockd_cidr:parse(CIDR, true)}; +compile(who, {client, all}) -> + {client, all}; +compile(who, {client, ClientId}) -> + {client, bin(ClientId)}; +compile(who, {user, all}) -> + {user, all}; +compile(who, {user, Username}) -> + {user, bin(Username)}; +compile(who, {'and', Conds}) when is_list(Conds) -> + {'and', [compile(who, Cond) || Cond <- Conds]}; +compile(who, {'or', Conds}) when is_list(Conds) -> + {'or', [compile(who, Cond) || Cond <- Conds]}; + +compile(topic, {eq, Topic}) -> + {eq, emqx_topic:words(bin(Topic))}; +compile(topic, Topic) -> + Words = emqx_topic:words(bin(Topic)), + case 'pattern?'(Words) of + true -> {pattern, Words}; + false -> Words + end. + +'pattern?'(Words) -> + lists:member(<<"%u">>, Words) + orelse lists:member(<<"%c">>, Words). + +bin(L) when is_list(L) -> + list_to_binary(L); +bin(B) when is_binary(B) -> + B. + +%% @doc Match access rule +-spec(match(emqx_types:clientinfo(), emqx_types:topic(), rule()) + -> {matched, allow} | {matched, deny} | nomatch). +match(_ClientInfo, _Topic, {AllowDeny, all}) when ?ALLOW_DENY(AllowDeny) -> + {matched, AllowDeny}; +match(ClientInfo, Topic, {AllowDeny, Who, _PubSub, TopicFilters}) + when ?ALLOW_DENY(AllowDeny) -> + case match_who(ClientInfo, Who) + andalso match_topics(ClientInfo, Topic, TopicFilters) of + true -> {matched, AllowDeny}; + false -> nomatch + end. + +match_who(_ClientInfo, all) -> + true; +match_who(_ClientInfo, {user, all}) -> + true; +match_who(_ClientInfo, {client, all}) -> + true; +match_who(#{clientid := ClientId}, {client, ClientId}) -> + true; +match_who(#{username := Username}, {user, Username}) -> + true; +match_who(#{peerhost := undefined}, {ipaddr, _Tup}) -> + false; +match_who(#{peerhost := IP}, {ipaddr, CIDR}) -> + esockd_cidr:match(IP, CIDR); +match_who(ClientInfo, {'and', Conds}) when is_list(Conds) -> + lists:foldl(fun(Who, Allow) -> + match_who(ClientInfo, Who) andalso Allow + end, true, Conds); +match_who(ClientInfo, {'or', Conds}) when is_list(Conds) -> + lists:foldl(fun(Who, Allow) -> + match_who(ClientInfo, Who) orelse Allow + end, false, Conds); +match_who(_ClientInfo, _Who) -> + false. + +match_topics(_ClientInfo, _Topic, []) -> + false; +match_topics(ClientInfo, Topic, [{pattern, PatternFilter}|Filters]) -> + TopicFilter = feed_var(ClientInfo, PatternFilter), + match_topic(emqx_topic:words(Topic), TopicFilter) + orelse match_topics(ClientInfo, Topic, Filters); +match_topics(ClientInfo, Topic, [TopicFilter|Filters]) -> + match_topic(emqx_topic:words(Topic), TopicFilter) + orelse match_topics(ClientInfo, Topic, Filters). + +match_topic(Topic, {eq, TopicFilter}) -> + Topic == TopicFilter; +match_topic(Topic, TopicFilter) -> + emqx_topic:match(Topic, TopicFilter). + +feed_var(ClientInfo, Pattern) -> + feed_var(ClientInfo, Pattern, []). +feed_var(_ClientInfo, [], Acc) -> + lists:reverse(Acc); +feed_var(ClientInfo = #{clientid := undefined}, [<<"%c">>|Words], Acc) -> + feed_var(ClientInfo, Words, [<<"%c">>|Acc]); +feed_var(ClientInfo = #{clientid := ClientId}, [<<"%c">>|Words], Acc) -> + feed_var(ClientInfo, Words, [ClientId |Acc]); +feed_var(ClientInfo = #{username := undefined}, [<<"%u">>|Words], Acc) -> + feed_var(ClientInfo, Words, [<<"%u">>|Acc]); +feed_var(ClientInfo = #{username := Username}, [<<"%u">>|Words], Acc) -> + feed_var(ClientInfo, Words, [Username|Acc]); +feed_var(ClientInfo, [W|Words], Acc) -> + feed_var(ClientInfo, Words, [W|Acc]). + From 3f41adc3bd98348738bd253cbb4622effb6985e3 Mon Sep 17 00:00:00 2001 From: zhanghongtong Date: Tue, 24 Nov 2020 01:47:45 +0000 Subject: [PATCH 12/41] chore(appup): update version --- src/emqx.appup.src | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/emqx.appup.src b/src/emqx.appup.src index 39c79d773..0900bb449 100644 --- a/src/emqx.appup.src +++ b/src/emqx.appup.src @@ -1,5 +1,11 @@ -{"4.2.1", +{"4.2.2", [ + {"4.2.1", [ + {load_module, emqx_alarm, brutal_purge, soft_purge, []}, + {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, + {load_module, emqx_channel, brutal_purge, soft_purge, []}, + {load_module, emqx_metrics, brutal_purge, soft_purge, []} + ]}, {"4.2.0", [ {load_module, emqx_alarm, brutal_purge, soft_purge, []}, {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, @@ -8,6 +14,12 @@ ]} ], [ + {"4.2.1", [ + {load_module, emqx_alarm, brutal_purge, soft_purge, []}, + {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, + {load_module, emqx_channel, brutal_purge, soft_purge, []}, + {load_module, emqx_metrics, brutal_purge, soft_purge, []} + ]}, {"4.2.0", [ {load_module, emqx_alarm, brutal_purge, soft_purge, []}, {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, From 3ca39cb9cb19214afc09d2b9350eb7aa38ba4e7e Mon Sep 17 00:00:00 2001 From: turtleDeng Date: Wed, 25 Nov 2020 10:27:56 +0800 Subject: [PATCH 13/41] chore(appup): update version --- src/emqx.appup.src | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/emqx.appup.src b/src/emqx.appup.src index 0900bb449..9a88fb938 100644 --- a/src/emqx.appup.src +++ b/src/emqx.appup.src @@ -1,11 +1,6 @@ {"4.2.2", [ - {"4.2.1", [ - {load_module, emqx_alarm, brutal_purge, soft_purge, []}, - {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, - {load_module, emqx_channel, brutal_purge, soft_purge, []}, - {load_module, emqx_metrics, brutal_purge, soft_purge, []} - ]}, + {"4.2.1", []}, {"4.2.0", [ {load_module, emqx_alarm, brutal_purge, soft_purge, []}, {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, @@ -14,12 +9,7 @@ ]} ], [ - {"4.2.1", [ - {load_module, emqx_alarm, brutal_purge, soft_purge, []}, - {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, - {load_module, emqx_channel, brutal_purge, soft_purge, []}, - {load_module, emqx_metrics, brutal_purge, soft_purge, []} - ]}, + {"4.2.1", []}, {"4.2.0", [ {load_module, emqx_alarm, brutal_purge, soft_purge, []}, {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, From aa7124f3c9703d69f7bdd4ac976a067dad98935d Mon Sep 17 00:00:00 2001 From: Shawn <506895667@qq.com> Date: Wed, 25 Nov 2020 14:40:25 +0800 Subject: [PATCH 14/41] chore(appup): use binding var 'VSN' --- src/emqx.appup.src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emqx.appup.src b/src/emqx.appup.src index 9a88fb938..cf25e1196 100644 --- a/src/emqx.appup.src +++ b/src/emqx.appup.src @@ -1,4 +1,4 @@ -{"4.2.2", +{VSN, [ {"4.2.1", []}, {"4.2.0", [ From f5162562a45187986ad26dc293c4dbcbd8f95880 Mon Sep 17 00:00:00 2001 From: Shawn <506895667@qq.com> Date: Thu, 26 Nov 2020 10:42:35 +0800 Subject: [PATCH 15/41] chore(appup): update appup --- src/emqx.appup.src | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/emqx.appup.src b/src/emqx.appup.src index cf25e1196..9a9d221aa 100644 --- a/src/emqx.appup.src +++ b/src/emqx.appup.src @@ -1,12 +1,12 @@ {VSN, [ - {"4.2.1", []}, {"4.2.0", [ {load_module, emqx_alarm, brutal_purge, soft_purge, []}, {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, {load_module, emqx_channel, brutal_purge, soft_purge, []}, {load_module, emqx_metrics, brutal_purge, soft_purge, []} - ]} + ]}, + {<<".*">>, []} ], [ {"4.2.1", []}, @@ -15,6 +15,7 @@ {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, {load_module, emqx_channel, brutal_purge, soft_purge, []}, {load_module, emqx_metrics, brutal_purge, soft_purge, []} - ]} + ]}, + {<<".*">>, []} ] }. From a3cdae3b42d9b55201b3927f23d3d93c9505f401 Mon Sep 17 00:00:00 2001 From: zhanghongtong Date: Mon, 30 Nov 2020 17:28:03 +0800 Subject: [PATCH 16/41] feat(listener): add depth for ssl listener --- .gitignore | 1 + etc/listeners.conf | 7 ++++++- priv/emqx.schema | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index aaec950d4..2e19823c3 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ erlang.mk *.coverdata etc/emqx.conf.rendered Mnesia.*/ +.stamp diff --git a/etc/listeners.conf b/etc/listeners.conf index c7d11967d..034321b2a 100644 --- a/etc/listeners.conf +++ b/etc/listeners.conf @@ -301,6 +301,11 @@ listener.ssl.external.access.1 = allow all ## Value: Duration listener.ssl.external.handshake_timeout = 15s +## Maximum number of non-self-issued intermediate certificates that can follow the peer certificate in a valid certification path. +## +## Value: Number +## listener.ssl.external.depth = 10 + ## Path to the file containing the user's private PEM-encoded key. ## ## See: http://erlang.org/doc/man/ssl.html @@ -932,4 +937,4 @@ listener.wss.external.send_timeout_close = on ## Whether a WebSocket message is allowed to contain multiple MQTT packets ## ## Value: single | multiple -listener.wss.external.mqtt_piggyback = multiple \ No newline at end of file +listener.wss.external.mqtt_piggyback = multiple diff --git a/priv/emqx.schema b/priv/emqx.schema index 21047aaaa..830a0e934 100644 --- a/priv/emqx.schema +++ b/priv/emqx.schema @@ -1372,6 +1372,11 @@ end}. {datatype, {duration, ms}} ]}. +{mapping, "listener.ssl.$name.depth", "emqx.listeners", [ + {default, 10}, + {datatype, integer} +]}. + {mapping, "listener.ssl.$name.dhfile", "emqx.listeners", [ {datatype, string} ]}. @@ -1890,6 +1895,7 @@ end}. {ciphers, Ciphers}, {user_lookup_fun, UserLookupFun}, {handshake_timeout, cuttlefish:conf_get(Prefix ++ ".handshake_timeout", Conf, undefined)}, + {depth, cuttlefish:conf_get(Prefix ++ ".depth", Conf, undefined)}, {dhfile, cuttlefish:conf_get(Prefix ++ ".dhfile", Conf, undefined)}, {keyfile, cuttlefish:conf_get(Prefix ++ ".keyfile", Conf, undefined)}, {certfile, cuttlefish:conf_get(Prefix ++ ".certfile", Conf, undefined)}, From 40d272815a73833032f24586f333133f223296ed Mon Sep 17 00:00:00 2001 From: JianBo He Date: Wed, 2 Dec 2020 14:07:55 +0800 Subject: [PATCH 17/41] refactor(limiter): not saving anonymous function --- src/emqx_limiter.erl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/emqx_limiter.erl b/src/emqx_limiter.erl index e3ff7512f..26172f761 100644 --- a/src/emqx_limiter.erl +++ b/src/emqx_limiter.erl @@ -35,7 +35,7 @@ -type(checker() :: #{ name := name() , capacity := non_neg_integer() , interval := non_neg_integer() - , consumer := function() | esockd_rate_limit:bucket() + , consumer := esockd_rate_limit:bucket() | emqx_zone:zone() }). -type(name() :: conn_bytes_in @@ -84,7 +84,7 @@ do_init_checker(Zone, {Name, {Capacity, Interval}}) -> _ -> esockd_limiter:create({Zone, Name}, Capacity, Interval) end, - Ck#{consumer => fun(I) -> esockd_limiter:consume({Zone, Name}, I) end}; + Ck#{consumer => Zone}; _ -> Ck#{consumer => esockd_rate_limit:new(Capacity / Interval, Capacity)} end. @@ -126,7 +126,13 @@ consume(Pubs, Bytes, #{name := Name, consumer := Cons}) -> _ -> case is_overall_limiter(Name) of true -> - {_, Intv} = Cons(Tokens), + {_, Intv} = case erlang:is_function(Cons) of + true -> %% Compatible with hot-upgrade from e4.2.0, e4.2.1. + %% It should be removed after 4.3.0 + {env, [Zone|_]} = erlang:fun_info(Cons, env), + esockd_limiter:consume({Zone, Name}, Tokens); + _ -> esockd_limiter:consume({Cons, Name}, Tokens) + end, {Intv, Cons}; _ -> esockd_rate_limit:check(Tokens, Cons) From 80c503fd64f73ac8b2650c9afa5bdee72c3121f4 Mon Sep 17 00:00:00 2001 From: JianBo He Date: Wed, 2 Dec 2020 17:00:23 +0800 Subject: [PATCH 18/41] refactor(conn): not saving anonymous func --- src/emqx.appup.src | 37 +++++++++-- src/emqx_connection.erl | 10 +-- src/emqx_frame.erl | 124 +++++++++++++++++++++++++++++++++++++ src/emqx_limiter.erl | 2 + src/emqx_ws_connection.erl | 10 +-- test/emqx_frame_SUITE.erl | 15 ++++- 6 files changed, 182 insertions(+), 16 deletions(-) diff --git a/src/emqx.appup.src b/src/emqx.appup.src index 9a9d221aa..8070ffc13 100644 --- a/src/emqx.appup.src +++ b/src/emqx.appup.src @@ -1,20 +1,47 @@ +%% -*-: erlang -*- + {VSN, [ {"4.2.0", [ {load_module, emqx_alarm, brutal_purge, soft_purge, []}, - {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, {load_module, emqx_channel, brutal_purge, soft_purge, []}, - {load_module, emqx_metrics, brutal_purge, soft_purge, []} + {load_module, emqx_metrics, brutal_purge, soft_purge, []}, + {load_module, emqx_limiter, brutal_purge, soft_purge, []}, + {suspend, [emqx_connection, emqx_ws_connection]}, + {load_module, emqx_frame, brutal_purge, soft_purge, []}, + {update, emqx_connection, {advanced, []}}, + {update, emqx_ws_connection, {advanced, []}}, + {resume, [emqx_connection, emqx_ws_connection]} + ]}, + {"4.2.1", [ + {load_module, emqx_limiter, brutal_purge, soft_purge, []}, + {suspend, [emqx_connection, emqx_ws_connection]}, + {load_module, emqx_frame, brutal_purge, soft_purge, []}, + {update, emqx_connection, {advanced, []}}, + {update, emqx_ws_connection, {advanced, []}}, + {resume, [emqx_connection, emqx_ws_connection]} ]}, {<<".*">>, []} ], [ - {"4.2.1", []}, {"4.2.0", [ {load_module, emqx_alarm, brutal_purge, soft_purge, []}, - {load_module, emqx_connection, brutal_purge, soft_purge, [emqx_channel]}, {load_module, emqx_channel, brutal_purge, soft_purge, []}, - {load_module, emqx_metrics, brutal_purge, soft_purge, []} + {load_module, emqx_metrics, brutal_purge, soft_purge, []}, + {load_module, emqx_limiter, brutal_purge, soft_purge, []}, + {suspend, [emqx_connection, emqx_ws_connection]}, + {load_module, emqx_frame, brutal_purge, soft_purge, []}, + {update, emqx_connection, {advanced, []}}, + {update, emqx_ws_connection, {advanced, []}}, + {resume, [emqx_connection, emqx_ws_connection]} + ]}, + {"4.2.1", [ + {load_module, emqx_limiter, brutal_purge, soft_purge, []}, + {suspend, [emqx_connection, emqx_ws_connection]}, + {load_module, emqx_frame, brutal_purge, soft_purge, []}, + {update, emqx_connection, {advanced, []}}, + {update, emqx_ws_connection, {advanced, []}}, + {resume, [emqx_connection, emqx_ws_connection]} ]}, {<<".*">>, []} ] diff --git a/src/emqx_connection.erl b/src/emqx_connection.erl index 3078ebd91..6f66386bc 100644 --- a/src/emqx_connection.erl +++ b/src/emqx_connection.erl @@ -80,8 +80,8 @@ limit_timer :: maybe(reference()), %% Parse State parse_state :: emqx_frame:parse_state(), - %% Serialize function - serialize :: emqx_frame:serialize_fun(), + %% Serialize options + serialize :: emqx_frame:serialize_opts(), %% Channel State channel :: emqx_channel:channel(), %% GC State @@ -214,7 +214,7 @@ init_state(Transport, Socket, Options) -> Limiter = emqx_limiter:init(Zone, PubLimit, BytesIn, RateLimit), FrameOpts = emqx_zone:mqtt_frame_options(Zone), ParseState = emqx_frame:initial_parse_state(FrameOpts), - Serialize = emqx_frame:serialize_fun(), + Serialize = emqx_frame:serialize_opts(), Channel = emqx_channel:init(ConnInfo, Options), GcState = emqx_zone:init_gc_state(Zone), StatsTimer = emqx_zone:stats_timer(Zone), @@ -348,7 +348,7 @@ handle_msg({Inet, _Sock, Data}, State) when Inet == tcp; Inet == ssl -> handle_msg({incoming, Packet = ?CONNECT_PACKET(ConnPkt)}, State = #state{idle_timer = IdleTimer}) -> ok = emqx_misc:cancel_timer(IdleTimer), - Serialize = emqx_frame:serialize_fun(ConnPkt), + Serialize = emqx_frame:serialize_opts(ConnPkt), NState = State#state{serialize = Serialize, idle_timer = undefined }, @@ -590,7 +590,7 @@ handle_outgoing(Packet, State) -> serialize_and_inc_stats_fun(#state{serialize = Serialize}) -> fun(Packet) -> - case Serialize(Packet) of + case emqx_frame:serialize_pkt(Packet, Serialize) of <<>> -> ?LOG(warning, "~s is discarded due to the frame is too large!", [emqx_packet:format(Packet)]), ok = emqx_metrics:inc('delivery.dropped.too_large'), diff --git a/src/emqx_frame.erl b/src/emqx_frame.erl index 1c27548f7..cd41a935c 100644 --- a/src/emqx_frame.erl +++ b/src/emqx_frame.erl @@ -31,26 +31,53 @@ , serialize/2 ]). +%% The new version APIs to avoid saving +%% anonymous func +-export([ parse2/1 + , parse2/2 + , serialize_opts/0 + , serialize_opts/1 + , serialize_pkt/2 + ]). + -export_type([ options/0 , parse_state/0 , parse_result/0 , serialize_fun/0 ]). +-export_type([ parse_state2/0 + , parse_result2/0 + , serialize_opts/0 + ]). + -type(options() :: #{strict_mode => boolean(), max_size => 1..?MAX_PACKET_SIZE, version => emqx_types:version() }). -type(parse_state() :: {none, options()} | cont_fun()). +-type(parse_state2() :: {none, options()} | {cont_state(), options()}). -type(parse_result() :: {more, cont_fun()} | {ok, emqx_types:packet(), binary(), parse_state()}). +-type(parse_result2() :: {more, parse_state()} + | {ok, emqx_types:packet(), binary(), parse_state()}). + -type(cont_fun() :: fun((binary()) -> parse_result())). +-type(cont_state() :: {Stage :: len | body, + State :: #{hdr := #mqtt_packet_header{}, + len := {pos_integer(), non_neg_integer()} | non_neg_integer(), + rest => binary() + } + }). + -type(serialize_fun() :: fun((emqx_types:packet()) -> iodata())). +-type(serialize_opts() :: options()). + -define(none(Options), {none, Options}). -define(DEFAULT_OPTIONS, @@ -81,6 +108,89 @@ merge_opts(Options) -> %% Parse MQTT Frame %%-------------------------------------------------------------------- +-spec(parse2(binary()) -> parse_result2()). +parse2(Bin) -> + parse2(Bin, initial_parse_state()). + +-spec(parse2(binary(), parse_state()) -> parse_result2()). +parse2(<<>>, {none, Options}) -> + {more, {none, Options}}; +parse2(<>, + {none, Options = #{strict_mode := StrictMode}}) -> + %% Validate header if strict mode. + StrictMode andalso validate_header(Type, Dup, QoS, Retain), + Header = #mqtt_packet_header{type = Type, + dup = bool(Dup), + qos = QoS, + retain = bool(Retain) + }, + Header1 = case fixqos(Type, QoS) of + QoS -> Header; + FixedQoS -> Header#mqtt_packet_header{qos = FixedQoS} + end, + parse_remaining_len2(Rest, Header1, Options); + +parse2(Bin, {{len, #{hdr := Header, + len := {Multiplier, Length}} + }, Options}) when is_binary(Bin) -> + parse_remaining_len2(Bin, Header, Multiplier, Length, Options); +parse2(Bin, {{body, #{hdr := Header, + len := Length, + rest := Rest} + }, Options}) when is_binary(Bin) -> + parse_frame2(<>, Header, Length, Options). + +parse_remaining_len2(<<>>, Header, Options) -> + {more, {{len, #{hdr => Header, len => {1, 0}}}, Options}}; +parse_remaining_len2(Rest, Header, Options) -> + parse_remaining_len2(Rest, Header, 1, 0, Options). + +parse_remaining_len2(_Bin, _Header, _Multiplier, Length, #{max_size := MaxSize}) + when Length > MaxSize -> + error(frame_too_large); +parse_remaining_len2(<<>>, Header, Multiplier, Length, Options) -> + {more, {{len, #{hdr => Header, len => {Multiplier, Length}}}, Options}}; +%% Match DISCONNECT without payload +parse_remaining_len2(<<0:8, Rest/binary>>, Header = #mqtt_packet_header{type = ?DISCONNECT}, 1, 0, Options) -> + Packet = packet(Header, #mqtt_packet_disconnect{reason_code = ?RC_SUCCESS}), + {ok, Packet, Rest, ?none(Options)}; +%% Match PINGREQ. +parse_remaining_len2(<<0:8, Rest/binary>>, Header, 1, 0, Options) -> + parse_frame2(Rest, Header, 0, Options); +%% Match PUBACK, PUBREC, PUBREL, PUBCOMP, UNSUBACK... +parse_remaining_len2(<<0:1, 2:7, Rest/binary>>, Header, 1, 0, Options) -> + parse_frame2(Rest, Header, 2, Options); +parse_remaining_len2(<<1:1, Len:7, Rest/binary>>, Header, Multiplier, Value, Options) -> + parse_remaining_len2(Rest, Header, Multiplier * ?HIGHBIT, Value + Len * Multiplier, Options); +parse_remaining_len2(<<0:1, Len:7, Rest/binary>>, Header, Multiplier, Value, + Options = #{max_size := MaxSize}) -> + FrameLen = Value + Len * Multiplier, + if + FrameLen > MaxSize -> error(frame_too_large); + true -> parse_frame2(Rest, Header, FrameLen, Options) + end. + +parse_frame2(Bin, Header, 0, Options) -> + {ok, packet(Header), Bin, ?none(Options)}; + +parse_frame2(Bin, Header, Length, Options) -> + case Bin of + <> -> + case parse_packet(Header, FrameBin, Options) of + {Variable, Payload} -> + {ok, packet(Header, Variable, Payload), Rest, ?none(Options)}; + Variable = #mqtt_packet_connect{proto_ver = Ver} -> + {ok, packet(Header, Variable), Rest, ?none(Options#{version := Ver})}; + Variable -> + {ok, packet(Header, Variable), Rest, ?none(Options)} + end; + TooShortBin -> + {more, {{body, #{hdr => Header, len => Length, rest => TooShortBin}}, Options}} + end. + +%% Deprecated parse funcs +%% It should be removed after 4.2.x + -spec(parse(binary()) -> parse_result()). parse(Bin) -> parse(Bin, initial_parse_state()). @@ -443,6 +553,20 @@ serialize_fun(#{version := Ver, max_size := MaxSize}) -> end end. +serialize_opts() -> + ?DEFAULT_OPTIONS. + +serialize_opts(#mqtt_packet_connect{proto_ver = ProtoVer, properties = ConnProps}) -> + MaxSize = get_property('Maximum-Packet-Size', ConnProps, ?MAX_PACKET_SIZE), + #{version => ProtoVer, max_size => MaxSize}. + +serialize_pkt(Packet, #{version := Ver, max_size := MaxSize}) -> + IoData = serialize(Packet, Ver), + case is_too_large(IoData, MaxSize) of + true -> <<>>; + false -> IoData + end. + -spec(serialize(emqx_types:packet()) -> iodata()). serialize(Packet) -> serialize(Packet, ?MQTT_PROTO_V4). diff --git a/src/emqx_limiter.erl b/src/emqx_limiter.erl index 26172f761..fad897d92 100644 --- a/src/emqx_limiter.erl +++ b/src/emqx_limiter.erl @@ -53,6 +53,8 @@ -type(limiter() :: #limiter{}). +-dialyzer({nowarn_function, [consume/3]}). + %%-------------------------------------------------------------------- %% APIs %%-------------------------------------------------------------------- diff --git a/src/emqx_ws_connection.erl b/src/emqx_ws_connection.erl index 33b882768..ee0e24dbb 100644 --- a/src/emqx_ws_connection.erl +++ b/src/emqx_ws_connection.erl @@ -70,8 +70,8 @@ limit_timer :: maybe(reference()), %% Parse State parse_state :: emqx_frame:parse_state(), - %% Serialize Fun - serialize :: emqx_frame:serialize_fun(), + %% Serialize options + serialize :: emqx_frame:serialize_opts(), %% Channel channel :: emqx_channel:channel(), %% GC State @@ -231,7 +231,7 @@ websocket_init([Req, Opts]) -> MQTTPiggyback = proplists:get_value(mqtt_piggyback, Opts, multiple), FrameOpts = emqx_zone:mqtt_frame_options(Zone), ParseState = emqx_frame:initial_parse_state(FrameOpts), - Serialize = emqx_frame:serialize_fun(), + Serialize = emqx_frame:serialize_opts(), Channel = emqx_channel:init(ConnInfo, Opts), GcState = emqx_zone:init_gc_state(Zone), StatsTimer = emqx_zone:stats_timer(Zone), @@ -292,7 +292,7 @@ websocket_info({cast, Msg}, State) -> handle_info(Msg, State); websocket_info({incoming, Packet = ?CONNECT_PACKET(ConnPkt)}, State) -> - Serialize = emqx_frame:serialize_fun(ConnPkt), + Serialize = emqx_frame:serialize_opts(ConnPkt), NState = State#state{serialize = Serialize}, handle_incoming(Packet, cancel_idle_timer(NState)); @@ -544,7 +544,7 @@ handle_outgoing(Packets, State = #state{active_n = ActiveN, mqtt_piggyback = MQT serialize_and_inc_stats_fun(#state{serialize = Serialize}) -> fun(Packet) -> - case Serialize(Packet) of + case emqx_frame:serialize_pkt(Packet, Serialize) of <<>> -> ?LOG(warning, "~s is discarded due to the frame is too large.", [emqx_packet:format(Packet)]), ok = emqx_metrics:inc('delivery.dropped.too_large'), diff --git a/test/emqx_frame_SUITE.erl b/test/emqx_frame_SUITE.erl index 5d4e146db..7ef60bc69 100644 --- a/test/emqx_frame_SUITE.erl +++ b/test/emqx_frame_SUITE.erl @@ -26,6 +26,7 @@ all() -> [{group, parse}, + {group, parse2}, {group, connect}, {group, connack}, {group, publish}, @@ -44,6 +45,8 @@ groups() -> [t_parse_cont, t_parse_frame_too_large ]}, + {parse2, [parallel], + [t_parse_cont2]}, {connect, [parallel], [t_serialize_parse_v3_connect, t_serialize_parse_v4_connect, @@ -129,6 +132,16 @@ t_parse_frame_too_large(_) -> ?catch_error(frame_too_large, parse_serialize(Packet, #{max_size => 512})), ?assertEqual(Packet, parse_serialize(Packet, #{max_size => 2048, version => ?MQTT_PROTO_V4})). +t_parse_cont2(_) -> + Packet = ?CONNECT_PACKET(#mqtt_packet_connect{}), + ParseState = emqx_frame:initial_parse_state(), + <> = serialize_to_binary(Packet), + {more, ContParse} = emqx_frame:parse2(<<>>, ParseState), + {more, ContParse1} = emqx_frame:parse2(HdrBin, ContParse), + {more, ContParse2} = emqx_frame:parse2(LenBin, ContParse1), + {more, ContParse3} = emqx_frame:parse2(<<>>, ContParse2), + {ok, Packet, <<>>, _} = emqx_frame:parse2(RestBin, ContParse3). + t_serialize_parse_v3_connect(_) -> Bin = <<16,37,0,6,77,81,73,115,100,112,3,2,0,60,0,23,109,111,115, 113,112,117, 98,47,49,48,52,53,49,45,105,77,97,99,46,108, @@ -509,7 +522,7 @@ parse_serialize(Packet, Opts) when is_map(Opts) -> Ver = maps:get(version, Opts, ?MQTT_PROTO_V4), Bin = iolist_to_binary(emqx_frame:serialize(Packet, Ver)), ParseState = emqx_frame:initial_parse_state(Opts), - {ok, NPacket, <<>>, _} = emqx_frame:parse(Bin, ParseState), + {ok, NPacket, <<>>, _} = emqx_frame:parse2(Bin, ParseState), NPacket. serialize_to_binary(Packet) -> From ca0f6b69a447a245345bf9d1854dbafe8781546d Mon Sep 17 00:00:00 2001 From: JianBo He Date: Wed, 2 Dec 2020 17:52:36 +0800 Subject: [PATCH 19/41] chore: supply the code_change logic --- rebar.config | 2 +- src/emqx_connection.erl | 56 ++++++++++++++++ src/emqx_frame.erl | 133 ++++++-------------------------------- src/emqx_limiter.erl | 8 +-- test/emqx_frame_SUITE.erl | 15 +---- test/emqx_vm_SUITE.erl | 2 +- 6 files changed, 78 insertions(+), 138 deletions(-) diff --git a/rebar.config b/rebar.config index df71f9762..fc3a95ce2 100644 --- a/rebar.config +++ b/rebar.config @@ -40,7 +40,7 @@ [{plugins, [{coveralls, {git, "https://github.com/emqx/coveralls-erl", {branch, "github"}}}]}, {deps, [{bbmustache, "1.7.0"}, - {emqtt, {git, "https://github.com/emqx/emqtt", {tag, "1.2.0"}}}, + {emqtt, {git, "https://github.com/emqx/emqtt", {tag, "1.2.3"}}}, {emqx_ct_helpers, {git, "https://github.com/emqx/emqx-ct-helpers", {tag, "1.3.0"}}} ]}, {erl_opts, [debug_info]} diff --git a/src/emqx_connection.erl b/src/emqx_connection.erl index 6f66386bc..7d055a14e 100644 --- a/src/emqx_connection.erl +++ b/src/emqx_connection.erl @@ -453,6 +453,62 @@ system_continue(Parent, _Debug, State) -> system_terminate(Reason, _Parent, _Debug, State) -> terminate(Reason, State). +system_code_change(State, _Mod, {down, Vsn}, _Extra) + when Vsn == "4.2.0"; + Vsn == "4.2.1" -> + Channel = State#state.channel, + NSerialize = emqx_frame:serialize_fun(State#state.serialize), + case {State#state.parse_state, element(10, Channel)} of + {{none, _}, undefined} -> + {ok, State#state{serialize = NSerialize}}; + {Ps, Quota} -> + %% BACKW: e4.2.0-e4.2.1 + %% We can't recover/reconstruct anonymous function state for + %% Parser or Quota consumer. So just close it. + ?LOG(error, "Unsupport downgrade connection ~0p, peername: ~0p." + " Due to it have an incomplete frame or unsafed quota counter," + " parser_state: ~0p, quota: ~0p." + " Force close it now!!!", [self(), State#state.peername, Ps, Quota]), + self() ! {close, unsupported_downgrade_connection_state}, + {ok, State#state{serialize = NSerialize}} + end; + +system_code_change(State, _Mod, Vsn, _Extra) + when Vsn == "4.2.0"; + Vsn == "4.2.1" -> + Channel = State#state.channel, + NChannel = + case element(10, Channel) of + undefined -> Channel; + Quoter -> + Zone = element(2, Quoter), + Cks = element(3, Quoter), + NCks = [case Name == overall_messages_routing of + true -> Ck#{consumer => Zone}; + _ -> Ck + end || Ck = #{name := Name} <- Cks], + setelement(10, Channel, setelement(3, Quoter, NCks)) + end, + + NParseState = + case State#state.parse_state of + Ps = {none, _} -> Ps; + Ps when is_function(Ps) -> + case erlang:fun_info(Ps, env) of + {_, [Hdr, Opts]} -> + {{len, #{hdr => Hdr, len => {1,0}}}, Opts}; + {_, [Bin, Hdr, Len, Opts]} when is_binary(Bin) -> + {{body, #{hdr => Hdr, len => Len, rest => Bin}}, Opts}; + {_, [Hdr, Multip, Len, Opts]} -> + {{len, #{hdr => Hdr, len => {Multip, Len}}}, Opts} + end + end, + + {_, [Ver, MaxSize]} = erlang:fun_info(State#state.serialize, env), + NSerialize = #{version => Ver, max_size => MaxSize}, + + {ok, State#state{channel = NChannel, parse_state = NParseState, serialize = NSerialize}}; + system_code_change(State, _Mod, _OldVsn, _Extra) -> {ok, State}. diff --git a/src/emqx_frame.erl b/src/emqx_frame.erl index cd41a935c..d09b8416e 100644 --- a/src/emqx_frame.erl +++ b/src/emqx_frame.erl @@ -27,27 +27,16 @@ , parse/2 , serialize_fun/0 , serialize_fun/1 - , serialize/1 - , serialize/2 - ]). - -%% The new version APIs to avoid saving -%% anonymous func --export([ parse2/1 - , parse2/2 , serialize_opts/0 , serialize_opts/1 , serialize_pkt/2 + , serialize/1 + , serialize/2 ]). -export_type([ options/0 , parse_state/0 , parse_result/0 - , serialize_fun/0 - ]). - --export_type([ parse_state2/0 - , parse_result2/0 , serialize_opts/0 ]). @@ -56,17 +45,11 @@ version => emqx_types:version() }). --type(parse_state() :: {none, options()} | cont_fun()). --type(parse_state2() :: {none, options()} | {cont_state(), options()}). +-type(parse_state() :: {none, options()} | {cont_state(), options()}). --type(parse_result() :: {more, cont_fun()} +-type(parse_result() :: {more, parse_state()} | {ok, emqx_types:packet(), binary(), parse_state()}). --type(parse_result2() :: {more, parse_state()} - | {ok, emqx_types:packet(), binary(), parse_state()}). - --type(cont_fun() :: fun((binary()) -> parse_result())). - -type(cont_state() :: {Stage :: len | body, State :: #{hdr := #mqtt_packet_header{}, len := {pos_integer(), non_neg_integer()} | non_neg_integer(), @@ -74,8 +57,6 @@ } }). --type(serialize_fun() :: fun((emqx_types:packet()) -> iodata())). - -type(serialize_opts() :: options()). -define(none(Options), {none, Options}). @@ -108,96 +89,13 @@ merge_opts(Options) -> %% Parse MQTT Frame %%-------------------------------------------------------------------- --spec(parse2(binary()) -> parse_result2()). -parse2(Bin) -> - parse2(Bin, initial_parse_state()). - --spec(parse2(binary(), parse_state()) -> parse_result2()). -parse2(<<>>, {none, Options}) -> - {more, {none, Options}}; -parse2(<>, - {none, Options = #{strict_mode := StrictMode}}) -> - %% Validate header if strict mode. - StrictMode andalso validate_header(Type, Dup, QoS, Retain), - Header = #mqtt_packet_header{type = Type, - dup = bool(Dup), - qos = QoS, - retain = bool(Retain) - }, - Header1 = case fixqos(Type, QoS) of - QoS -> Header; - FixedQoS -> Header#mqtt_packet_header{qos = FixedQoS} - end, - parse_remaining_len2(Rest, Header1, Options); - -parse2(Bin, {{len, #{hdr := Header, - len := {Multiplier, Length}} - }, Options}) when is_binary(Bin) -> - parse_remaining_len2(Bin, Header, Multiplier, Length, Options); -parse2(Bin, {{body, #{hdr := Header, - len := Length, - rest := Rest} - }, Options}) when is_binary(Bin) -> - parse_frame2(<>, Header, Length, Options). - -parse_remaining_len2(<<>>, Header, Options) -> - {more, {{len, #{hdr => Header, len => {1, 0}}}, Options}}; -parse_remaining_len2(Rest, Header, Options) -> - parse_remaining_len2(Rest, Header, 1, 0, Options). - -parse_remaining_len2(_Bin, _Header, _Multiplier, Length, #{max_size := MaxSize}) - when Length > MaxSize -> - error(frame_too_large); -parse_remaining_len2(<<>>, Header, Multiplier, Length, Options) -> - {more, {{len, #{hdr => Header, len => {Multiplier, Length}}}, Options}}; -%% Match DISCONNECT without payload -parse_remaining_len2(<<0:8, Rest/binary>>, Header = #mqtt_packet_header{type = ?DISCONNECT}, 1, 0, Options) -> - Packet = packet(Header, #mqtt_packet_disconnect{reason_code = ?RC_SUCCESS}), - {ok, Packet, Rest, ?none(Options)}; -%% Match PINGREQ. -parse_remaining_len2(<<0:8, Rest/binary>>, Header, 1, 0, Options) -> - parse_frame2(Rest, Header, 0, Options); -%% Match PUBACK, PUBREC, PUBREL, PUBCOMP, UNSUBACK... -parse_remaining_len2(<<0:1, 2:7, Rest/binary>>, Header, 1, 0, Options) -> - parse_frame2(Rest, Header, 2, Options); -parse_remaining_len2(<<1:1, Len:7, Rest/binary>>, Header, Multiplier, Value, Options) -> - parse_remaining_len2(Rest, Header, Multiplier * ?HIGHBIT, Value + Len * Multiplier, Options); -parse_remaining_len2(<<0:1, Len:7, Rest/binary>>, Header, Multiplier, Value, - Options = #{max_size := MaxSize}) -> - FrameLen = Value + Len * Multiplier, - if - FrameLen > MaxSize -> error(frame_too_large); - true -> parse_frame2(Rest, Header, FrameLen, Options) - end. - -parse_frame2(Bin, Header, 0, Options) -> - {ok, packet(Header), Bin, ?none(Options)}; - -parse_frame2(Bin, Header, Length, Options) -> - case Bin of - <> -> - case parse_packet(Header, FrameBin, Options) of - {Variable, Payload} -> - {ok, packet(Header, Variable, Payload), Rest, ?none(Options)}; - Variable = #mqtt_packet_connect{proto_ver = Ver} -> - {ok, packet(Header, Variable), Rest, ?none(Options#{version := Ver})}; - Variable -> - {ok, packet(Header, Variable), Rest, ?none(Options)} - end; - TooShortBin -> - {more, {{body, #{hdr => Header, len => Length, rest => TooShortBin}}, Options}} - end. - -%% Deprecated parse funcs -%% It should be removed after 4.2.x - -spec(parse(binary()) -> parse_result()). parse(Bin) -> parse(Bin, initial_parse_state()). -spec(parse(binary(), parse_state()) -> parse_result()). parse(<<>>, {none, Options}) -> - {more, fun(Bin) -> parse(Bin, {none, Options}) end}; + {more, {none, Options}}; parse(<>, {none, Options = #{strict_mode := StrictMode}}) -> %% Validate header if strict mode. @@ -212,11 +110,19 @@ parse(<>, FixedQoS -> Header#mqtt_packet_header{qos = FixedQoS} end, parse_remaining_len(Rest, Header1, Options); -parse(Bin, Cont) when is_binary(Bin), is_function(Cont) -> - Cont(Bin). + +parse(Bin, {{len, #{hdr := Header, + len := {Multiplier, Length}} + }, Options}) when is_binary(Bin) -> + parse_remaining_len(Bin, Header, Multiplier, Length, Options); +parse(Bin, {{body, #{hdr := Header, + len := Length, + rest := Rest} + }, Options}) when is_binary(Bin) -> + parse_frame(<>, Header, Length, Options). parse_remaining_len(<<>>, Header, Options) -> - {more, fun(Bin) -> parse_remaining_len(Bin, Header, Options) end}; + {more, {{len, #{hdr => Header, len => {1, 0}}}, Options}}; parse_remaining_len(Rest, Header, Options) -> parse_remaining_len(Rest, Header, 1, 0, Options). @@ -224,7 +130,7 @@ parse_remaining_len(_Bin, _Header, _Multiplier, Length, #{max_size := MaxSize}) when Length > MaxSize -> error(frame_too_large); parse_remaining_len(<<>>, Header, Multiplier, Length, Options) -> - {more, fun(Bin) -> parse_remaining_len(Bin, Header, Multiplier, Length, Options) end}; + {more, {{len, #{hdr => Header, len => {Multiplier, Length}}}, Options}}; %% Match DISCONNECT without payload parse_remaining_len(<<0:8, Rest/binary>>, Header = #mqtt_packet_header{type = ?DISCONNECT}, 1, 0, Options) -> Packet = packet(Header, #mqtt_packet_disconnect{reason_code = ?RC_SUCCESS}), @@ -260,9 +166,7 @@ parse_frame(Bin, Header, Length, Options) -> {ok, packet(Header, Variable), Rest, ?none(Options)} end; TooShortBin -> - {more, fun(BinMore) -> - parse_frame(<>, Header, Length, Options) - end} + {more, {{body, #{hdr => Header, len => Length, rest => TooShortBin}}, Options}} end. -compile({inline, [packet/1, packet/2, packet/3]}). @@ -870,4 +774,3 @@ fixqos(?PUBREL, 0) -> 1; fixqos(?SUBSCRIBE, 0) -> 1; fixqos(?UNSUBSCRIBE, 0) -> 1; fixqos(_Type, QoS) -> QoS. - diff --git a/src/emqx_limiter.erl b/src/emqx_limiter.erl index fad897d92..447e04fea 100644 --- a/src/emqx_limiter.erl +++ b/src/emqx_limiter.erl @@ -128,13 +128,7 @@ consume(Pubs, Bytes, #{name := Name, consumer := Cons}) -> _ -> case is_overall_limiter(Name) of true -> - {_, Intv} = case erlang:is_function(Cons) of - true -> %% Compatible with hot-upgrade from e4.2.0, e4.2.1. - %% It should be removed after 4.3.0 - {env, [Zone|_]} = erlang:fun_info(Cons, env), - esockd_limiter:consume({Zone, Name}, Tokens); - _ -> esockd_limiter:consume({Cons, Name}, Tokens) - end, + {_, Intv} = esockd_limiter:consume({Cons, Name}, Tokens), {Intv, Cons}; _ -> esockd_rate_limit:check(Tokens, Cons) diff --git a/test/emqx_frame_SUITE.erl b/test/emqx_frame_SUITE.erl index 7ef60bc69..5d4e146db 100644 --- a/test/emqx_frame_SUITE.erl +++ b/test/emqx_frame_SUITE.erl @@ -26,7 +26,6 @@ all() -> [{group, parse}, - {group, parse2}, {group, connect}, {group, connack}, {group, publish}, @@ -45,8 +44,6 @@ groups() -> [t_parse_cont, t_parse_frame_too_large ]}, - {parse2, [parallel], - [t_parse_cont2]}, {connect, [parallel], [t_serialize_parse_v3_connect, t_serialize_parse_v4_connect, @@ -132,16 +129,6 @@ t_parse_frame_too_large(_) -> ?catch_error(frame_too_large, parse_serialize(Packet, #{max_size => 512})), ?assertEqual(Packet, parse_serialize(Packet, #{max_size => 2048, version => ?MQTT_PROTO_V4})). -t_parse_cont2(_) -> - Packet = ?CONNECT_PACKET(#mqtt_packet_connect{}), - ParseState = emqx_frame:initial_parse_state(), - <> = serialize_to_binary(Packet), - {more, ContParse} = emqx_frame:parse2(<<>>, ParseState), - {more, ContParse1} = emqx_frame:parse2(HdrBin, ContParse), - {more, ContParse2} = emqx_frame:parse2(LenBin, ContParse1), - {more, ContParse3} = emqx_frame:parse2(<<>>, ContParse2), - {ok, Packet, <<>>, _} = emqx_frame:parse2(RestBin, ContParse3). - t_serialize_parse_v3_connect(_) -> Bin = <<16,37,0,6,77,81,73,115,100,112,3,2,0,60,0,23,109,111,115, 113,112,117, 98,47,49,48,52,53,49,45,105,77,97,99,46,108, @@ -522,7 +509,7 @@ parse_serialize(Packet, Opts) when is_map(Opts) -> Ver = maps:get(version, Opts, ?MQTT_PROTO_V4), Bin = iolist_to_binary(emqx_frame:serialize(Packet, Ver)), ParseState = emqx_frame:initial_parse_state(Opts), - {ok, NPacket, <<>>, _} = emqx_frame:parse2(Bin, ParseState), + {ok, NPacket, <<>>, _} = emqx_frame:parse(Bin, ParseState), NPacket. serialize_to_binary(Packet) -> diff --git a/test/emqx_vm_SUITE.erl b/test/emqx_vm_SUITE.erl index 19545f0ea..4bc231ad0 100644 --- a/test/emqx_vm_SUITE.erl +++ b/test/emqx_vm_SUITE.erl @@ -80,7 +80,7 @@ t_get_port_info(_Config) -> {ok, Sock} = gen_tcp:connect("localhost", 5678, [binary, {packet, 0}]), emqx_vm:get_port_info(), ok = gen_tcp:close(Sock), - [Port | _] = erlang:ports(). + [_Port | _] = erlang:ports(). t_transform_port(_Config) -> [Port | _] = erlang:ports(), From 7462ed92baea3935109591b581533de559f18cc9 Mon Sep 17 00:00:00 2001 From: JianBo He Date: Thu, 3 Dec 2020 17:13:06 +0800 Subject: [PATCH 20/41] chore: eliminate diaylzer warnings --- src/emqx_connection.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/emqx_connection.erl b/src/emqx_connection.erl index 7d055a14e..6e8ed9a46 100644 --- a/src/emqx_connection.erl +++ b/src/emqx_connection.erl @@ -119,6 +119,7 @@ , init_state/3 , run_loop/2 , system_terminate/4 + , system_code_change/4 ]}). -spec(start_link(esockd:transport(), esockd:socket(), proplists:proplist()) From f8369f5280890319be3b1749f0631c64c3f094a7 Mon Sep 17 00:00:00 2001 From: Turtle Date: Fri, 4 Dec 2020 21:39:27 +0800 Subject: [PATCH 21/41] test: comment the will message cases --- test/mqtt_protocol_v5_SUITE.erl | 110 +++++++++++++++++--------------- 1 file changed, 57 insertions(+), 53 deletions(-) diff --git a/test/mqtt_protocol_v5_SUITE.erl b/test/mqtt_protocol_v5_SUITE.erl index f0a0cc3dc..2291605e0 100644 --- a/test/mqtt_protocol_v5_SUITE.erl +++ b/test/mqtt_protocol_v5_SUITE.erl @@ -328,59 +328,63 @@ t_connect_session_expiry_interval(_) -> ok = emqtt:disconnect(Client3). %% [MQTT-3.1.3-9] -t_connect_will_delay_interval(_) -> - process_flag(trap_exit, true), - Topic = nth(1, ?TOPICS), - Payload = "will message", - - {ok, Client1} = emqtt:start_link([{proto_ver, v5}]), - {ok, _} = emqtt:connect(Client1), - {ok, _, [2]} = emqtt:subscribe(Client1, Topic, qos2), - - {ok, Client2} = emqtt:start_link([ - {clientid, <<"t_connect_will_delay_interval">>}, - {proto_ver, v5}, - {clean_start, true}, - {will_flag, true}, - {will_qos, 2}, - {will_topic, Topic}, - {will_payload, Payload}, - {will_props, #{'Will-Delay-Interval' => 3}}, - {properties, #{'Session-Expiry-Interval' => 7200}}, - {keepalive, 2} - ]), - {ok, _} = emqtt:connect(Client2), - - timer:sleep(5000), - ?assertEqual(0, length(receive_messages(1))), - timer:sleep(7000), - ?assertEqual(1, length(receive_messages(1))), - - {ok, Client3} = emqtt:start_link([ - {clientid, <<"t_connect_will_delay_interval">>}, - {proto_ver, v5}, - {clean_start, true}, - {will_flag, true}, - {will_qos, 2}, - {will_topic, Topic}, - {will_payload, Payload}, - {will_props, #{'Will-Delay-Interval' => 7200}}, - {properties, #{'Session-Expiry-Interval' => 3}}, - {keepalive, 2} - ]), - {ok, _} = emqtt:connect(Client3), - - timer:sleep(5000), - ?assertEqual(0, length(receive_messages(1))), - timer:sleep(7000), - ?assertEqual(1, length(receive_messages(1))), - - ok = emqtt:disconnect(Client1), - - receive {'EXIT', _, _} -> ok - after 100 -> ok - end, - process_flag(trap_exit, false). +%% !!!REFACTOR NEED: +%t_connect_will_delay_interval(_) -> +% process_flag(trap_exit, true), +% Topic = nth(1, ?TOPICS), +% Payload = "will message", +% +% {ok, Client1} = emqtt:start_link([{proto_ver, v5}]), +% {ok, _} = emqtt:connect(Client1), +% {ok, _, [2]} = emqtt:subscribe(Client1, Topic, qos2), +% +% {ok, Client2} = emqtt:start_link([ +% {clientid, <<"t_connect_will_delay_interval">>}, +% {proto_ver, v5}, +% {clean_start, true}, +% {will_flag, true}, +% {will_qos, 2}, +% {will_topic, Topic}, +% {will_payload, Payload}, +% {will_props, #{'Will-Delay-Interval' => 3}}, +% {properties, #{'Session-Expiry-Interval' => 7200}}, +% {keepalive, 2} +% ]), +% {ok, _} = emqtt:connect(Client2), +% timer:sleep(50), +% erlang:exit(Client2, kill), +% timer:sleep(2000), +% ?assertEqual(0, length(receive_messages(1))), +% timer:sleep(5000), +% ?assertEqual(1, length(receive_messages(1))), +% +% {ok, Client3} = emqtt:start_link([ +% {clientid, <<"t_connect_will_delay_interval">>}, +% {proto_ver, v5}, +% {clean_start, true}, +% {will_flag, true}, +% {will_qos, 2}, +% {will_topic, Topic}, +% {will_payload, Payload}, +% {will_props, #{'Will-Delay-Interval' => 7200}}, +% {properties, #{'Session-Expiry-Interval' => 3}}, +% {keepalive, 2} +% ]), +% {ok, _} = emqtt:connect(Client3), +% timer:sleep(50), +% erlang:exit(Client3, kill), +% +% timer:sleep(2000), +% ?assertEqual(0, length(receive_messages(1))), +% timer:sleep(5000), +% ?assertEqual(1, length(receive_messages(1))), +% +% ok = emqtt:disconnect(Client1), +% +% receive {'EXIT', _, _} -> ok +% after 100 -> ok +% end, +% process_flag(trap_exit, false). %% [MQTT-3.1.4-3] t_connect_duplicate_clientid(_) -> From 042b75adc77066e692ea1e1ff2b0572d65fe715a Mon Sep 17 00:00:00 2001 From: zhouzb Date: Fri, 4 Dec 2020 10:45:55 +0800 Subject: [PATCH 22/41] fix(ekka): update ekka version to fix oom --- rebar.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rebar.config b/rebar.config index fc3a95ce2..a7ae1409f 100644 --- a/rebar.config +++ b/rebar.config @@ -7,7 +7,7 @@ {jiffy, {git, "https://github.com/emqx/jiffy", {tag, "1.0.5"}}}, {cowboy, {git, "https://github.com/emqx/cowboy", {tag, "2.7.1"}}}, {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.7.4"}}}, - {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.7.4"}}}, + {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.7.5"}}}, {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.5.0"}}}, {cuttlefish, {git, "https://github.com/emqx/cuttlefish", {tag, "v3.0.0"}}} ]}. From 2e7ec25ae292aa63be79b6e8edb51ec1b7582a08 Mon Sep 17 00:00:00 2001 From: JianBo He Date: Sat, 5 Dec 2020 15:04:14 +0800 Subject: [PATCH 23/41] chore(appup): suspend esockd_acceptor --- src/emqx.appup.src | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/emqx.appup.src b/src/emqx.appup.src index 8070ffc13..ed4b0695f 100644 --- a/src/emqx.appup.src +++ b/src/emqx.appup.src @@ -7,19 +7,19 @@ {load_module, emqx_channel, brutal_purge, soft_purge, []}, {load_module, emqx_metrics, brutal_purge, soft_purge, []}, {load_module, emqx_limiter, brutal_purge, soft_purge, []}, - {suspend, [emqx_connection, emqx_ws_connection]}, + {suspend, [esockd_acceptor,emqx_connection, emqx_ws_connection]}, {load_module, emqx_frame, brutal_purge, soft_purge, []}, {update, emqx_connection, {advanced, []}}, {update, emqx_ws_connection, {advanced, []}}, - {resume, [emqx_connection, emqx_ws_connection]} + {resume, [esockd_acceptor,emqx_connection, emqx_ws_connection]} ]}, {"4.2.1", [ {load_module, emqx_limiter, brutal_purge, soft_purge, []}, - {suspend, [emqx_connection, emqx_ws_connection]}, + {suspend, [esockd_acceptor, emqx_connection, emqx_ws_connection]}, {load_module, emqx_frame, brutal_purge, soft_purge, []}, {update, emqx_connection, {advanced, []}}, {update, emqx_ws_connection, {advanced, []}}, - {resume, [emqx_connection, emqx_ws_connection]} + {resume, [esockd_acceptor, emqx_connection, emqx_ws_connection]} ]}, {<<".*">>, []} ], @@ -29,19 +29,19 @@ {load_module, emqx_channel, brutal_purge, soft_purge, []}, {load_module, emqx_metrics, brutal_purge, soft_purge, []}, {load_module, emqx_limiter, brutal_purge, soft_purge, []}, - {suspend, [emqx_connection, emqx_ws_connection]}, + {suspend, [esockd_acceptor, emqx_connection, emqx_ws_connection]}, {load_module, emqx_frame, brutal_purge, soft_purge, []}, {update, emqx_connection, {advanced, []}}, {update, emqx_ws_connection, {advanced, []}}, - {resume, [emqx_connection, emqx_ws_connection]} + {resume, [esockd_acceptor, emqx_connection, emqx_ws_connection]} ]}, {"4.2.1", [ {load_module, emqx_limiter, brutal_purge, soft_purge, []}, - {suspend, [emqx_connection, emqx_ws_connection]}, + {suspend, [esockd_acceptor, emqx_connection, emqx_ws_connection]}, {load_module, emqx_frame, brutal_purge, soft_purge, []}, {update, emqx_connection, {advanced, []}}, {update, emqx_ws_connection, {advanced, []}}, - {resume, [emqx_connection, emqx_ws_connection]} + {resume, [esockd_acceptor, emqx_connection, emqx_ws_connection]} ]}, {<<".*">>, []} ] From 6c1129dc6afcc0bca2c9cbf984421a474300ac93 Mon Sep 17 00:00:00 2001 From: emqx-ci-robot <77955145+emqx-ci-robot@users.noreply.github.com> Date: Sat, 30 Jan 2021 10:30:18 +0800 Subject: [PATCH 24/41] Auto-pull-request-on-2021-01-29 (#4114) * fix(share sub): fix the issue that the number of subscriptions dropped to 0 during the picking subscriber and caused a crash * Connection Busy Alarms (#3992) feat(emqx_connection): improve port_busy alarm * fix(emqx_connection): tune the congestion alarm params * chore(deps): upgrade esockd to 5.7.5 * fix(appup): correct the appup file --- rebar.config | 2 +- src/emqx.appup.src | 38 +++++++- src/emqx_alarm.erl | 96 ++++++++++++-------- src/emqx_channel.erl | 44 +++++---- src/emqx_congestion.erl | 161 +++++++++++++++++++++++++++++++++ src/emqx_connection.erl | 81 ++++------------- src/emqx_os_mon.erl | 4 +- src/emqx_shared_sub.erl | 2 +- test/emqx_connection_SUITE.erl | 4 + 9 files changed, 303 insertions(+), 129 deletions(-) create mode 100644 src/emqx_congestion.erl diff --git a/rebar.config b/rebar.config index a7ae1409f..2f5e362c8 100644 --- a/rebar.config +++ b/rebar.config @@ -6,7 +6,7 @@ [{gproc, {git, "https://github.com/uwiger/gproc", {tag, "0.8.0"}}}, {jiffy, {git, "https://github.com/emqx/jiffy", {tag, "1.0.5"}}}, {cowboy, {git, "https://github.com/emqx/cowboy", {tag, "2.7.1"}}}, - {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.7.4"}}}, + {esockd, {git, "https://github.com/emqx/esockd", {tag, "5.7.5"}}}, {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.7.5"}}}, {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.5.0"}}}, {cuttlefish, {git, "https://github.com/emqx/cuttlefish", {tag, "v3.0.0"}}} diff --git a/src/emqx.appup.src b/src/emqx.appup.src index ed4b0695f..7322f75f5 100644 --- a/src/emqx.appup.src +++ b/src/emqx.appup.src @@ -3,6 +3,7 @@ {VSN, [ {"4.2.0", [ + {add_module, emqx_congestion}, {load_module, emqx_alarm, brutal_purge, soft_purge, []}, {load_module, emqx_channel, brutal_purge, soft_purge, []}, {load_module, emqx_metrics, brutal_purge, soft_purge, []}, @@ -11,37 +12,68 @@ {load_module, emqx_frame, brutal_purge, soft_purge, []}, {update, emqx_connection, {advanced, []}}, {update, emqx_ws_connection, {advanced, []}}, + {load_module, emqx_os_mon, brutal_purge, soft_purge, []}, + {load_module, emqx_shared_sub, brutal_purge, soft_purge, []}, {resume, [esockd_acceptor,emqx_connection, emqx_ws_connection]} ]}, {"4.2.1", [ + {add_module, emqx_congestion}, + {load_module, emqx_alarm, brutal_purge, soft_purge, []}, + {load_module, emqx_channel, brutal_purge, soft_purge, []}, {load_module, emqx_limiter, brutal_purge, soft_purge, []}, {suspend, [esockd_acceptor, emqx_connection, emqx_ws_connection]}, {load_module, emqx_frame, brutal_purge, soft_purge, []}, {update, emqx_connection, {advanced, []}}, {update, emqx_ws_connection, {advanced, []}}, + {load_module, emqx_os_mon, brutal_purge, soft_purge, []}, + {load_module, emqx_shared_sub, brutal_purge, soft_purge, []}, {resume, [esockd_acceptor, emqx_connection, emqx_ws_connection]} ]}, + {<<"4.2.[23]">>, [ + {add_module, emqx_congestion}, + {load_module, emqx_alarm, brutal_purge, soft_purge, []}, + {load_module, emqx_channel, brutal_purge, soft_purge, []}, + {load_module, emqx_connection, brutal_purge, soft_purge, []}, + {load_module, emqx_os_mon, brutal_purge, soft_purge, []}, + {load_module, emqx_shared_sub, brutal_purge, soft_purge, []} + ]}, {<<".*">>, []} ], [ {"4.2.0", [ + {load_module, emqx_shared_sub, brutal_purge, soft_purge, []}, + {load_module, emqx_os_mon, brutal_purge, soft_purge, []}, {load_module, emqx_alarm, brutal_purge, soft_purge, []}, - {load_module, emqx_channel, brutal_purge, soft_purge, []}, {load_module, emqx_metrics, brutal_purge, soft_purge, []}, {load_module, emqx_limiter, brutal_purge, soft_purge, []}, {suspend, [esockd_acceptor, emqx_connection, emqx_ws_connection]}, {load_module, emqx_frame, brutal_purge, soft_purge, []}, {update, emqx_connection, {advanced, []}}, {update, emqx_ws_connection, {advanced, []}}, - {resume, [esockd_acceptor, emqx_connection, emqx_ws_connection]} + {load_module, emqx_channel, brutal_purge, soft_purge, []}, + {resume, [esockd_acceptor, emqx_connection, emqx_ws_connection]}, + {delete_module, emqx_congestion} ]}, {"4.2.1", [ + {load_module, emqx_shared_sub, brutal_purge, soft_purge, []}, + {load_module, emqx_os_mon, brutal_purge, soft_purge, []}, {load_module, emqx_limiter, brutal_purge, soft_purge, []}, {suspend, [esockd_acceptor, emqx_connection, emqx_ws_connection]}, + {load_module, emqx_channel, brutal_purge, soft_purge, []}, {load_module, emqx_frame, brutal_purge, soft_purge, []}, {update, emqx_connection, {advanced, []}}, {update, emqx_ws_connection, {advanced, []}}, - {resume, [esockd_acceptor, emqx_connection, emqx_ws_connection]} + {load_module, emqx_alarm, brutal_purge, soft_purge, []}, + {resume, [esockd_acceptor, emqx_connection, emqx_ws_connection]}, + {delete_module, emqx_congestion} + ]}, + {<<"4.2.[23]">>, [ + {load_module, emqx_shared_sub, brutal_purge, soft_purge, []}, + {load_module, emqx_os_mon, brutal_purge, soft_purge, []}, + {load_module, emqx_connection, brutal_purge, soft_purge, []}, + {load_module, emqx_channel, brutal_purge, soft_purge, []}, + {load_module, emqx_alarm, brutal_purge, soft_purge, []}, + {delete_module, emqx_congestion} ]}, {<<".*">>, []} ] diff --git a/src/emqx_alarm.erl b/src/emqx_alarm.erl index ec2cb4338..12c888e6c 100644 --- a/src/emqx_alarm.erl +++ b/src/emqx_alarm.erl @@ -37,6 +37,7 @@ -export([ activate/1 , activate/2 , deactivate/1 + , deactivate/2 , delete_all_deactivated_alarms/0 , get_alarms/0 , get_alarms/1 @@ -132,7 +133,10 @@ activate(Name, Details) -> gen_server:call(?MODULE, {activate_alarm, Name, Details}). deactivate(Name) -> - gen_server:call(?MODULE, {deactivate_alarm, Name}). + gen_server:call(?MODULE, {deactivate_alarm, Name, no_details}). + +deactivate(Name, Details) -> + gen_server:call(?MODULE, {deactivate_alarm, Name, Details}). delete_all_deactivated_alarms() -> gen_server:call(?MODULE, delete_all_deactivated_alarms). @@ -179,34 +183,13 @@ handle_call({activate_alarm, Name, Details}, _From, State = #state{actions = Act {reply, ok, State} end; -handle_call({deactivate_alarm, Name}, _From, State = #state{actions = Actions, - size_limit = SizeLimit}) -> +handle_call({deactivate_alarm, Name, Details}, _From, State = #state{ + actions = Actions, size_limit = SizeLimit}) -> case mnesia:dirty_read(?ACTIVATED_ALARM, Name) of [] -> {reply, {error, not_found}, State}; - [#activated_alarm{name = Name, - details = Details, - message = Message, - activate_at = ActivateAt}] -> - case SizeLimit > 0 andalso (mnesia:table_info(?DEACTIVATED_ALARM, size) >= SizeLimit) of - true -> - case mnesia:dirty_first(?DEACTIVATED_ALARM) of - '$end_of_table' -> - ok; - ActivateAt2 -> - mnesia:dirty_delete(?DEACTIVATED_ALARM, ActivateAt2) - end; - false -> - ok - end, - Alarm = #deactivated_alarm{activate_at = ActivateAt, - name = Name, - details = Details, - message = Message, - deactivate_at = erlang:system_time(microsecond)}, - mnesia:dirty_delete(?ACTIVATED_ALARM, Name), - mnesia:dirty_write(?DEACTIVATED_ALARM, Alarm), - do_actions(deactivate, Alarm, Actions), + [Alarm] -> + deactivate_alarm(Details, SizeLimit, Actions, Alarm), {reply, ok, State} end; @@ -254,18 +237,50 @@ code_change(_OldVsn, State, _Extra) -> %% Internal functions %%------------------------------------------------------------------------------ +deactivate_alarm(Details, SizeLimit, Actions, #activated_alarm{ + activate_at = ActivateAt, name = Name, details = Details0, + message = Msg0}) -> + case SizeLimit > 0 andalso + (mnesia:table_info(?DEACTIVATED_ALARM, size) >= SizeLimit) of + true -> + case mnesia:dirty_first(?DEACTIVATED_ALARM) of + '$end_of_table' -> ok; + ActivateAt2 -> + mnesia:dirty_delete(?DEACTIVATED_ALARM, ActivateAt2) + end; + false -> ok + end, + HistoryAlarm = make_deactivated_alarm(ActivateAt, Name, Details0, Msg0, + erlang:system_time(microsecond)), + DeActAlarm = make_deactivated_alarm(ActivateAt, Name, Details, + normalize_message(Name, Details), + erlang:system_time(microsecond)), + mnesia:dirty_write(?DEACTIVATED_ALARM, HistoryAlarm), + mnesia:dirty_delete(?ACTIVATED_ALARM, Name), + do_actions(deactivate, DeActAlarm, Actions). + +make_deactivated_alarm(ActivateAt, Name, Details, Message, DeActivateAt) -> + #deactivated_alarm{ + activate_at = ActivateAt, + name = Name, + details = Details, + message = Message, + deactivate_at = DeActivateAt}. + deactivate_all_alarms() -> - lists:foreach(fun(#activated_alarm{name = Name, - details = Details, - message = Message, - activate_at = ActivateAt}) -> - mnesia:dirty_write(?DEACTIVATED_ALARM, - #deactivated_alarm{activate_at = ActivateAt, - name = Name, - details = Details, - message = Message, - deactivate_at = erlang:system_time(microsecond)}) - end, ets:tab2list(?ACTIVATED_ALARM)), + lists:foreach( + fun(#activated_alarm{name = Name, + details = Details, + message = Message, + activate_at = ActivateAt}) -> + mnesia:dirty_write(?DEACTIVATED_ALARM, + #deactivated_alarm{ + activate_at = ActivateAt, + name = Name, + details = Details, + message = Message, + deactivate_at = erlang:system_time(microsecond)}) + end, ets:tab2list(?ACTIVATED_ALARM)), mnesia:clear_table(?ACTIVATED_ALARM). ensure_delete_timer(State = #state{validity_period = ValidityPeriod}) -> @@ -332,6 +347,8 @@ normalize(#deactivated_alarm{activate_at = ActivateAt, deactivate_at => DeactivateAt, activated => false}. +normalize_message(Name, no_details) -> + list_to_binary(io_lib:format("~p", [Name])); normalize_message(high_system_memory_usage, #{high_watermark := HighWatermark}) -> list_to_binary(io_lib:format("System memory usage is higher than ~p%", [HighWatermark])); normalize_message(high_process_memory_usage, #{high_watermark := HighWatermark}) -> @@ -344,8 +361,7 @@ normalize_message(partition, #{occurred := Node}) -> list_to_binary(io_lib:format("Partition occurs at node ~s", [Node])); normalize_message(<<"resource", _/binary>>, #{type := Type, id := ID}) -> list_to_binary(io_lib:format("Resource ~s(~s) is down", [Type, ID])); -normalize_message(<<"mqtt_conn/congested/", ClientId/binary>>, _) -> - list_to_binary(io_lib:format("MQTT connection for clientid '~s' is congested", [ClientId])); +normalize_message(<<"mqtt_conn/congested/", Info/binary>>, _) -> + list_to_binary(io_lib:format("MQTT connection congested: ~s", [Info])); normalize_message(_Name, _UnknownDetails) -> <<"Unknown alarm">>. - diff --git a/src/emqx_channel.erl b/src/emqx_channel.erl index d9356ccd7..f4c71d5d2 100644 --- a/src/emqx_channel.erl +++ b/src/emqx_channel.erl @@ -31,6 +31,7 @@ -export([ info/1 , info/2 + , set_conn_state/2 , stats/1 , caps/1 ]). @@ -87,7 +88,7 @@ pendings :: list() }). --opaque(channel() :: #channel{}). +-type(channel() :: #channel{}). -type(conn_state() :: idle | connecting | connected | disconnected). @@ -127,26 +128,26 @@ info(Keys, Channel) when is_list(Keys) -> [{Key, info(Key, Channel)} || Key <- Keys]; info(conninfo, #channel{conninfo = ConnInfo}) -> ConnInfo; -info(zone, #channel{clientinfo = #{zone := Zone}}) -> - Zone; -info(clientid, #channel{clientinfo = #{clientid := ClientId}}) -> - ClientId; -info(username, #channel{clientinfo = #{username := Username}}) -> - Username; -info(socktype, #channel{conninfo = #{socktype := SockType}}) -> - SockType; -info(peername, #channel{conninfo = #{peername := Peername}}) -> - Peername; -info(sockname, #channel{conninfo = #{sockname := Sockname}}) -> - Sockname; -info(proto_name, #channel{conninfo = #{proto_name := ProtoName}}) -> - ProtoName; -info(proto_ver, #channel{conninfo = #{proto_ver := ProtoVer}}) -> - ProtoVer; -info(connected_at, #channel{conninfo = #{connected_at := ConnectedAt}}) -> - ConnectedAt; +info(socktype, #channel{conninfo = ConnInfo}) -> + maps:get(socktype, ConnInfo, undefined); +info(peername, #channel{conninfo = ConnInfo}) -> + maps:get(peername, ConnInfo, undefined); +info(sockname, #channel{conninfo = ConnInfo}) -> + maps:get(sockname, ConnInfo, undefined); +info(proto_name, #channel{conninfo = ConnInfo}) -> + maps:get(proto_name, ConnInfo, undefined); +info(proto_ver, #channel{conninfo = ConnInfo}) -> + maps:get(proto_ver, ConnInfo, undefined); +info(connected_at, #channel{conninfo = ConnInfo}) -> + maps:get(connected_at, ConnInfo, undefined); info(clientinfo, #channel{clientinfo = ClientInfo}) -> ClientInfo; +info(zone, #channel{clientinfo = ClientInfo}) -> + maps:get(zone, ClientInfo, undefined); +info(clientid, #channel{clientinfo = ClientInfo}) -> + maps:get(clientid, ClientInfo, undefined); +info(username, #channel{clientinfo = ClientInfo}) -> + maps:get(username, ClientInfo, undefined); info(session, #channel{session = Session}) -> maybe_apply(fun emqx_session:info/1, Session); info(conn_state, #channel{conn_state = ConnState}) -> @@ -163,6 +164,9 @@ info(alias_maximum, #channel{alias_maximum = Limits}) -> Limits; info(timers, #channel{timers = Timers}) -> Timers. +set_conn_state(ConnState, Channel) -> + Channel#channel{conn_state = ConnState}. + %% TODO: Add more stats. -spec(stats(channel()) -> emqx_types:stats()). stats(#channel{session = Session})-> @@ -1290,7 +1294,7 @@ packing_alias(Packet = #mqtt_packet{ }, Channel = ?IS_MQTT_V5 = #channel{topic_aliases = TopicAliases, alias_maximum = Limits}) -> case find_alias(outbound, Topic, TopicAliases) of - {ok, AliasId} -> + {ok, AliasId} -> NPublish = Publish#mqtt_packet_publish{ topic_name = <<>>, properties = maps:merge(Prop, #{'Topic-Alias' => AliasId}) diff --git a/src/emqx_congestion.erl b/src/emqx_congestion.erl new file mode 100644 index 000000000..36dc7ac9f --- /dev/null +++ b/src/emqx_congestion.erl @@ -0,0 +1,161 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2020 EMQ Technologies Co., Ltd. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +-module(emqx_congestion). + +-export([ maybe_alarm_port_busy/3 + , maybe_alarm_port_busy/4 + , maybe_alarm_too_many_publish/5 + , maybe_alarm_too_many_publish/6 + , cancel_alarms/3 + ]). + +-define(ALARM_CONN_CONGEST(Channel, Reason), + list_to_binary(io_lib:format("mqtt_conn/congested/~s/~s/~s", [emqx_channel:info(clientid, Channel), + maps:get(username, emqx_channel:info(clientinfo, Channel), <<"undefined">>), + Reason]))). + +-define(ALARM_CONN_INFO_KEYS, [ + socktype, sockname, peername, clientid, username, proto_name, proto_ver, + connected_at, conn_state +]). +-define(ALARM_SOCK_STATS_KEYS, [send_pend, recv_cnt, recv_oct, send_cnt, send_oct]). +-define(ALARM_SOCK_OPTS_KEYS, [high_watermark, high_msgq_watermark, sndbuf, recbuf, buffer]). +-define(PROC_INFO_KEYS, [message_queue_len, memory, reductions]). +-define(ALARM_SENT(REASON), {alarm_sent, REASON}). +-define(ALL_ALARM_REASONS, [port_busy, too_many_publish]). +-define(CONFIRM_CLEAR(REASON), {alarm_confirm_clear, REASON}). +-define(CONFIRM_CLEAR_INTERVAL, 10000). + +maybe_alarm_port_busy(Socket, Transport, Channel) -> + maybe_alarm_port_busy(Socket, Transport, Channel, false). + +maybe_alarm_port_busy(Socket, Transport, Channel, ForceClear) -> + case is_tcp_congested(Socket, Transport) of + true -> alarm_congestion(Socket, Transport, Channel, port_busy); + false -> cancel_alarm_congestion(Socket, Transport, Channel, port_busy, + ForceClear) + end. + +maybe_alarm_too_many_publish(Socket, Transport, Channel, PubMsgCount, + MaxBatchSize) -> + maybe_alarm_too_many_publish(Socket, Transport, Channel, PubMsgCount, + MaxBatchSize, false). + +maybe_alarm_too_many_publish(Socket, Transport, Channel, PubMsgCount, + PubMsgCount = _MaxBatchSize, _ForceClear) -> + %% we only alarm it when the process is "too busy" + alarm_congestion(Socket, Transport, Channel, too_many_publish); +maybe_alarm_too_many_publish(Socket, Transport, Channel, PubMsgCount, + _MaxBatchSize, ForceClear) when PubMsgCount == 0 -> + %% but we clear the alarm until it is really "idle", to avoid sending + %% alarms and clears too frequently + cancel_alarm_congestion(Socket, Transport, Channel, too_many_publish, + ForceClear); +maybe_alarm_too_many_publish(_Socket, _Transport, _Channel, _PubMsgCount, + _MaxBatchSize, _ForceClear) -> + ok. + +cancel_alarms(Socket, Transport, Channel) -> + lists:foreach(fun(Reason) -> + do_cancel_alarm_congestion(Socket, Transport, Channel, Reason) + end, ?ALL_ALARM_REASONS). + +alarm_congestion(Socket, Transport, Channel, Reason) -> + case has_alarm_sent(Reason) of + false -> do_alarm_congestion(Socket, Transport, Channel, Reason); + true -> + %% pretend we have sent an alarm again + update_alarm_sent_at(Reason) + end. + +cancel_alarm_congestion(Socket, Transport, Channel, Reason, ForceClear) -> + case is_alarm_allowed_clear(Reason, ForceClear) of + true -> do_cancel_alarm_congestion(Socket, Transport, Channel, Reason); + false -> ok + end. + +do_alarm_congestion(Socket, Transport, Channel, Reason) -> + ok = update_alarm_sent_at(Reason), + AlarmDetails = tcp_congestion_alarm_details(Socket, Transport, Channel), + emqx_alarm:activate(?ALARM_CONN_CONGEST(Channel, Reason), AlarmDetails), + ok. + +do_cancel_alarm_congestion(Socket, Transport, Channel, Reason) -> + ok = remove_alarm_sent_at(Reason), + AlarmDetails = tcp_congestion_alarm_details(Socket, Transport, Channel), + emqx_alarm:deactivate(?ALARM_CONN_CONGEST(Channel, Reason), AlarmDetails), + ok. + +is_tcp_congested(Socket, Transport) -> + case Transport:getstat(Socket, [send_pend]) of + {ok, [{send_pend, N}]} when N > 0 -> true; + _ -> false + end. + +has_alarm_sent(Reason) -> + case get_alarm_sent_at(Reason) of + 0 -> false; + _ -> true + end. +update_alarm_sent_at(Reason) -> + erlang:put(?ALARM_SENT(Reason), timenow()), + ok. +remove_alarm_sent_at(Reason) -> + erlang:erase(?ALARM_SENT(Reason)), + ok. +get_alarm_sent_at(Reason) -> + case erlang:get(?ALARM_SENT(Reason)) of + undefined -> 0; + LastSentAt -> LastSentAt + end. + +is_alarm_allowed_clear(Reason, _ForceClear = true) -> + has_alarm_sent(Reason); +is_alarm_allowed_clear(Reason, _ForceClear = false) -> + %% only sent clears when the alarm was not triggered in the last + %% ?CONFIRM_CLEAR_INTERVAL time + case timenow() - get_alarm_sent_at(Reason) of + Elapse when Elapse >= ?CONFIRM_CLEAR_INTERVAL -> true; + _ -> false + end. + +timenow() -> + erlang:system_time(millisecond). + +%%============================================================================== +%% Alarm message +%%============================================================================== +tcp_congestion_alarm_details(Socket, Transport, Channel) -> + ProcInfo = process_info(self(), ?PROC_INFO_KEYS), + BasicInfo = [{pid, list_to_binary(pid_to_list(self()))} | ProcInfo], + Stat = case Transport:getstat(Socket, ?ALARM_SOCK_STATS_KEYS) of + {ok, Stat0} -> Stat0; + {error, _} -> [] + end, + Opts = case Transport:getopts(Socket, ?ALARM_SOCK_OPTS_KEYS) of + {ok, Opts0} -> Opts0; + {error, _} -> [] + end, + SockInfo = Stat ++ Opts, + ConnInfo = [conn_info(Key, Channel) || Key <- ?ALARM_CONN_INFO_KEYS], + maps:from_list(BasicInfo ++ ConnInfo ++ SockInfo). + +conn_info(Key, Channel) when Key =:= sockname; Key =:= peername -> + {IPStr, Port} = emqx_channel:info(Key, Channel), + {Key, iolist_to_binary([inet:ntoa(IPStr),":",integer_to_list(Port)])}; +conn_info(Key, Channel) -> + {Key, emqx_channel:info(Key, Channel)}. diff --git a/src/emqx_connection.erl b/src/emqx_connection.erl index 6e8ed9a46..91088f027 100644 --- a/src/emqx_connection.erl +++ b/src/emqx_connection.erl @@ -103,17 +103,6 @@ -define(ENABLED(X), (X =/= undefined)). --define(ALARM_TCP_CONGEST(Channel), - list_to_binary(io_lib:format("mqtt_conn/congested/~s/~s", [emqx_channel:info(clientid, Channel), maps:get(username, emqx_channel:info(clientinfo, Channel), <<"undefined">>)]))). - - --define(ALARM_CONN_INFO_KEYS, [ - socktype, sockname, peername, - clientid, username, proto_name, proto_ver, connected_at -]). --define(ALARM_SOCK_STATS_KEYS, [send_pend, recv_cnt, recv_oct, send_cnt, send_oct]). --define(ALARM_SOCK_OPTS_KEYS, [high_watermark, high_msgq_watermark, sndbuf, recbuf, buffer]). - -dialyzer({no_match, [info/2]}). -dialyzer({nowarn_function, [ init/4 , init_state/3 @@ -272,7 +261,7 @@ recvloop(Parent, State = #state{idle_timeout = IdleTimeout}) -> Msg -> process_msg([Msg], Parent, ensure_stats_timer(IdleTimeout, State)) after - IdleTimeout -> + IdleTimeout + 100 -> hibernate(Parent, cancel_stats_timer(State)) end. @@ -385,8 +374,12 @@ handle_msg({Passive, _Sock}, State) handle_info(activate_socket, NState1); handle_msg(Deliver = {deliver, _Topic, _Msg}, - State = #state{active_n = ActiveN}) -> - Delivers = [Deliver|emqx_misc:drain_deliver(ActiveN)], + #state{active_n = MaxBatchSize, transport = Transport, + socket = Socket, channel = Channel} = State) -> + Delivers0 = emqx_misc:drain_deliver(MaxBatchSize), + emqx_congestion:maybe_alarm_too_many_publish(Socket, Transport, Channel, + length(Delivers0), MaxBatchSize), + Delivers = [Deliver|Delivers0], with_channel(handle_deliver, [Delivers], State); %% Something sent @@ -438,10 +431,12 @@ handle_msg(Msg, State) -> %%-------------------------------------------------------------------- %% Terminate -terminate(Reason, State = #state{channel = Channel}) -> +terminate(Reason, State = #state{channel = Channel, transport = Transport, + socket = Socket}) -> ?LOG(debug, "Terminated due to ~p", [Reason]), - emqx_alarm:deactivate(?ALARM_TCP_CONGEST(Channel)), - emqx_channel:terminate(Reason, Channel), + Channel1 = emqx_channel:set_conn_state(disconnected, Channel), + emqx_congestion:cancel_alarms(Socket, Transport, Channel1), + emqx_channel:terminate(Reason, Channel1), close_socket(State), exit(Reason). @@ -553,8 +548,12 @@ handle_timeout(_TRef, limit_timeout, State) -> }, handle_info(activate_socket, NState); -handle_timeout(_TRef, emit_stats, State = - #state{channel = Channel}) -> +handle_timeout(_TRef, emit_stats, State = #state{active_n = MaxBatchSize, + channel = Channel, transport = Transport, socket = Socket}) -> + {_, MsgQLen} = erlang:process_info(self(), message_queue_len), + emqx_congestion:maybe_alarm_port_busy(Socket, Transport, Channel, true), + emqx_congestion:maybe_alarm_too_many_publish(Socket, Transport, Channel, + MsgQLen, MaxBatchSize, true), ClientId = emqx_channel:info(clientid, Channel), emqx_cm:set_chan_stats(ClientId, stats(State)), {ok, State#state{stats_timer = undefined}}; @@ -667,7 +666,7 @@ send(IoData, #state{transport = Transport, socket = Socket, channel = Channel}) Oct = iolist_size(IoData), ok = emqx_metrics:inc('bytes.sent', Oct), emqx_pd:inc_counter(outgoing_bytes, Oct), - maybe_warn_congestion(Socket, Transport, Channel), + emqx_congestion:maybe_alarm_port_busy(Socket, Transport, Channel), case Transport:async_send(Socket, IoData, [nosuspend]) of ok -> ok; Error = {error, _Reason} -> @@ -676,48 +675,6 @@ send(IoData, #state{transport = Transport, socket = Socket, channel = Channel}) ok end. -maybe_warn_congestion(Socket, Transport, Channel) -> - IsCongestAlarmSet = is_congestion_alarm_set(), - case is_congested(Socket, Transport) of - true when not IsCongestAlarmSet -> - ok = set_congestion_alarm(), - emqx_alarm:activate(?ALARM_TCP_CONGEST(Channel), - tcp_congestion_alarm_details(Socket, Transport, Channel)); - false when IsCongestAlarmSet -> - ok = clear_congestion_alarm(), - emqx_alarm:deactivate(?ALARM_TCP_CONGEST(Channel)); - _ -> ok - end. - -is_congested(Socket, Transport) -> - case Transport:getstat(Socket, [send_pend]) of - {ok, [{send_pend, N}]} when N > 0 -> true; - _ -> false - end. - -is_congestion_alarm_set() -> - case erlang:get(conn_congested) of - true -> true; - _ -> false - end. -set_congestion_alarm() -> - erlang:put(conn_congested, true), ok. -clear_congestion_alarm() -> - erlang:put(conn_congested, false), ok. - -tcp_congestion_alarm_details(Socket, Transport, Channel) -> - {ok, Stat} = Transport:getstat(Socket, ?ALARM_SOCK_STATS_KEYS), - {ok, Opts} = Transport:getopts(Socket, ?ALARM_SOCK_OPTS_KEYS), - SockInfo = maps:from_list(Stat ++ Opts), - ConnInfo = maps:from_list([conn_info(Key, Channel) || Key <- ?ALARM_CONN_INFO_KEYS]), - maps:merge(ConnInfo, SockInfo). - -conn_info(Key, Channel) when Key =:= sockname; Key =:= peername -> - {IPStr, Port} = emqx_channel:info(Key, Channel), - {Key, iolist_to_binary([inet:ntoa(IPStr),":",integer_to_list(Port)])}; -conn_info(Key, Channel) -> - {Key, emqx_channel:info(Key, Channel)}. - %%-------------------------------------------------------------------- %% Handle Info diff --git a/src/emqx_os_mon.erl b/src/emqx_os_mon.erl index 49517d8a6..2852c917b 100644 --- a/src/emqx_os_mon.erl +++ b/src/emqx_os_mon.erl @@ -145,12 +145,12 @@ handle_info({timeout, Timer, check}, State = #{timer := Timer, case emqx_vm:cpu_util() of %% TODO: should be improved? 0 -> State#{timer := undefined}; - Busy when Busy / 100 >= CPUHighWatermark -> + Busy when Busy >= CPUHighWatermark -> emqx_alarm:activate(high_cpu_usage, #{usage => Busy, high_watermark => CPUHighWatermark, low_watermark => CPULowWatermark}), ensure_check_timer(State); - Busy when Busy / 100 =< CPULowWatermark -> + Busy when Busy =< CPULowWatermark -> emqx_alarm:deactivate(high_cpu_usage), ensure_check_timer(State); _Busy -> diff --git a/src/emqx_shared_sub.erl b/src/emqx_shared_sub.erl index 71372cd90..17476199b 100644 --- a/src/emqx_shared_sub.erl +++ b/src/emqx_shared_sub.erl @@ -246,7 +246,7 @@ pick(Strategy, ClientId, Group, Topic, FailedSubs) -> do_pick(Strategy, ClientId, Group, Topic, FailedSubs) -> All = subscribers(Group, Topic), case All -- FailedSubs of - [] when FailedSubs =:= [] -> + [] when All =:= [] -> %% Genuinely no subscriber false; [] -> diff --git a/test/emqx_connection_SUITE.erl b/test/emqx_connection_SUITE.erl index 2538aeecb..d360bb5ae 100644 --- a/test/emqx_connection_SUITE.erl +++ b/test/emqx_connection_SUITE.erl @@ -54,6 +54,7 @@ init_per_suite(Config) -> ok = meck:expect(emqx_alarm, activate, fun(_, _) -> ok end), ok = meck:expect(emqx_alarm, deactivate, fun(_) -> ok end), + ok = meck:expect(emqx_alarm, deactivate, fun(_, _) -> ok end), Config. @@ -77,6 +78,9 @@ init_per_testcase(_TestCase, Config) -> (peercert, [sock]) -> undefined end), ok = meck:expect(emqx_transport, setopts, fun(_Sock, _Opts) -> ok end), + ok = meck:expect(emqx_transport, getopts, fun(_Sock, Options) -> + {ok, [{K, 0} || K <- Options]} + end), ok = meck:expect(emqx_transport, getstat, fun(_Sock, Options) -> {ok, [{K, 0} || K <- Options]} end), From 5ebf94a50a5d828822e38a226b4a3157007052f5 Mon Sep 17 00:00:00 2001 From: Zaiming Shi Date: Tue, 9 Feb 2021 09:19:08 +0100 Subject: [PATCH 25/41] chore(config): One config emqx.conf was split into small files for enterprise which leads to merge difficulties This commit merges back config into the same file. --- etc/cluster.conf | 170 ---- etc/emqx.conf | 1936 +++++++++++++++++++++++++++++++++++++++++++- etc/listeners.conf | 940 --------------------- etc/logger.conf | 170 ---- etc/rpc.conf | 98 --- etc/sys_mon.conf | 148 ---- etc/zones.conf | 327 -------- priv/emqx.schema | 18 +- 8 files changed, 1930 insertions(+), 1877 deletions(-) delete mode 100644 etc/cluster.conf delete mode 100644 etc/listeners.conf delete mode 100644 etc/logger.conf delete mode 100644 etc/rpc.conf delete mode 100644 etc/sys_mon.conf delete mode 100644 etc/zones.conf diff --git a/etc/cluster.conf b/etc/cluster.conf deleted file mode 100644 index cd4d3d007..000000000 --- a/etc/cluster.conf +++ /dev/null @@ -1,170 +0,0 @@ -##-------------------------------------------------------------------- -## Cluster -##-------------------------------------------------------------------- - -## Cluster name. -## -## Value: String -cluster.name = emqxcl - -## Specify the erlang distributed protocol. -## -## Value: Enum -## - inet_tcp: the default; handles TCP streams with IPv4 addressing. -## - inet6_tcp: handles TCP with IPv6 addressing. -## - inet_tls: using TLS for Erlang Distribution. -## -## vm.args: -proto_dist inet_tcp -cluster.proto_dist = inet_tcp - -## Cluster auto-discovery strategy. -## -## Value: Enum -## - manual: Manual join command -## - static: Static node list -## - mcast: IP Multicast -## - dns: DNS A Record -## - etcd: etcd -## - k8s: Kubernetes -## -## Default: manual -cluster.discovery = manual - -## Enable cluster autoheal from network partition. -## -## Value: on | off -## -## Default: on -cluster.autoheal = on - -## Autoclean down node. A down node will be removed from the cluster -## if this value > 0. -## -## Value: Duration -## -h: hour, e.g. '2h' for 2 hours -## -m: minute, e.g. '5m' for 5 minutes -## -s: second, e.g. '30s' for 30 seconds -## -## Default: 5m -cluster.autoclean = 5m - -##-------------------------------------------------------------------- -## Cluster using static node list - -## Node list of the cluster. -## -## Value: String -## cluster.static.seeds = emqx1@127.0.0.1,emqx2@127.0.0.1 - -##-------------------------------------------------------------------- -## Cluster using IP Multicast. - -## IP Multicast Address. -## -## Value: IP Address -## cluster.mcast.addr = 239.192.0.1 - -## Multicast Ports. -## -## Value: Port List -## cluster.mcast.ports = 4369,4370 - -## Multicast Iface. -## -## Value: Iface Address -## -## Default: 0.0.0.0 -## cluster.mcast.iface = 0.0.0.0 - -## Multicast Ttl. -## -## Value: 0-255 -## cluster.mcast.ttl = 255 - -## Multicast loop. -## -## Value: on | off -## cluster.mcast.loop = on - -##-------------------------------------------------------------------- -## Cluster using DNS A records. - -## DNS name. -## -## Value: String -## cluster.dns.name = localhost - -## The App name is used to build 'node.name' with IP address. -## -## Value: String -## cluster.dns.app = emqx - -##-------------------------------------------------------------------- -## Cluster using etcd - -## Etcd server list, seperated by ','. -## -## Value: String -## cluster.etcd.server = http://127.0.0.1:2379 - -## The prefix helps build nodes path in etcd. Each node in the cluster -## will create a path in etcd: v2/keys/// -## -## Value: String -## cluster.etcd.prefix = emqxcl - -## The TTL for node's path in etcd. -## -## Value: Duration -## -## Default: 1m, 1 minute -## cluster.etcd.node_ttl = 1m - -## Path to a file containing the client's private PEM-encoded key. -## -## Value: File -## cluster.etcd.ssl.keyfile = {{ platform_etc_dir }}/certs/client-key.pem - -## The path to a file containing the client's certificate. -## -## Value: File -## cluster.etcd.ssl.certfile = {{ platform_etc_dir }}/certs/client.pem - -## Path to the file containing PEM-encoded CA certificates. The CA certificates -## are used during server authentication and when building the client certificate chain. -## -## Value: File -## cluster.etcd.ssl.cacertfile = {{ platform_etc_dir }}/certs/ca.pem - -##-------------------------------------------------------------------- -## Cluster using Kubernetes - -## Kubernetes API server list, seperated by ','. -## -## Value: String -## cluster.k8s.apiserver = http://10.110.111.204:8080 - -## The service name helps lookup EMQ nodes in the cluster. -## -## Value: String -## cluster.k8s.service_name = emqx - -## The address type is used to extract host from k8s service. -## -## Value: ip | dns | hostname -## cluster.k8s.address_type = ip - -## The app name helps build 'node.name'. -## -## Value: String -## cluster.k8s.app_name = emqx - -## The suffix added to dns and hostname get from k8s service -## -## Value: String -## cluster.k8s.suffix = pod.cluster.local - -## Kubernetes Namespace -## -## Value: String -## cluster.k8s.namespace = default \ No newline at end of file diff --git a/etc/emqx.conf b/etc/emqx.conf index 58cf05cbe..6e6ebd4cb 100644 --- a/etc/emqx.conf +++ b/etc/emqx.conf @@ -2,12 +2,176 @@ ## EMQ X Configuration R4.0 ##==================================================================== -include {{ platform_etc_dir }}/cluster.conf -include {{ platform_etc_dir }}/rpc.conf -include {{ platform_etc_dir }}/logger.conf -include {{ platform_etc_dir }}/zones.conf -include {{ platform_etc_dir }}/listeners.conf -include {{ platform_etc_dir }}/sys_mon.conf +##-------------------------------------------------------------------- +## Cluster +##-------------------------------------------------------------------- + +## Cluster name. +## +## Value: String +cluster.name = emqxcl + +## Specify the erlang distributed protocol. +## +## Value: Enum +## - inet_tcp: the default; handles TCP streams with IPv4 addressing. +## - inet6_tcp: handles TCP with IPv6 addressing. +## - inet_tls: using TLS for Erlang Distribution. +## +## vm.args: -proto_dist inet_tcp +cluster.proto_dist = inet_tcp + +## Cluster auto-discovery strategy. +## +## Value: Enum +## - manual: Manual join command +## - static: Static node list +## - mcast: IP Multicast +## - dns: DNS A Record +## - etcd: etcd +## - k8s: Kubernetes +## +## Default: manual +cluster.discovery = manual + +## Enable cluster autoheal from network partition. +## +## Value: on | off +## +## Default: on +cluster.autoheal = on + +## Autoclean down node. A down node will be removed from the cluster +## if this value > 0. +## +## Value: Duration +## -h: hour, e.g. '2h' for 2 hours +## -m: minute, e.g. '5m' for 5 minutes +## -s: second, e.g. '30s' for 30 seconds +## +## Default: 5m +cluster.autoclean = 5m + +##-------------------------------------------------------------------- +## Cluster using static node list + +## Node list of the cluster. +## +## Value: String +## cluster.static.seeds = emqx1@127.0.0.1,emqx2@127.0.0.1 + +##-------------------------------------------------------------------- +## Cluster using IP Multicast. + +## IP Multicast Address. +## +## Value: IP Address +## cluster.mcast.addr = 239.192.0.1 + +## Multicast Ports. +## +## Value: Port List +## cluster.mcast.ports = 4369,4370 + +## Multicast Iface. +## +## Value: Iface Address +## +## Default: 0.0.0.0 +## cluster.mcast.iface = 0.0.0.0 + +## Multicast Ttl. +## +## Value: 0-255 +## cluster.mcast.ttl = 255 + +## Multicast loop. +## +## Value: on | off +## cluster.mcast.loop = on + +##-------------------------------------------------------------------- +## Cluster using DNS A records. + +## DNS name. +## +## Value: String +## cluster.dns.name = localhost + +## The App name is used to build 'node.name' with IP address. +## +## Value: String +## cluster.dns.app = emqx + +##-------------------------------------------------------------------- +## Cluster using etcd + +## Etcd server list, seperated by ','. +## +## Value: String +## cluster.etcd.server = http://127.0.0.1:2379 + +## The prefix helps build nodes path in etcd. Each node in the cluster +## will create a path in etcd: v2/keys/// +## +## Value: String +## cluster.etcd.prefix = emqxcl + +## The TTL for node's path in etcd. +## +## Value: Duration +## +## Default: 1m, 1 minute +## cluster.etcd.node_ttl = 1m + +## Path to a file containing the client's private PEM-encoded key. +## +## Value: File +## cluster.etcd.ssl.keyfile = {{ platform_etc_dir }}/certs/client-key.pem + +## The path to a file containing the client's certificate. +## +## Value: File +## cluster.etcd.ssl.certfile = {{ platform_etc_dir }}/certs/client.pem + +## Path to the file containing PEM-encoded CA certificates. The CA certificates +## are used during server authentication and when building the client certificate chain. +## +## Value: File +## cluster.etcd.ssl.cacertfile = {{ platform_etc_dir }}/certs/ca.pem + +##-------------------------------------------------------------------- +## Cluster using Kubernetes + +## Kubernetes API server list, seperated by ','. +## +## Value: String +## cluster.k8s.apiserver = http://10.110.111.204:8080 + +## The service name helps lookup EMQ nodes in the cluster. +## +## Value: String +## cluster.k8s.service_name = emqx + +## The address type is used to extract host from k8s service. +## +## Value: ip | dns | hostname +## cluster.k8s.address_type = ip + +## The app name helps build 'node.name'. +## +## Value: String +## cluster.k8s.app_name = emqx + +## The suffix added to dns and hostname get from k8s service +## +## Value: String +## cluster.k8s.suffix = pod.cluster.local + +## Kubernetes Namespace +## +## Value: String +## cluster.k8s.namespace = default ##-------------------------------------------------------------------- ## Node @@ -137,6 +301,276 @@ node.crash_dump = {{ platform_log_dir }}/crash.dump node.dist_listen_min = 6369 node.dist_listen_max = 6369 +##-------------------------------------------------------------------- +## RPC +##-------------------------------------------------------------------- +## RPC Mode. +## +## Value: sync | async +rpc.mode = async + +## Max batch size of async RPC requests. +## +## Value: Integer +## Zero or negative value disables rpc batching. +## +## NOTE: RPC batch won't work when rpc.mode = sync +rpc.async_batch_size = 256 + +## RPC port discovery +## +## The strategy for discovering the RPC listening port of other nodes. +## +## Value: Enum +## - manual: discover ports by `tcp_server_port` and `tcp_client_port`. +## - stateless: discover ports in a stateless manner. +## If node name is `emqx@127.0.0.1`, where the `` is an integer, +## then the listening port will be `5370 + ` +## +## Defaults to `stateless`. +rpc.port_discovery = stateless + +## TCP server port for RPC. +## +## Only takes effect when `rpc.port_discovery` = `manual`. +## +## Value: Port [1024-65535] +#rpc.tcp_server_port = 5369 + +## TCP port for outgoing RPC connections. +## +## Only takes effect when `rpc.port_discovery` = `manual`. +## +## Value: Port [1024-65535] +#rpc.tcp_client_port = 5369 + +## Number of outgoing RPC connections. +## +## Value: Interger [1-256] +## Defaults to NumberOfCPUSchedulers / 2 +#rpc.tcp_client_num = 1 + +## RCP Client connect timeout. +## +## Value: Seconds +rpc.connect_timeout = 5s + +## TCP send timeout of RPC client and server. +## +## Value: Seconds +rpc.send_timeout = 5s + +## Authentication timeout +## +## Value: Seconds +rpc.authentication_timeout = 5s + +## Default receive timeout for call() functions +## +## Value: Seconds +rpc.call_receive_timeout = 15s + +## Socket idle keepalive. +## +## Value: Seconds +rpc.socket_keepalive_idle = 900s + +## TCP Keepalive probes interval. +## +## Value: Seconds +rpc.socket_keepalive_interval = 75s + +## Probes lost to close the connection +## +## Value: Integer +rpc.socket_keepalive_count = 9 + +## Size of TCP send buffer. +## +## Value: Bytes +rpc.socket_sndbuf = 1MB + +## Size of TCP receive buffer. +## +## Value: Seconds +rpc.socket_recbuf = 1MB + +## Size of user-level software socket buffer. +## +## Value: Seconds +rpc.socket_buffer = 1MB + +##-------------------------------------------------------------------- +## Log +##-------------------------------------------------------------------- + +## Where to emit the logs. +## Enable the console (standard output) logs. +## +## Value: off | file | console | both +## - off: disable logs entirely +## - file: write logs only to file +## - console: write logs only to standard I/O +## - both: write logs both to file and standard I/O +log.to = both + +## The log severity level. +## +## Value: debug | info | notice | warning | error | critical | alert | emergency +## +## Note: Only the messages with severity level higher than or equal to +## this level will be logged. +## +## Default: warning +log.level = warning + +## The dir for log files. +## +## Value: Folder +log.dir = {{ platform_log_dir }} + +## The log filename for logs of level specified in "log.level". +## +## If `log.rotation` is enabled, this is the base name of the +## files. Each file in a rotated log is named .N, where N is an integer. +## +## Value: String +## Default: emqx.log +log.file = emqx.log + +## Limits the total number of characters printed for each log event. +## +## Value: Integer +## Default: No Limit +#log.chars_limit = 8192 + +## Enables the log rotation. +## With this enabled, new log files will be created when the current +## log file is full, max to `log.rotation.size` files will be created. +## +## Value: on | off +## Default: on +log.rotation = on + +## Maximum size of each log file. +## +## Value: Number +## Default: 10M +## Supported Unit: KB | MB | GB +log.rotation.size = 10MB + +## Maximum rotation count of log files. +## +## Value: Number +## Default: 5 +log.rotation.count = 5 + +## To create additional log files for specific log levels. +## +## Value: File Name +## Format: log.$level.file = $filename, +## where "$level" can be one of: debug, info, notice, warning, +## error, critical, alert, emergency +## Note: Log files for a specific log level will only contain all the logs +## that higher than or equal to that level +## +#log.info.file = info.log +#log.error.file = error.log + +## The max allowed queue length before switching to sync mode. +## +## Log overload protection parameter. If the message queue grows +## larger than this value the handler switches from anync to sync mode. +## +## Default: 100 +## +#log.sync_mode_qlen = 100 + +## The max allowed queue length before switching to drop mode. +## +## Log overload protection parameter. When the message queue grows +## larger than this threshold, the handler switches to a mode in which +## it drops all new events that senders want to log. +## +## Default: 3000 +## +#log.drop_mode_qlen = 3000 + +## The max allowed queue length before switching to flush mode. +## +## Log overload protection parameter. If the length of the message queue +## grows larger than this threshold, a flush (delete) operation takes place. +## To flush events, the handler discards the messages in the message queue +## by receiving them in a loop without logging. +## +## Default: 8000 +## +#log.flush_qlen = 8000 + +## Kill the log handler when it gets overloaded. +## +## Log overload protection parameter. It is possible that a handler, +## even if it can successfully manage peaks of high load without crashing, +## can build up a large message queue, or use a large amount of memory. +## We could kill the log handler in these cases and restart it after a +## few seconds. +## +## Default: on +## +#log.overload_kill = on + +## The max allowed queue length before killing the log hanlder. +## +## Log overload protection parameter. This is the maximum allowed queue +## length. If the message queue grows larger than this, the handler +## process is terminated. +## +## Default: 20000 +## +#log.overload_kill_qlen = 20000 + +## The max allowed memory size before killing the log hanlder. +## +## Log overload protection parameter. This is the maximum memory size +## that the handler process is allowed to use. If the handler grows +## larger than this, the process is terminated. +## +## Default: 30MB +## +#log.overload_kill_mem_size = 30MB + +## Restart the log hanlder after some seconds. +## +## Log overload protection parameter. If the handler is terminated, +## it restarts automatically after a delay specified in seconds. +## The value "infinity" prevents restarts. +## +## Default: 5s +## +#log.overload_kill_restart_after = 5s + +## Max burst count and time window for burst control. +## +## Log overload protection parameter. Large bursts of log events - many +## events received by the handler under a short period of time - can +## potentially cause problems. By specifying the maximum number of events +## to be handled within a certain time frame, the handler can avoid +## choking the log with massive amounts of printouts. +## +## This config controls the maximum number of events to handle within +## a time frame. After the limit is reached, successive events are +## dropped until the end of the time frame. +## +## Note that there would be no warning if any messages were +## dropped because of burst control. +## +## Comment this config out to disable the burst control feature. +## +## Value: MaxBurstCount,TimeWindow +## Default: disabled +## +#log.burst_limit = 20000, 1s + ##-------------------------------------------------------------------- ## Authentication/Access Control ##-------------------------------------------------------------------- @@ -152,6 +586,11 @@ allow_anonymous = true ## Value: allow | deny acl_nomatch = allow +## Default ACL File. +## +## Value: File Name +acl_file = {{ platform_etc_dir }}/acl.conf + ## Whether to enable ACL cache. ## ## If enabled, ACLs roles for each client will be cached in the memory @@ -242,10 +681,1334 @@ mqtt.ignore_loop_deliver = false mqtt.strict_mode = false ## Specify the response information returned to the client -## +## ## Value: String ## mqtt.response_information = example +##-------------------------------------------------------------------- +## Zones +##-------------------------------------------------------------------- + +##-------------------------------------------------------------------- +## External Zone + +## Idle timeout of the external MQTT connections. +## +## Value: duration +zone.external.idle_timeout = 15s + +## Enable ACL check. +## +## Value: Flag +zone.external.enable_acl = on + +## Enable ban check. +## +## Value: Flag +zone.external.enable_ban = on + +## Enable per connection statistics. +## +## Value: on | off +zone.external.enable_stats = on + +## The action when acl check reject current operation +## +## Value: ignore | disconnect +## Default: ignore +zone.external.acl_deny_action = ignore + +## Force the MQTT connection process GC after this number of +## messages | bytes passed through. +## +## Numbers delimited by `|'. Zero or negative is to disable. +zone.external.force_gc_policy = 16000|16MB + +## Max message queue length and total heap size to force shutdown +## connection/session process. +## Message queue here is the Erlang process mailbox, but not the number +## of queued MQTT messages of QoS 1 and 2. +## +## Numbers delimited by `|'. Zero or negative is to disable. +zone.external.force_shutdown_policy = 10000|32MB + +## Maximum MQTT packet size allowed. +## +## Value: Bytes +## Default: 1MB +## zone.external.max_packet_size = 64KB + +## Maximum length of MQTT clientId allowed. +## +## Value: Number [23-65535] +## zone.external.max_clientid_len = 1024 + +## Maximum topic levels allowed. 0 means no limit. +## +## Value: Number +## zone.external.max_topic_levels = 7 + +## Maximum QoS allowed. +## +## Value: 0 | 1 | 2 +## zone.external.max_qos_allowed = 2 + +## Maximum Topic Alias, 0 means no limit. +## +## Value: 0-65535 +## zone.external.max_topic_alias = 65535 + +## Whether the Server supports retained messages. +## +## Value: boolean +## zone.external.retain_available = true + +## Whether the Server supports Wildcard Subscriptions +## +## Value: boolean +## zone.external.wildcard_subscription = false + +## Whether the Server supports Shared Subscriptions +## +## Value: boolean +## zone.external.shared_subscription = false + +## Server Keep Alive +## +## Value: Number +## zone.external.server_keepalive = 0 + +## The backoff for MQTT keepalive timeout. The broker will kick a connection out +## until 'Keepalive * backoff * 2' timeout. +## +## Value: Float > 0.5 +zone.external.keepalive_backoff = 0.75 + +## Maximum number of subscriptions allowed, 0 means no limit. +## +## Value: Number +zone.external.max_subscriptions = 0 + +## Force to upgrade QoS according to subscription. +## +## Value: on | off +zone.external.upgrade_qos = off + +## Maximum size of the Inflight Window storing QoS1/2 messages delivered but unacked. +## +## Value: Number +zone.external.max_inflight = 32 + +## Retry interval for QoS1/2 message delivering. +## +## Value: Duration +zone.external.retry_interval = 30s + +## Maximum QoS2 packets (Client -> Broker) awaiting PUBREL, 0 means no limit. +## +## Value: Number +zone.external.max_awaiting_rel = 100 + +## The QoS2 messages (Client -> Broker) will be dropped if awaiting PUBREL timeout. +## +## Value: Duration +zone.external.await_rel_timeout = 300s + +## Default session expiry interval for MQTT V3.1.1 connections. +## +## Value: Duration +## -d: day +## -h: hour +## -m: minute +## -s: second +## +## Default: 2h, 2 hours +zone.external.session_expiry_interval = 2h + +## Maximum queue length. Enqueued messages when persistent client disconnected, +## or inflight window is full. 0 means no limit. +## +## Value: Number >= 0 +zone.external.max_mqueue_len = 1000 + +## Topic priorities. +## 'none' to indicate no priority table (by default), hence all messages +## are treated equal +## +## Priority number [1-255] +## Example: topic/1=10,topic/2=8 +## NOTE: comma and equal signs are not allowed for priority topic names +## NOTE: messages for topics not in the priority table are treated as +## either highest or lowest priority depending on the configured +## value for mqueue_default_priority +## +zone.external.mqueue_priorities = none + +## Default to highest priority for topics not matching priority table +## +## Value: highest | lowest +zone.external.mqueue_default_priority = highest + +## Whether to enqueue QoS0 messages. +## +## Value: false | true +zone.external.mqueue_store_qos0 = true + +## Whether to turn on flapping detect +## +## Value: on | off +zone.external.enable_flapping_detect = off + +## Message limit for the a external MQTT connection. +## +## Value: Number,Duration +## Example: 100 messages per 10 seconds. +#zone.external.rate_limit.conn_messages_in = 100,10s + +## Bytes limit for a external MQTT connections. +## +## Value: Number,Duration +## Example: 100KB incoming per 10 seconds. +#zone.external.rate_limit.conn_bytes_in = 100KB,10s + +## Messages quota for the each of external MQTT connection. +## This value consumed by the number of recipient on a message. +## +## Value: Number, Duration +## +## Example: 100 messaegs per 1s +#zone.external.quota.conn_messages_routing = 100,1s + +## Messages quota for the all of external MQTT connections. +## This value consumed by the number of recipient on a message. +## +## Value: Number, Duration +## +## Example: 200000 messaegs per 1s +#zone.external.quota.overall_messages_routing = 200000,1s + +## All the topics will be prefixed with the mountpoint path if this option is enabled. +## +## Variables in mountpoint path: +## - %c: clientid +## - %u: username +## +## Value: String +## zone.external.mountpoint = devicebound/ + +## Whether use username replace client id +## +## Value: boolean +## Default: false +zone.external.use_username_as_clientid = false + +## Whether to ignore loop delivery of messages.(for mqtt v3.1.1) +## +## Value: true | false +zone.external.ignore_loop_deliver = false + +## Whether to parse the MQTT frame in strict mode +## +## Value: true | false +zone.external.strict_mode = false + +## Specify the response information returned to the client +## +## Value: String +## zone.external.response_information = example + +##-------------------------------------------------------------------- +## Internal Zone + +zone.internal.allow_anonymous = true + +## Enable per connection stats. +## +## Value: Flag +zone.internal.enable_stats = on + +## Enable ACL check. +## +## Value: Flag +zone.internal.enable_acl = off + +## The action when acl check reject current operation +## +## Value: ignore | disconnect +## Default: ignore +zone.internal.acl_deny_action = ignore + +## See zone.$name.force_gc_policy +## zone.internal.force_gc_policy = 128000|128MB + +## See zone.$name.wildcard_subscription. +## +## Value: boolean +## zone.internal.wildcard_subscription = true + +## See zone.$name.shared_subscription. +## +## Value: boolean +## zone.internal.shared_subscription = true + +## See zone.$name.max_subscriptions. +## +## Value: Integer +zone.internal.max_subscriptions = 0 + +## See zone.$name.max_inflight +## +## Value: Number +zone.internal.max_inflight = 128 + +## See zone.$name.max_awaiting_rel +## +## Value: Number +zone.internal.max_awaiting_rel = 1000 + +## See zone.$name.max_mqueue_len +## +## Value: Number >= 0 +zone.internal.max_mqueue_len = 10000 + +## Whether to enqueue Qos0 messages. +## +## Value: false | true +zone.internal.mqueue_store_qos0 = true + +## Whether to turn on flapping detect +## +## Value: on | off +zone.internal.enable_flapping_detect = off + +## See zone.$name.force_shutdown_policy +zone.internal.force_shutdown_policy = 128000|28MB + +## All the topics will be prefixed with the mountpoint path if this option is enabled. +## +## Variables in mountpoint path: +## - %c: clientid +## - %u: username +## +## Value: String +## zone.internal.mountpoint = cloudbound/ + +## Whether to ignore loop delivery of messages.(for mqtt v3.1.1) +## +## Value: true | false +zone.internal.ignore_loop_deliver = false + +## Whether to parse the MQTT frame in strict mode +## +## Value: true | false +zone.internal.strict_mode = false + +## Specify the response information returned to the client +## +## Value: String +## zone.internal.response_information = example + +## Allow the zone's clients to bypass authentication step +## +## Value: true | false +zone.internal.bypass_auth_plugins = true + +##-------------------------------------------------------------------- +## Listeners +##-------------------------------------------------------------------- + +##-------------------------------------------------------------------- +## MQTT/TCP - External TCP Listener for MQTT Protocol + +## listener.tcp.$name is the IP address and port that the MQTT/TCP +## listener will bind. +## +## Value: IP:Port | Port +## +## Examples: 1883, 127.0.0.1:1883, ::1:1883 +listener.tcp.external = 0.0.0.0:1883 + +## The acceptor pool for external MQTT/TCP listener. +## +## Value: Number +listener.tcp.external.acceptors = 8 + +## Maximum number of concurrent MQTT/TCP connections. +## +## Value: Number +listener.tcp.external.max_connections = 1024000 + +## Maximum external connections per second. +## +## Value: Number +listener.tcp.external.max_conn_rate = 1000 + +## Specify the {active, N} option for the external MQTT/TCP Socket. +## +## Value: Number +listener.tcp.external.active_n = 100 + +## Zone of the external MQTT/TCP listener belonged to. +## +## See: zone.$name.* +## +## Value: String +listener.tcp.external.zone = external + +## The access control rules for the MQTT/TCP listener. +## +## See: https://github.com/emqtt/esockd#allowdeny +## +## Value: ACL Rule +## +## Example: allow 192.168.0.0/24 +listener.tcp.external.access.1 = allow all + +## Enable the Proxy Protocol V1/2 if the EMQ X cluster is deployed +## behind HAProxy or Nginx. +## +## See: https://www.haproxy.com/blog/haproxy/proxy-protocol/ +## +## Value: on | off +## listener.tcp.external.proxy_protocol = on + +## Sets the timeout for proxy protocol. EMQ X will close the TCP connection +## if no proxy protocol packet recevied within the timeout. +## +## Value: Duration +## listener.tcp.external.proxy_protocol_timeout = 3s + +## Enable the option for X.509 certificate based authentication. +## EMQX will use the common name of certificate as MQTT username. +## +## Value: cn | dn | crt +## listener.tcp.external.peer_cert_as_username = cn + +## The TCP backlog defines the maximum length that the queue of pending +## connections can grow to. +## +## Value: Number >= 0 +listener.tcp.external.backlog = 1024 + +## The TCP send timeout for external MQTT connections. +## +## Value: Duration +listener.tcp.external.send_timeout = 15s + +## Close the TCP connection if send timeout. +## +## Value: on | off +listener.tcp.external.send_timeout_close = on + +## The TCP receive buffer(os kernel) for MQTT connections. +## +## See: http://erlang.org/doc/man/inet.html +## +## Value: Bytes +## listener.tcp.external.recbuf = 2KB + +## The TCP send buffer(os kernel) for MQTT connections. +## +## See: http://erlang.org/doc/man/inet.html +## +## Value: Bytes +## listener.tcp.external.sndbuf = 2KB + +## The size of the user-level software buffer used by the driver. +## Not to be confused with options sndbuf and recbuf, which correspond +## to the Kernel socket buffers. It is recommended to have val(buffer) +## >= max(val(sndbuf),val(recbuf)) to avoid performance issues because +## of unnecessary copying. val(buffer) is automatically set to the above +## maximum when values sndbuf or recbuf are set. +## +## See: http://erlang.org/doc/man/inet.html +## +## Value: Bytes +## listener.tcp.external.buffer = 2KB + +## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. +## +## Value: on | off +## listener.tcp.external.tune_buffer = off + +## The socket is set to a busy state when the amount of data queued internally +## by the ERTS socket implementation reaches this limit. +## +## Value: on | off +## Defaults to 1MB +## listener.tcp.external.high_watermark = 1MB + +## The TCP_NODELAY flag for MQTT connections. Small amounts of data are +## sent immediately if the option is enabled. +## +## Value: true | false +listener.tcp.external.nodelay = true + +## The SO_REUSEADDR flag for TCP listener. +## +## Value: true | false +listener.tcp.external.reuseaddr = true + +##-------------------------------------------------------------------- +## Internal TCP Listener for MQTT Protocol + +## The IP address and port that the internal MQTT/TCP protocol listener +## will bind. +## +## Value: IP:Port, Port +## +## Examples: 11883, 127.0.0.1:11883, ::1:11883 +listener.tcp.internal = 127.0.0.1:11883 + +## The acceptor pool for internal MQTT/TCP listener. +## +## Value: Number +listener.tcp.internal.acceptors = 4 + +## Maximum number of concurrent MQTT/TCP connections. +## +## Value: Number +listener.tcp.internal.max_connections = 1024000 + +## Maximum internal connections per second. +## +## Value: Number +listener.tcp.internal.max_conn_rate = 1000 + +## Specify the {active, N} option for the internal MQTT/TCP Socket. +## +## Value: Number +listener.tcp.internal.active_n = 1000 + +## Zone of the internal MQTT/TCP listener belonged to. +## +## Value: String +listener.tcp.internal.zone = internal + +## The TCP backlog of internal MQTT/TCP Listener. +## +## See: listener.tcp.$name.backlog +## +## Value: Number >= 0 +listener.tcp.internal.backlog = 512 + +## The TCP send timeout for internal MQTT connections. +## +## See: listener.tcp.$name.send_timeout +## +## Value: Duration +listener.tcp.internal.send_timeout = 5s + +## Close the MQTT/TCP connection if send timeout. +## +## See: listener.tcp.$name.send_timeout_close +## +## Value: on | off +listener.tcp.internal.send_timeout_close = on + +## The TCP receive buffer(os kernel) for internal MQTT connections. +## +## See: listener.tcp.$name.recbuf +## +## Value: Bytes +listener.tcp.internal.recbuf = 64KB + +## The TCP send buffer(os kernel) for internal MQTT connections. +## +## See: http://erlang.org/doc/man/inet.html +## +## Value: Bytes +listener.tcp.internal.sndbuf = 64KB + +## The size of the user-level software buffer used by the driver. +## +## See: listener.tcp.$name.buffer +## +## Value: Bytes +## listener.tcp.internal.buffer = 16KB + +## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. +## +## See: listener.tcp.$name.tune_buffer +## +## Value: on | off +## listener.tcp.internal.tune_buffer = off + +## The TCP_NODELAY flag for internal MQTT connections. +## +## See: listener.tcp.$name.nodelay +## +## Value: true | false +listener.tcp.internal.nodelay = false + +## The SO_REUSEADDR flag for MQTT/TCP Listener. +## +## Value: true | false +listener.tcp.internal.reuseaddr = true + +##-------------------------------------------------------------------- +## MQTT/SSL - External SSL Listener for MQTT Protocol + +## listener.ssl.$name is the IP address and port that the MQTT/SSL +## listener will bind. +## +## Value: IP:Port | Port +## +## Examples: 8883, 127.0.0.1:8883, ::1:8883 +listener.ssl.external = 8883 + +## The acceptor pool for external MQTT/SSL listener. +## +## Value: Number +listener.ssl.external.acceptors = 16 + +## Maximum number of concurrent MQTT/SSL connections. +## +## Value: Number +listener.ssl.external.max_connections = 102400 + +## Maximum MQTT/SSL connections per second. +## +## Value: Number +listener.ssl.external.max_conn_rate = 500 + +## Specify the {active, N} option for the internal MQTT/SSL Socket. +## +## Value: Number +listener.ssl.external.active_n = 100 + +## Zone of the external MQTT/SSL listener belonged to. +## +## Value: String +listener.ssl.external.zone = external + +## The access control rules for the MQTT/SSL listener. +## +## See: listener.tcp.$name.access +## +## Value: ACL Rule +listener.ssl.external.access.1 = allow all + +## Enable the Proxy Protocol V1/2 if the EMQ cluster is deployed behind +## HAProxy or Nginx. +## +## See: listener.tcp.$name.proxy_protocol +## +## Value: on | off +## listener.ssl.external.proxy_protocol = on + +## Sets the timeout for proxy protocol. +## +## See: listener.tcp.$name.proxy_protocol_timeout +## +## Value: Duration +## listener.ssl.external.proxy_protocol_timeout = 3s + +## TLS versions only to protect from POODLE attack. +## +## See: http://erlang.org/doc/man/ssl.html +## +## Value: String, seperated by ',' +## listener.ssl.external.tls_versions = tlsv1.2,tlsv1.1,tlsv1 + +## TLS Handshake timeout. +## +## Value: Duration +listener.ssl.external.handshake_timeout = 15s + +## Maximum number of non-self-issued intermediate certificates that +## can follow the peer certificate in a valid certification path. +## +## Value: Number +## listener.ssl.external.depth = 10 + +## String containing the user's password. Only used if the private keyfile +## is password-protected. +## +## Value: String +## listener.ssl.external.key_password = yourpass + +## Path to the file containing the user's private PEM-encoded key. +## +## See: http://erlang.org/doc/man/ssl.html +## +## Value: File +listener.ssl.external.keyfile = {{ platform_etc_dir }}/certs/key.pem + +## Path to a file containing the user certificate. +## +## See: http://erlang.org/doc/man/ssl.html +## +## Value: File +listener.ssl.external.certfile = {{ platform_etc_dir }}/certs/cert.pem + +## Path to the file containing PEM-encoded CA certificates. The CA certificates +## are used during server authentication and when building the client certificate chain. +## +## Value: File +## listener.ssl.external.cacertfile = {{ platform_etc_dir }}/certs/cacert.pem + +## The Ephemeral Diffie-Helman key exchange is a very effective way of +## ensuring Forward Secrecy by exchanging a set of keys that never hit +## the wire. Since the DH key is effectively signed by the private key, +## it needs to be at least as strong as the private key. In addition, +## the default DH groups that most of the OpenSSL installations have +## are only a handful (since they are distributed with the OpenSSL +## package that has been built for the operating system it’s running on) +## and hence predictable (not to mention, 1024 bits only). +## In order to escape this situation, first we need to generate a fresh, +## strong DH group, store it in a file and then use the option above, +## to force our SSL application to use the new DH group. Fortunately, +## OpenSSL provides us with a tool to do that. Simply run: +## openssl dhparam -out dh-params.pem 2048 +## +## Value: File +## listener.ssl.external.dhfile = {{ platform_etc_dir }}/certs/dh-params.pem + +## A server only does x509-path validation in mode verify_peer, +## as it then sends a certificate request to the client (this +## message is not sent if the verify option is verify_none). +## You can then also want to specify option fail_if_no_peer_cert. +## More information at: http://erlang.org/doc/man/ssl.html +## +## Value: verify_peer | verify_none +## listener.ssl.external.verify = verify_peer + +## Used together with {verify, verify_peer} by an SSL server. If set to true, +## the server fails if the client does not have a certificate to send, that is, +## sends an empty certificate. +## +## Value: true | false +## listener.ssl.external.fail_if_no_peer_cert = true + +## This is the single most important configuration option of an Erlang SSL +## application. Ciphers (and their ordering) define the way the client and +## server encrypt information over the wire, from the initial Diffie-Helman +## key exchange, the session key encryption ## algorithm and the message +## digest algorithm. Selecting a good cipher suite is critical for the +## application’s data security, confidentiality and performance. +## +## The cipher list above offers: +## +## A good balance between compatibility with older browsers. +## It can get stricter for Machine-To-Machine scenarios. +## Perfect Forward Secrecy. +## No old/insecure encryption and HMAC algorithms +## +## Most of it was copied from Mozilla’s Server Side TLS article +## +## Value: Ciphers +listener.ssl.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA + + +## Ciphers for TLS PSK. +## Note that 'listener.ssl.external.ciphers' and 'listener.ssl.external.psk_ciphers' cannot +## be configured at the same time. +## See 'https://tools.ietf.org/html/rfc4279#section-2'. +#listener.ssl.external.psk_ciphers = PSK-AES128-CBC-SHA,PSK-AES256-CBC-SHA,PSK-3DES-EDE-CBC-SHA,PSK-RC4-SHA + +## SSL parameter renegotiation is a feature that allows a client and a server +## to renegotiate the parameters of the SSL connection on the fly. +## RFC 5746 defines a more secure way of doing this. By enabling secure renegotiation, +## you drop support for the insecure renegotiation, prone to MitM attacks. +## +## Value: on | off +## listener.ssl.external.secure_renegotiate = off + +## A performance optimization setting, it allows clients to reuse +## pre-existing sessions, instead of initializing new ones. +## Read more about it here. +## +## See: http://erlang.org/doc/man/ssl.html +## +## Value: on | off +## listener.ssl.external.reuse_sessions = on + +## An important security setting, it forces the cipher to be set based +## on the server-specified order instead of the client-specified order, +## hence enforcing the (usually more properly configured) security +## ordering of the server administrator. +## +## Value: on | off +## listener.ssl.external.honor_cipher_order = on + +## Use the CN, DN or CRT field from the client certificate as a username. +## Notice that 'verify' should be set as 'verify_peer'. +## +## Value: cn | dn | crt +## listener.ssl.external.peer_cert_as_username = cn + +## TCP backlog for the SSL connection. +## +## See listener.tcp.$name.backlog +## +## Value: Number >= 0 +## listener.ssl.external.backlog = 1024 + +## The TCP send timeout for the SSL connection. +## +## See listener.tcp.$name.send_timeout +## +## Value: Duration +## listener.ssl.external.send_timeout = 15s + +## Close the SSL connection if send timeout. +## +## See: listener.tcp.$name.send_timeout_close +## +## Value: on | off +## listener.ssl.external.send_timeout_close = on + +## The TCP receive buffer(os kernel) for the SSL connections. +## +## See: listener.tcp.$name.recbuf +## +## Value: Bytes +## listener.ssl.external.recbuf = 4KB + +## The TCP send buffer(os kernel) for internal MQTT connections. +## +## See: listener.tcp.$name.sndbuf +## +## Value: Bytes +## listener.ssl.external.sndbuf = 4KB + +## The size of the user-level software buffer used by the driver. +## +## See: listener.tcp.$name.buffer +## +## Value: Bytes +## listener.ssl.external.buffer = 4KB + +## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. +## +## See: listener.tcp.$name.tune_buffer +## +## Value: on | off +## listener.ssl.external.tune_buffer = off + +## The TCP_NODELAY flag for SSL connections. +## +## See: listener.tcp.$name.nodelay +## +## Value: true | false +## listener.ssl.external.nodelay = true + +## The SO_REUSEADDR flag for MQTT/SSL Listener. +## +## Value: true | false +listener.ssl.external.reuseaddr = true + +##-------------------------------------------------------------------- +## External WebSocket listener for MQTT protocol + +## listener.ws.$name is the IP address and port that the MQTT/WebSocket +## listener will bind. +## +## Value: IP:Port | Port +## +## Examples: 8083, 127.0.0.1:8083, ::1:8083 +listener.ws.external = 8083 + +## The path of WebSocket MQTT endpoint +## +## Value: URL Path +listener.ws.external.mqtt_path = /mqtt + +## The acceptor pool for external MQTT/WebSocket listener. +## +## Value: Number +listener.ws.external.acceptors = 4 + +## Maximum number of concurrent MQTT/WebSocket connections. +## +## Value: Number +listener.ws.external.max_connections = 102400 + +## Maximum MQTT/WebSocket connections per second. +## +## Value: Number +listener.ws.external.max_conn_rate = 1000 + +## Simulate the {active, N} option for the MQTT/WebSocket connections. +## +## Value: Number +listener.ws.external.active_n = 100 + +## Zone of the external MQTT/WebSocket listener belonged to. +## +## Value: String +listener.ws.external.zone = external + +## The access control for the MQTT/WebSocket listener. +## +## See: listener.ws.$name.access +## +## Value: ACL Rule +listener.ws.external.access.1 = allow all + +## If set to true, the server fails if the client does not have a Sec-WebSocket-Protocol to send. +## Set to false for WeChat MiniApp. +## +## Value: true | false +## listener.ws.external.fail_if_no_subprotocol = on + +## Supported subprotocols +## +## Default: mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5 +## listener.ws.external.supported_protocols = mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5 + +## Enable the Proxy Protocol V1/2 if the EMQ cluster is deployed behind +## HAProxy or Nginx. +## +## See: listener.ws.$name.proxy_protocol +## +## Value: on | off +## listener.ws.external.proxy_protocol = on + +## Sets the timeout for proxy protocol. +## +## See: listener.ws.$name.proxy_protocol_timeout +## +## Value: Duration +## listener.ws.external.proxy_protocol_timeout = 3s + +## The TCP backlog of external MQTT/WebSocket Listener. +## +## See: listener.ws.$name.backlog +## +## Value: Number >= 0 +listener.ws.external.backlog = 1024 + +## The TCP send timeout for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.send_timeout +## +## Value: Duration +listener.ws.external.send_timeout = 15s + +## Close the MQTT/WebSocket connection if send timeout. +## +## See: listener.ws.$name.send_timeout_close +## +## Value: on | off +listener.ws.external.send_timeout_close = on + +## The TCP receive buffer(os kernel) for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.recbuf +## +## Value: Bytes +## listener.ws.external.recbuf = 2KB + +## The TCP send buffer(os kernel) for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.sndbuf +## +## Value: Bytes +## listener.ws.external.sndbuf = 2KB + +## The size of the user-level software buffer used by the driver. +## +## See: listener.ws.$name.buffer +## +## Value: Bytes +## listener.ws.external.buffer = 2KB + +## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. +## +## See: listener.ws.$name.tune_buffer +## +## Value: on | off +## listener.ws.external.tune_buffer = off + +## The TCP_NODELAY flag for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.nodelay +## +## Value: true | false +listener.ws.external.nodelay = true + +## The compress flag for external MQTT/WebSocket connections. +## +## If this Value is set true,the websocket message would be compressed +## +## Value: true | false +## listener.ws.external.compress = true + +## The level of deflate options for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.level +## +## Value: none | default | best_compression | best_speed +## listener.ws.external.deflate_opts.level = default + +## The mem_level of deflate options for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.mem_level +## +## Valid range is 1-9 +## listener.ws.external.deflate_opts.mem_level = 8 + +## The strategy of deflate options for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.strategy +## +## Value: default | filtered | huffman_only | rle +## listener.ws.external.deflate_opts.strategy = default + +## The deflate option for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.server_context_takeover +## +## Value: takeover | no_takeover +## listener.ws.external.deflate_opts.server_context_takeover = takeover + +## The deflate option for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.client_context_takeover +## +## Value: takeover | no_takeover +## listener.ws.external.deflate_opts.client_context_takeover = takeover + +## The deflate options for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.server_max_window_bits +## +## Valid range is 8-15 +## listener.ws.external.deflate_opts.server_max_window_bits = 15 + +## The deflate options for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.deflate_opts.client_max_window_bits +## +## Valid range is 8-15 +## listener.ws.external.deflate_opts.client_max_window_bits = 15 + +## The idle timeout for external MQTT/WebSocket connections. +## +## See: listener.ws.$name.idle_timeout +## +## Value: Duration +## listener.ws.external.idle_timeout = 60s + +## The max frame size for external MQTT/WebSocket connections. +## +## +## Value: Number +## listener.ws.external.max_frame_size = 0 + +## Whether a WebSocket message is allowed to contain multiple MQTT packets +## +## Value: single | multiple +## listener.ws.external.mqtt_piggyback = multiple + +##-------------------------------------------------------------------- +## External WebSocket/SSL listener for MQTT Protocol + +## listener.wss.$name is the IP address and port that the MQTT/WebSocket/SSL +## listener will bind. +## +## Value: IP:Port | Port +## +## Examples: 8084, 127.0.0.1:8084, ::1:8084 +listener.wss.external = 8084 + +## The path of WebSocket MQTT endpoint +## +## Value: URL Path +listener.wss.external.mqtt_path = /mqtt + +## The acceptor pool for external MQTT/WebSocket/SSL listener. +## +## Value: Number +listener.wss.external.acceptors = 4 + +## Maximum number of concurrent MQTT/Webwocket/SSL connections. +## +## Value: Number +listener.wss.external.max_connections = 16 + +## Maximum MQTT/WebSocket/SSL connections per second. +## +## See: listener.tcp.$name.max_conn_rate +## +## Value: Number +listener.wss.external.max_conn_rate = 1000 + +## Simulate the {active, N} option for the MQTT/WebSocket/SSL connections. +## +## Value: Number +listener.wss.external.active_n = 100 + +## Zone of the external MQTT/WebSocket/SSL listener belonged to. +## +## Value: String +listener.wss.external.zone = external + +## The access control rules for the MQTT/WebSocket/SSL listener. +## +## See: listener.tcp.$name.access. +## +## Value: ACL Rule +listener.wss.external.access.1 = allow all + +## If set to true, the server fails if the client does not have a Sec-WebSocket-Protocol to send. +## Set to false for WeChat MiniApp. +## +## Value: true | false +## listener.wss.external.fail_if_no_subprotocol = true + +## Supported subprotocols +## +## Default: mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5 +## listener.wss.external.supported_protocols = mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5 + +## Enable the Proxy Protocol V1/2 support. +## +## See: listener.tcp.$name.proxy_protocol +## +## Value: on | off +## listener.wss.external.proxy_protocol = on + +## Sets the timeout for proxy protocol. +## +## See: listener.tcp.$name.proxy_protocol_timeout +## +## Value: Duration +## listener.wss.external.proxy_protocol_timeout = 3s + +## TLS versions only to protect from POODLE attack. +## +## See: listener.ssl.$name.tls_versions +## +## Value: String, seperated by ',' +## listener.wss.external.tls_versions = tlsv1.2,tlsv1.1,tlsv1 + +## Path to the file containing the user's private PEM-encoded key. +## +## See: listener.ssl.$name.keyfile +## +## Value: File +listener.wss.external.keyfile = {{ platform_etc_dir }}/certs/key.pem + +## Path to a file containing the user certificate. +## +## See: listener.ssl.$name.certfile +## +## Value: File +listener.wss.external.certfile = {{ platform_etc_dir }}/certs/cert.pem + +## Path to the file containing PEM-encoded CA certificates. +## +## See: listener.ssl.$name.cacert +## +## Value: File +## listener.wss.external.cacertfile = {{ platform_etc_dir }}/certs/cacert.pem + +## Maximum number of non-self-issued intermediate certificates that +## can follow the peer certificate in a valid certification path. +## +## See: listener.ssl.external.depth +## +## Value: Number +## listener.wss.external.depth = 10 + +## String containing the user's password. Only used if the private keyfile +## is password-protected. +## +## See: listener.ssl.$name.key_password +## +## Value: String +## listener.wss.external.key_password = yourpass + +## See: listener.ssl.$name.dhfile +## +## Value: File +## listener.ssl.external.dhfile = {{ platform_etc_dir }}/certs/dh-params.pem + +## See: listener.ssl.$name.verify +## +## Value: verify_peer | verify_none +## listener.wss.external.verify = verify_peer + +## See: listener.ssl.$name.fail_if_no_peer_cert +## +## Value: false | true +## listener.wss.external.fail_if_no_peer_cert = true + +## See: listener.ssl.$name.ciphers +## +## Value: Ciphers +listener.wss.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA + +## Ciphers for TLS PSK. +## Note that 'listener.wss.external.ciphers' and 'listener.wss.external.psk_ciphers' cannot +## be configured at the same time. +## See 'https://tools.ietf.org/html/rfc4279#section-2'. +## listener.wss.external.psk_ciphers = PSK-AES128-CBC-SHA,PSK-AES256-CBC-SHA,PSK-3DES-EDE-CBC-SHA,PSK-RC4-SHA + +## See: listener.ssl.$name.secure_renegotiate +## +## Value: on | off +## listener.wss.external.secure_renegotiate = off + +## See: listener.ssl.$name.reuse_sessions +## +## Value: on | off +## listener.wss.external.reuse_sessions = on + +## See: listener.ssl.$name.honor_cipher_order +## +## Value: on | off +## listener.wss.external.honor_cipher_order = on + +## See: listener.ssl.$name.peer_cert_as_username +## +## Value: cn | dn | crt +## listener.wss.external.peer_cert_as_username = cn + +## TCP backlog for the WebSocket/SSL connection. +## +## See: listener.tcp.$name.backlog +## +## Value: Number >= 0 +listener.wss.external.backlog = 1024 + +## The TCP send timeout for the WebSocket/SSL connection. +## +## See: listener.tcp.$name.send_timeout +## +## Value: Duration +listener.wss.external.send_timeout = 15s + +## Close the WebSocket/SSL connection if send timeout. +## +## See: listener.tcp.$name.send_timeout_close +## +## Value: on | off +listener.wss.external.send_timeout_close = on + +## The TCP receive buffer(os kernel) for the WebSocket/SSL connections. +## +## See: listener.tcp.$name.recbuf +## +## Value: Bytes +## listener.wss.external.recbuf = 4KB + +## The TCP send buffer(os kernel) for the WebSocket/SSL connections. +## +## See: listener.tcp.$name.sndbuf +## +## Value: Bytes +## listener.wss.external.sndbuf = 4KB + +## The size of the user-level software buffer used by the driver. +## +## See: listener.tcp.$name.buffer +## +## Value: Bytes +## listener.wss.external.buffer = 4KB + +## The TCP_NODELAY flag for WebSocket/SSL connections. +## +## See: listener.tcp.$name.nodelay +## +## Value: true | false +## listener.wss.external.nodelay = true + +## The compress flag for external WebSocket/SSL connections. +## +## If this Value is set true,the websocket message would be compressed +## +## Value: true | false +## listener.wss.external.compress = true + +## The level of deflate options for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.level +## +## Value: none | default | best_compression | best_speed +## listener.wss.external.deflate_opts.level = default + +## The mem_level of deflate options for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.mem_level +## +## Valid range is 1-9 +## listener.wss.external.deflate_opts.mem_level = 8 + +## The strategy of deflate options for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.strategy +## +## Value: default | filtered | huffman_only | rle +## listener.wss.external.deflate_opts.strategy = default + +## The deflate option for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.server_context_takeover +## +## Value: takeover | no_takeover +## listener.wss.external.deflate_opts.server_context_takeover = takeover + +## The deflate option for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.client_context_takeover +## +## Value: takeover | no_takeover +## listener.wss.external.deflate_opts.client_context_takeover = takeover + +## The deflate options for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.server_max_window_bits +## +## Valid range is 8-15 +## listener.wss.external.deflate_opts.server_max_window_bits = 15 + +## The deflate options for external WebSocket/SSL connections. +## +## See: listener.wss.$name.deflate_opts.client_max_window_bits +## +## Valid range is 8-15 +## listener.wss.external.deflate_opts.client_max_window_bits = 15 + +## The idle timeout for external WebSocket/SSL connections. +## +## See: listener.wss.$name.idle_timeout +## +## Value: Duration +## listener.wss.external.idle_timeout = 60s + +## The max frame size for external WebSocket/SSL connections. +## +## Value: Number +## listener.wss.external.max_frame_size = 0 + +## Whether a WebSocket message is allowed to contain multiple MQTT packets +## +## Value: single | multiple +listener.wss.external.mqtt_piggyback = multiple + +##------------------------------------------------------------------- +## Plugins +##------------------------------------------------------------------- + +## The etc dir for plugins' config. +## +## Value: Folder +plugins.etc_dir = {{ platform_etc_dir }}/plugins/ + +## The file to store loaded plugin names. +## +## Value: File +plugins.loaded_file = {{ platform_data_dir }}/loaded_plugins + +## The directory of extension plugins. +## +## Value: File +plugins.expand_plugins_dir = {{ platform_plugins_dir }}/ + ##-------------------------------------------------------------------- ## Broker ##-------------------------------------------------------------------- @@ -268,7 +2031,7 @@ broker.sys_heartbeat = 30s ## ## Value: Enum ## - local -## - one +## - leader ## - quorum ## - all broker.session_locking_strategy = quorum @@ -279,7 +2042,9 @@ broker.session_locking_strategy = quorum ## - random ## - round_robin ## - sticky -## - hash +## - hash # same as hash_clientid +## - hash_clientid +## - hash_topic broker.shared_subscription_strategy = random ## Enable/disable shared dispatch acknowledgement for QoS1 and QoS2 messages @@ -296,18 +2061,153 @@ broker.shared_dispatch_ack_enabled = false ## Value: Flag broker.route_batch_clean = off -##------------------------------------------------------------------- -## Plugins -##------------------------------------------------------------------- +##-------------------------------------------------------------------- +## System Monitor +##-------------------------------------------------------------------- -## The etc dir for plugins' config. +## Enable Long GC monitoring. Disable if the value is 0. +## Notice: don't enable the monitor in production for: +## https://github.com/erlang/otp/blob/feb45017da36be78d4c5784d758ede619fa7bfd3/erts/emulator/beam/erl_gc.c#L421 ## -## Value: Folder -plugins.etc_dir = {{ platform_etc_dir }}/plugins/ +## Value: Duration +## - h: hour +## - m: minute +## - s: second +## - ms: milliseconds +## +## Examples: +## - 2h: 2 hours +## - 30m: 30 minutes +## - 0.1s: 0.1 seconds +## - 100ms : 100 milliseconds +## +## Default: 0ms +sysmon.long_gc = 0 -## The file to store loaded plugin names. +## Enable Long Schedule(ms) monitoring. ## -## Value: File -plugins.loaded_file = {{ platform_data_dir }}/loaded_plugins +## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 +## +## Value: Duration +## - h: hour +## - m: minute +## - s: second +## - ms: milliseconds +## +## Examples: +## - 2h: 2 hours +## - 30m: 30 minutes +## - 0.1s: 0.1 seconds +## - 100ms: 100 milliseconds +## +## Default: 0ms +sysmon.long_schedule = 240ms + +## Enable Large Heap monitoring. +## +## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 +## +## Value: bytes +## +## Default: 8M words. 32MB on 32-bit VM, 64MB on 64-bit VM. +sysmon.large_heap = 8MB + +## Enable Busy Port monitoring. +## +## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 +## +## Value: true | false +sysmon.busy_port = false + +## Enable Busy Dist Port monitoring. +## +## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 +## +## Value: true | false +sysmon.busy_dist_port = true + +## The time interval for the periodic cpu check +## +## Value: Duration +## -h: hour, e.g. '2h' for 2 hours +## -m: minute, e.g. '5m' for 5 minutes +## -s: second, e.g. '30s' for 30 seconds +## +## Default: 60s +os_mon.cpu_check_interval = 60s + +## The threshold, as percentage of system cpu, for how much system cpu can be used before the corresponding alarm is set. +## +## Default: 80% +os_mon.cpu_high_watermark = 80% + +## The threshold, as percentage of system cpu, for how much system cpu can be used before the corresponding alarm is clear. +## +## Default: 60% +os_mon.cpu_low_watermark = 60% + +## The time interval for the periodic memory check +## +## Value: Duration +## -h: hour, e.g. '2h' for 2 hours +## -m: minute, e.g. '5m' for 5 minutes +## -s: second, e.g. '30s' for 30 seconds +## +## Default: 60s +os_mon.mem_check_interval = 60s + +## The threshold, as percentage of system memory, for how much system memory can be allocated before the corresponding alarm is set. +## +## Default: 70% +os_mon.sysmem_high_watermark = 70% + +## The threshold, as percentage of system memory, for how much system memory can be allocated by one Erlang process before the corresponding alarm is set. +## +## Default: 5% +os_mon.procmem_high_watermark = 5% + +## The time interval for the periodic process limit check +## +## Value: Duration +## +## Default: 30s +vm_mon.check_interval = 30s + +## The threshold, as percentage of processes, for how many processes can simultaneously exist at the local node before the corresponding alarm is set. +## +## Default: 80% +vm_mon.process_high_watermark = 80% + +## The threshold, as percentage of processes, for how many processes can simultaneously exist at the local node before the corresponding alarm is clear. +## +## Default: 60% +vm_mon.process_low_watermark = 60% + +## Specifies the actions to take when an alarm is activated +## +## Value: String +## - log +## - publish +## +## Default: log,publish +alarm.actions = log,publish + +## The maximum number of deactivated alarms +## +## Value: Integer +## +## Default: 1000 +alarm.size_limit = 1000 + +## Validity Period of deactivated alarms +## +## Value: Duration +## - h: hour +## - m: minute +## - s: second +## - ms: milliseconds +## +## Default: 24h +alarm.validity_period = 24h {{ additional_configs }} diff --git a/etc/listeners.conf b/etc/listeners.conf deleted file mode 100644 index 034321b2a..000000000 --- a/etc/listeners.conf +++ /dev/null @@ -1,940 +0,0 @@ -##-------------------------------------------------------------------- -## Listeners -##-------------------------------------------------------------------- - -##-------------------------------------------------------------------- -## MQTT/TCP - External TCP Listener for MQTT Protocol - -## listener.tcp.$name is the IP address and port that the MQTT/TCP -## listener will bind. -## -## Value: IP:Port | Port -## -## Examples: 1883, 127.0.0.1:1883, ::1:1883 -listener.tcp.external = 0.0.0.0:1883 - -## The acceptor pool for external MQTT/TCP listener. -## -## Value: Number -listener.tcp.external.acceptors = 8 - -## Maximum number of concurrent MQTT/TCP connections. -## -## Value: Number -listener.tcp.external.max_connections = 1024000 - -## Maximum external connections per second. -## -## Value: Number -listener.tcp.external.max_conn_rate = 1000 - -## Specify the {active, N} option for the external MQTT/TCP Socket. -## -## Value: Number -listener.tcp.external.active_n = 100 - -## Zone of the external MQTT/TCP listener belonged to. -## -## See: zone.$name.* -## -## Value: String -listener.tcp.external.zone = external - -## The access control rules for the MQTT/TCP listener. -## -## See: https://github.com/emqtt/esockd#allowdeny -## -## Value: ACL Rule -## -## Example: allow 192.168.0.0/24 -listener.tcp.external.access.1 = allow all - -## Enable the Proxy Protocol V1/2 if the EMQ X cluster is deployed -## behind HAProxy or Nginx. -## -## See: https://www.haproxy.com/blog/haproxy/proxy-protocol/ -## -## Value: on | off -## listener.tcp.external.proxy_protocol = on - -## Sets the timeout for proxy protocol. EMQ X will close the TCP connection -## if no proxy protocol packet recevied within the timeout. -## -## Value: Duration -## listener.tcp.external.proxy_protocol_timeout = 3s - -## Enable the option for X.509 certificate based authentication. -## EMQX will use the common name of certificate as MQTT username. -## -## Value: cn | dn | crt -## listener.tcp.external.peer_cert_as_username = cn - -## The TCP backlog defines the maximum length that the queue of pending -## connections can grow to. -## -## Value: Number >= 0 -listener.tcp.external.backlog = 1024 - -## The TCP send timeout for external MQTT connections. -## -## Value: Duration -listener.tcp.external.send_timeout = 15s - -## Close the TCP connection if send timeout. -## -## Value: on | off -listener.tcp.external.send_timeout_close = on - -## The TCP receive buffer(os kernel) for MQTT connections. -## -## See: http://erlang.org/doc/man/inet.html -## -## Value: Bytes -## listener.tcp.external.recbuf = 2KB - -## The TCP send buffer(os kernel) for MQTT connections. -## -## See: http://erlang.org/doc/man/inet.html -## -## Value: Bytes -## listener.tcp.external.sndbuf = 2KB - -## The size of the user-level software buffer used by the driver. -## Not to be confused with options sndbuf and recbuf, which correspond -## to the Kernel socket buffers. It is recommended to have val(buffer) -## >= max(val(sndbuf),val(recbuf)) to avoid performance issues because -## of unnecessary copying. val(buffer) is automatically set to the above -## maximum when values sndbuf or recbuf are set. -## -## See: http://erlang.org/doc/man/inet.html -## -## Value: Bytes -## listener.tcp.external.buffer = 2KB - -## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. -## -## Value: on | off -## listener.tcp.external.tune_buffer = off - -## The socket is set to a busy state when the amount of data queued internally -## by the ERTS socket implementation reaches this limit. -## -## Value: on | off -## Defaults to 1MB -## listener.tcp.external.high_watermark = 1MB - -## The TCP_NODELAY flag for MQTT connections. Small amounts of data are -## sent immediately if the option is enabled. -## -## Value: true | false -listener.tcp.external.nodelay = true - -## The SO_REUSEADDR flag for TCP listener. -## -## Value: true | false -listener.tcp.external.reuseaddr = true - -##-------------------------------------------------------------------- -## Internal TCP Listener for MQTT Protocol - -## The IP address and port that the internal MQTT/TCP protocol listener -## will bind. -## -## Value: IP:Port, Port -## -## Examples: 11883, 127.0.0.1:11883, ::1:11883 -listener.tcp.internal = 127.0.0.1:11883 - -## The acceptor pool for internal MQTT/TCP listener. -## -## Value: Number -listener.tcp.internal.acceptors = 4 - -## Maximum number of concurrent MQTT/TCP connections. -## -## Value: Number -listener.tcp.internal.max_connections = 1024000 - -## Maximum internal connections per second. -## -## Value: Number -listener.tcp.internal.max_conn_rate = 1000 - -## Specify the {active, N} option for the internal MQTT/TCP Socket. -## -## Value: Number -listener.tcp.internal.active_n = 1000 - -## Zone of the internal MQTT/TCP listener belonged to. -## -## Value: String -listener.tcp.internal.zone = internal - -## The TCP backlog of internal MQTT/TCP Listener. -## -## See: listener.tcp.$name.backlog -## -## Value: Number >= 0 -listener.tcp.internal.backlog = 512 - -## The TCP send timeout for internal MQTT connections. -## -## See: listener.tcp.$name.send_timeout -## -## Value: Duration -listener.tcp.internal.send_timeout = 5s - -## Close the MQTT/TCP connection if send timeout. -## -## See: listener.tcp.$name.send_timeout_close -## -## Value: on | off -listener.tcp.internal.send_timeout_close = on - -## The TCP receive buffer(os kernel) for internal MQTT connections. -## -## See: listener.tcp.$name.recbuf -## -## Value: Bytes -listener.tcp.internal.recbuf = 64KB - -## The TCP send buffer(os kernel) for internal MQTT connections. -## -## See: http://erlang.org/doc/man/inet.html -## -## Value: Bytes -listener.tcp.internal.sndbuf = 64KB - -## The size of the user-level software buffer used by the driver. -## -## See: listener.tcp.$name.buffer -## -## Value: Bytes -## listener.tcp.internal.buffer = 16KB - -## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. -## -## See: listener.tcp.$name.tune_buffer -## -## Value: on | off -## listener.tcp.internal.tune_buffer = off - -## The TCP_NODELAY flag for internal MQTT connections. -## -## See: listener.tcp.$name.nodelay -## -## Value: true | false -listener.tcp.internal.nodelay = false - -## The SO_REUSEADDR flag for MQTT/TCP Listener. -## -## Value: true | false -listener.tcp.internal.reuseaddr = true - -##-------------------------------------------------------------------- -## MQTT/SSL - External SSL Listener for MQTT Protocol - -## listener.ssl.$name is the IP address and port that the MQTT/SSL -## listener will bind. -## -## Value: IP:Port | Port -## -## Examples: 8883, 127.0.0.1:8883, ::1:8883 -listener.ssl.external = 8883 - -## The acceptor pool for external MQTT/SSL listener. -## -## Value: Number -listener.ssl.external.acceptors = 16 - -## Maximum number of concurrent MQTT/SSL connections. -## -## Value: Number -listener.ssl.external.max_connections = 102400 - -## Maximum MQTT/SSL connections per second. -## -## Value: Number -listener.ssl.external.max_conn_rate = 500 - -## Specify the {active, N} option for the internal MQTT/SSL Socket. -## -## Value: Number -listener.ssl.external.active_n = 100 - -## Zone of the external MQTT/SSL listener belonged to. -## -## Value: String -listener.ssl.external.zone = external - -## The access control rules for the MQTT/SSL listener. -## -## See: listener.tcp.$name.access -## -## Value: ACL Rule -listener.ssl.external.access.1 = allow all - -## Enable the Proxy Protocol V1/2 if the EMQ cluster is deployed behind -## HAProxy or Nginx. -## -## See: listener.tcp.$name.proxy_protocol -## -## Value: on | off -## listener.ssl.external.proxy_protocol = on - -## Sets the timeout for proxy protocol. -## -## See: listener.tcp.$name.proxy_protocol_timeout -## -## Value: Duration -## listener.ssl.external.proxy_protocol_timeout = 3s - -## TLS versions only to protect from POODLE attack. -## -## See: http://erlang.org/doc/man/ssl.html -## -## Value: String, seperated by ',' -## listener.ssl.external.tls_versions = tlsv1.2,tlsv1.1,tlsv1 - -## TLS Handshake timeout. -## -## Value: Duration -listener.ssl.external.handshake_timeout = 15s - -## Maximum number of non-self-issued intermediate certificates that can follow the peer certificate in a valid certification path. -## -## Value: Number -## listener.ssl.external.depth = 10 - -## Path to the file containing the user's private PEM-encoded key. -## -## See: http://erlang.org/doc/man/ssl.html -## -## Value: File -listener.ssl.external.keyfile = {{ platform_etc_dir }}/certs/key.pem - -## Path to a file containing the user certificate. -## -## See: http://erlang.org/doc/man/ssl.html -## -## Value: File -listener.ssl.external.certfile = {{ platform_etc_dir }}/certs/cert.pem - -## Path to the file containing PEM-encoded CA certificates. The CA certificates -## are used during server authentication and when building the client certificate chain. -## -## Value: File -## listener.ssl.external.cacertfile = {{ platform_etc_dir }}/certs/cacert.pem - -## The Ephemeral Diffie-Helman key exchange is a very effective way of -## ensuring Forward Secrecy by exchanging a set of keys that never hit -## the wire. Since the DH key is effectively signed by the private key, -## it needs to be at least as strong as the private key. In addition, -## the default DH groups that most of the OpenSSL installations have -## are only a handful (since they are distributed with the OpenSSL -## package that has been built for the operating system it’s running on) -## and hence predictable (not to mention, 1024 bits only). -## In order to escape this situation, first we need to generate a fresh, -## strong DH group, store it in a file and then use the option above, -## to force our SSL application to use the new DH group. Fortunately, -## OpenSSL provides us with a tool to do that. Simply run: -## openssl dhparam -out dh-params.pem 2048 -## -## Value: File -## listener.ssl.external.dhfile = {{ platform_etc_dir }}/certs/dh-params.pem - -## A server only does x509-path validation in mode verify_peer, -## as it then sends a certificate request to the client (this -## message is not sent if the verify option is verify_none). -## You can then also want to specify option fail_if_no_peer_cert. -## More information at: http://erlang.org/doc/man/ssl.html -## -## Value: verify_peer | verify_none -## listener.ssl.external.verify = verify_peer - -## Used together with {verify, verify_peer} by an SSL server. If set to true, -## the server fails if the client does not have a certificate to send, that is, -## sends an empty certificate. -## -## Value: true | false -## listener.ssl.external.fail_if_no_peer_cert = true - -## This is the single most important configuration option of an Erlang SSL -## application. Ciphers (and their ordering) define the way the client and -## server encrypt information over the wire, from the initial Diffie-Helman -## key exchange, the session key encryption ## algorithm and the message -## digest algorithm. Selecting a good cipher suite is critical for the -## application’s data security, confidentiality and performance. -## -## The cipher list above offers: -## -## A good balance between compatibility with older browsers. -## It can get stricter for Machine-To-Machine scenarios. -## Perfect Forward Secrecy. -## No old/insecure encryption and HMAC algorithms -## -## Most of it was copied from Mozilla’s Server Side TLS article -## -## Value: Ciphers -listener.ssl.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA - -## Ciphers for TLS PSK. -## Note that 'listener.ssl.external.ciphers' and 'listener.ssl.external.psk_ciphers' cannot -## be configured at the same time. -## See 'https://tools.ietf.org/html/rfc4279#section-2'. -#listener.ssl.external.psk_ciphers = PSK-AES128-CBC-SHA,PSK-AES256-CBC-SHA,PSK-3DES-EDE-CBC-SHA,PSK-RC4-SHA - -## SSL parameter renegotiation is a feature that allows a client and a server -## to renegotiate the parameters of the SSL connection on the fly. -## RFC 5746 defines a more secure way of doing this. By enabling secure renegotiation, -## you drop support for the insecure renegotiation, prone to MitM attacks. -## -## Value: on | off -## listener.ssl.external.secure_renegotiate = off - -## A performance optimization setting, it allows clients to reuse -## pre-existing sessions, instead of initializing new ones. -## Read more about it here. -## -## See: http://erlang.org/doc/man/ssl.html -## -## Value: on | off -## listener.ssl.external.reuse_sessions = on - -## An important security setting, it forces the cipher to be set based -## on the server-specified order instead of the client-specified order, -## hence enforcing the (usually more properly configured) security -## ordering of the server administrator. -## -## Value: on | off -## listener.ssl.external.honor_cipher_order = on - -## Use the CN, DN or CRT field from the client certificate as a username. -## Notice that 'verify' should be set as 'verify_peer'. -## -## Value: cn | dn | crt -## listener.ssl.external.peer_cert_as_username = cn - -## TCP backlog for the SSL connection. -## -## See listener.tcp.$name.backlog -## -## Value: Number >= 0 -## listener.ssl.external.backlog = 1024 - -## The TCP send timeout for the SSL connection. -## -## See listener.tcp.$name.send_timeout -## -## Value: Duration -## listener.ssl.external.send_timeout = 15s - -## Close the SSL connection if send timeout. -## -## See: listener.tcp.$name.send_timeout_close -## -## Value: on | off -## listener.ssl.external.send_timeout_close = on - -## The TCP receive buffer(os kernel) for the SSL connections. -## -## See: listener.tcp.$name.recbuf -## -## Value: Bytes -## listener.ssl.external.recbuf = 4KB - -## The TCP send buffer(os kernel) for internal MQTT connections. -## -## See: listener.tcp.$name.sndbuf -## -## Value: Bytes -## listener.ssl.external.sndbuf = 4KB - -## The size of the user-level software buffer used by the driver. -## -## See: listener.tcp.$name.buffer -## -## Value: Bytes -## listener.ssl.external.buffer = 4KB - -## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. -## -## See: listener.tcp.$name.tune_buffer -## -## Value: on | off -## listener.ssl.external.tune_buffer = off - -## The TCP_NODELAY flag for SSL connections. -## -## See: listener.tcp.$name.nodelay -## -## Value: true | false -## listener.ssl.external.nodelay = true - -## The SO_REUSEADDR flag for MQTT/SSL Listener. -## -## Value: true | false -listener.ssl.external.reuseaddr = true - -##-------------------------------------------------------------------- -## External WebSocket listener for MQTT protocol - -## listener.ws.$name is the IP address and port that the MQTT/WebSocket -## listener will bind. -## -## Value: IP:Port | Port -## -## Examples: 8083, 127.0.0.1:8083, ::1:8083 -listener.ws.external = 8083 - -## The path of WebSocket MQTT endpoint -## -## Value: URL Path -listener.ws.external.mqtt_path = /mqtt - -## The acceptor pool for external MQTT/WebSocket listener. -## -## Value: Number -listener.ws.external.acceptors = 4 - -## Maximum number of concurrent MQTT/WebSocket connections. -## -## Value: Number -listener.ws.external.max_connections = 102400 - -## Maximum MQTT/WebSocket connections per second. -## -## Value: Number -listener.ws.external.max_conn_rate = 1000 - -## Simulate the {active, N} option for the MQTT/WebSocket connections. -## -## Value: Number -listener.ws.external.active_n = 100 - -## Zone of the external MQTT/WebSocket listener belonged to. -## -## Value: String -listener.ws.external.zone = external - -## The access control for the MQTT/WebSocket listener. -## -## See: listener.ws.$name.access -## -## Value: ACL Rule -listener.ws.external.access.1 = allow all - -## Verify if the protocol header is valid. Turn off for WeChat MiniApp. -## -## Value: on | off -listener.ws.external.verify_protocol_header = on - -## Enable the Proxy Protocol V1/2 if the EMQ cluster is deployed behind -## HAProxy or Nginx. -## -## See: listener.ws.$name.proxy_protocol -## -## Value: on | off -## listener.ws.external.proxy_protocol = on - -## Sets the timeout for proxy protocol. -## -## See: listener.ws.$name.proxy_protocol_timeout -## -## Value: Duration -## listener.ws.external.proxy_protocol_timeout = 3s - -## The TCP backlog of external MQTT/WebSocket Listener. -## -## See: listener.ws.$name.backlog -## -## Value: Number >= 0 -listener.ws.external.backlog = 1024 - -## The TCP send timeout for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.send_timeout -## -## Value: Duration -listener.ws.external.send_timeout = 15s - -## Close the MQTT/WebSocket connection if send timeout. -## -## See: listener.ws.$name.send_timeout_close -## -## Value: on | off -listener.ws.external.send_timeout_close = on - -## The TCP receive buffer(os kernel) for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.recbuf -## -## Value: Bytes -## listener.ws.external.recbuf = 2KB - -## The TCP send buffer(os kernel) for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.sndbuf -## -## Value: Bytes -## listener.ws.external.sndbuf = 2KB - -## The size of the user-level software buffer used by the driver. -## -## See: listener.ws.$name.buffer -## -## Value: Bytes -## listener.ws.external.buffer = 2KB - -## Sets the 'buffer = max(sndbuf, recbuf)' if this option is enabled. -## -## See: listener.ws.$name.tune_buffer -## -## Value: on | off -## listener.ws.external.tune_buffer = off - -## The TCP_NODELAY flag for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.nodelay -## -## Value: true | false -listener.ws.external.nodelay = true - -## The compress flag for external MQTT/WebSocket connections. -## -## If this Value is set true,the websocket message would be compressed -## -## Value: true | false -## listener.ws.external.compress = true - -## The level of deflate options for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.level -## -## Value: none | default | best_compression | best_speed -## listener.ws.external.deflate_opts.level = default - -## The mem_level of deflate options for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.mem_level -## -## Valid range is 1-9 -## listener.ws.external.deflate_opts.mem_level = 8 - -## The strategy of deflate options for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.strategy -## -## Value: default | filtered | huffman_only | rle -## listener.ws.external.deflate_opts.strategy = default - -## The deflate option for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.server_context_takeover -## -## Value: takeover | no_takeover -## listener.ws.external.deflate_opts.server_context_takeover = takeover - -## The deflate option for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.client_context_takeover -## -## Value: takeover | no_takeover -## listener.ws.external.deflate_opts.client_context_takeover = takeover - -## The deflate options for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.server_max_window_bits -## -## Valid range is 8-15 -## listener.ws.external.deflate_opts.server_max_window_bits = 15 - -## The deflate options for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.deflate_opts.client_max_window_bits -## -## Valid range is 8-15 -## listener.ws.external.deflate_opts.client_max_window_bits = 15 - -## The idle timeout for external MQTT/WebSocket connections. -## -## See: listener.ws.$name.idle_timeout -## -## Value: Duration -## listener.ws.external.idle_timeout = 60s - -## The max frame size for external MQTT/WebSocket connections. -## -## -## Value: Number -## listener.ws.external.max_frame_size = 0 - -## Whether a WebSocket message is allowed to contain multiple MQTT packets -## -## Value: single | multiple -listener.ws.external.mqtt_piggyback = multiple - -##-------------------------------------------------------------------- -## External WebSocket/SSL listener for MQTT Protocol - -## listener.wss.$name is the IP address and port that the MQTT/WebSocket/SSL -## listener will bind. -## -## Value: IP:Port | Port -## -## Examples: 8084, 127.0.0.1:8084, ::1:8084 -listener.wss.external = 8084 - -## The path of WebSocket MQTT endpoint -## -## Value: URL Path -listener.wss.external.mqtt_path = /mqtt - -## The acceptor pool for external MQTT/WebSocket/SSL listener. -## -## Value: Number -listener.wss.external.acceptors = 4 - -## Maximum number of concurrent MQTT/Webwocket/SSL connections. -## -## Value: Number -listener.wss.external.max_connections = 16 - -## Maximum MQTT/WebSocket/SSL connections per second. -## -## See: listener.tcp.$name.max_conn_rate -## -## Value: Number -listener.wss.external.max_conn_rate = 1000 - -## Simulate the {active, N} option for the MQTT/WebSocket/SSL connections. -## -## Value: Number -listener.wss.external.active_n = 100 - -## Zone of the external MQTT/WebSocket/SSL listener belonged to. -## -## Value: String -listener.wss.external.zone = external - -## The access control rules for the MQTT/WebSocket/SSL listener. -## -## See: listener.tcp.$name.access. -## -## Value: ACL Rule -listener.wss.external.access.1 = allow all - -## See: listener.ws.external.verify_protocol_header -## -## Value: on | off -listener.wss.external.verify_protocol_header = on - -## Enable the Proxy Protocol V1/2 support. -## -## See: listener.tcp.$name.proxy_protocol -## -## Value: on | off -## listener.wss.external.proxy_protocol = on - -## Sets the timeout for proxy protocol. -## -## See: listener.tcp.$name.proxy_protocol_timeout -## -## Value: Duration -## listener.wss.external.proxy_protocol_timeout = 3s - -## TLS versions only to protect from POODLE attack. -## -## See: listener.ssl.$name.tls_versions -## -## Value: String, seperated by ',' -## listener.wss.external.tls_versions = tlsv1.2,tlsv1.1,tlsv1 - -## Path to the file containing the user's private PEM-encoded key. -## -## See: listener.ssl.$name.keyfile -## -## Value: File -listener.wss.external.keyfile = {{ platform_etc_dir }}/certs/key.pem - -## Path to a file containing the user certificate. -## -## See: listener.ssl.$name.certfile -## -## Value: File -listener.wss.external.certfile = {{ platform_etc_dir }}/certs/cert.pem - -## Path to the file containing PEM-encoded CA certificates. -## -## See: listener.ssl.$name.cacert -## -## Value: File -## listener.wss.external.cacertfile = {{ platform_etc_dir }}/certs/cacert.pem - -## See: listener.ssl.$name.dhfile -## -## Value: File -## listener.ssl.external.dhfile = {{ platform_etc_dir }}/certs/dh-params.pem - -## See: listener.ssl.$name.vefify -## -## Value: vefify_peer | verify_none -## listener.wss.external.verify = verify_peer - -## See: listener.ssl.$name.fail_if_no_peer_cert -## -## Value: false | true -## listener.wss.external.fail_if_no_peer_cert = true - -## See: listener.ssl.$name.ciphers -## -## Value: Ciphers -listener.wss.external.ciphers = ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA - -## Ciphers for TLS PSK. -## Note that 'listener.wss.external.ciphers' and 'listener.wss.external.psk_ciphers' cannot -## be configured at the same time. -## See 'https://tools.ietf.org/html/rfc4279#section-2'. -## listener.wss.external.psk_ciphers = PSK-AES128-CBC-SHA,PSK-AES256-CBC-SHA,PSK-3DES-EDE-CBC-SHA,PSK-RC4-SHA - -## See: listener.ssl.$name.secure_renegotiate -## -## Value: on | off -## listener.wss.external.secure_renegotiate = off - -## See: listener.ssl.$name.reuse_sessions -## -## Value: on | off -## listener.wss.external.reuse_sessions = on - -## See: listener.ssl.$name.honor_cipher_order -## -## Value: on | off -## listener.wss.external.honor_cipher_order = on - -## See: listener.ssl.$name.peer_cert_as_username -## -## Value: cn | dn | crt -## listener.wss.external.peer_cert_as_username = cn - -## TCP backlog for the WebSocket/SSL connection. -## -## See: listener.tcp.$name.backlog -## -## Value: Number >= 0 -listener.wss.external.backlog = 1024 - -## The TCP send timeout for the WebSocket/SSL connection. -## -## See: listener.tcp.$name.send_timeout -## -## Value: Duration -listener.wss.external.send_timeout = 15s - -## Close the WebSocket/SSL connection if send timeout. -## -## See: listener.tcp.$name.send_timeout_close -## -## Value: on | off -listener.wss.external.send_timeout_close = on - -## The TCP receive buffer(os kernel) for the WebSocket/SSL connections. -## -## See: listener.tcp.$name.recbuf -## -## Value: Bytes -## listener.wss.external.recbuf = 4KB - -## The TCP send buffer(os kernel) for the WebSocket/SSL connections. -## -## See: listener.tcp.$name.sndbuf -## -## Value: Bytes -## listener.wss.external.sndbuf = 4KB - -## The size of the user-level software buffer used by the driver. -## -## See: listener.tcp.$name.buffer -## -## Value: Bytes -## listener.wss.external.buffer = 4KB - -## The TCP_NODELAY flag for WebSocket/SSL connections. -## -## See: listener.tcp.$name.nodelay -## -## Value: true | false -## listener.wss.external.nodelay = true - -## The compress flag for external WebSocket/SSL connections. -## -## If this Value is set true,the websocket message would be compressed -## -## Value: true | false -## listener.wss.external.compress = true - -## The level of deflate options for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.level -## -## Value: none | default | best_compression | best_speed -## listener.wss.external.deflate_opts.level = default - -## The mem_level of deflate options for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.mem_level -## -## Valid range is 1-9 -## listener.wss.external.deflate_opts.mem_level = 8 - -## The strategy of deflate options for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.strategy -## -## Value: default | filtered | huffman_only | rle -## listener.wss.external.deflate_opts.strategy = default - -## The deflate option for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.server_context_takeover -## -## Value: takeover | no_takeover -## listener.wss.external.deflate_opts.server_context_takeover = takeover - -## The deflate option for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.client_context_takeover -## -## Value: takeover | no_takeover -## listener.wss.external.deflate_opts.client_context_takeover = takeover - -## The deflate options for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.server_max_window_bits -## -## Valid range is 8-15 -## listener.wss.external.deflate_opts.server_max_window_bits = 15 - -## The deflate options for external WebSocket/SSL connections. -## -## See: listener.wss.$name.deflate_opts.client_max_window_bits -## -## Valid range is 8-15 -## listener.wss.external.deflate_opts.client_max_window_bits = 15 - -## The idle timeout for external WebSocket/SSL connections. -## -## See: listener.wss.$name.idle_timeout -## -## Value: Duration -## listener.wss.external.idle_timeout = 60s - -## The max frame size for external WebSocket/SSL connections. -## -## Value: Number -## listener.wss.external.max_frame_size = 0 - -## Whether a WebSocket message is allowed to contain multiple MQTT packets -## -## Value: single | multiple -listener.wss.external.mqtt_piggyback = multiple diff --git a/etc/logger.conf b/etc/logger.conf deleted file mode 100644 index 4fd0faf5f..000000000 --- a/etc/logger.conf +++ /dev/null @@ -1,170 +0,0 @@ -##-------------------------------------------------------------------- -## Log -##-------------------------------------------------------------------- - -## Where to emit the logs. -## Enable the console (standard output) logs. -## -## Value: off | file | console | both -## - off: disable logs entirely -## - file: write logs only to file -## - console: write logs only to standard I/O -## - both: write logs both to file and standard I/O -log.to = both - -## The log severity level. -## -## Value: debug | info | notice | warning | error | critical | alert | emergency -## -## Note: Only the messages with severity level higher than or equal to -## this level will be logged. -## -## Default: warning -log.level = warning - -## The dir for log files. -## -## Value: Folder -log.dir = {{ platform_log_dir }} - -## The log filename for logs of level specified in "log.level". -## -## If `log.rotation` is enabled, this is the base name of the -## files. Each file in a rotated log is named .N, where N is an integer. -## -## Value: String -## Default: emqx.log -log.file = emqx.log - -## Limits the total number of characters printed for each log event. -## -## Value: Integer -## Default: No Limit -#log.chars_limit = 8192 - -## Enables the log rotation. -## With this enabled, new log files will be created when the current -## log file is full, max to `log.rotation.size` files will be created. -## -## Value: on | off -## Default: on -log.rotation = on - -## Maximum size of each log file. -## -## Value: Number -## Default: 10M -## Supported Unit: KB | MB | GB -log.rotation.size = 10MB - -## Maximum rotation count of log files. -## -## Value: Number -## Default: 5 -log.rotation.count = 5 - -## To create additional log files for specific log levels. -## -## Value: File Name -## Format: log.$level.file = $filename, -## where "$level" can be one of: debug, info, notice, warning, -## error, critical, alert, emergency -## Note: Log files for a specific log level will only contain all the logs -## that higher than or equal to that level -## -#log.info.file = info.log -#log.error.file = error.log - -## The max allowed queue length before switching to sync mode. -## -## Log overload protection parameter. If the message queue grows -## larger than this value the handler switches from anync to sync mode. -## -## Default: 100 -## -#log.sync_mode_qlen = 100 - -## The max allowed queue length before switching to drop mode. -## -## Log overload protection parameter. When the message queue grows -## larger than this threshold, the handler switches to a mode in which -## it drops all new events that senders want to log. -## -## Default: 3000 -## -#log.drop_mode_qlen = 3000 - -## The max allowed queue length before switching to flush mode. -## -## Log overload protection parameter. If the length of the message queue -## grows larger than this threshold, a flush (delete) operation takes place. -## To flush events, the handler discards the messages in the message queue -## by receiving them in a loop without logging. -## -## Default: 8000 -## -#log.flush_qlen = 8000 - -## Kill the log handler when it gets overloaded. -## -## Log overload protection parameter. It is possible that a handler, -## even if it can successfully manage peaks of high load without crashing, -## can build up a large message queue, or use a large amount of memory. -## We could kill the log handler in these cases and restart it after a -## few seconds. -## -## Default: on -## -#log.overload_kill = on - -## The max allowed queue length before killing the log hanlder. -## -## Log overload protection parameter. This is the maximum allowed queue -## length. If the message queue grows larger than this, the handler -## process is terminated. -## -## Default: 20000 -## -#log.overload_kill_qlen = 20000 - -## The max allowed memory size before killing the log hanlder. -## -## Log overload protection parameter. This is the maximum memory size -## that the handler process is allowed to use. If the handler grows -## larger than this, the process is terminated. -## -## Default: 30MB -## -#log.overload_kill_mem_size = 30MB - -## Restart the log hanlder after some seconds. -## -## Log overload protection parameter. If the handler is terminated, -## it restarts automatically after a delay specified in seconds. -## The value "infinity" prevents restarts. -## -## Default: 5s -## -#log.overload_kill_restart_after = 5s - -## Max burst count and time window for burst control. -## -## Log overload protection parameter. Large bursts of log events - many -## events received by the handler under a short period of time - can -## potentially cause problems. By specifying the maximum number of events -## to be handled within a certain time frame, the handler can avoid -## choking the log with massive amounts of printouts. -## -## This config controls the maximum number of events to handle within -## a time frame. After the limit is reached, successive events are -## dropped until the end of the time frame. -## -## Note that there would be no warning if any messages were -## dropped because of burst control. -## -## Comment this config out to disable the burst control feature. -## -## Value: MaxBurstCount,TimeWindow -## Default: disabled -## -#log.burst_limit = 20000, 1s \ No newline at end of file diff --git a/etc/rpc.conf b/etc/rpc.conf deleted file mode 100644 index d86838e4f..000000000 --- a/etc/rpc.conf +++ /dev/null @@ -1,98 +0,0 @@ -##-------------------------------------------------------------------- -## RPC -##-------------------------------------------------------------------- -## RPC Mode. -## -## Value: sync | async -rpc.mode = async - -## Max batch size of async RPC requests. -## -## Value: Integer -## Zero or negative value disables rpc batching. -## -## NOTE: RPC batch won't work when rpc.mode = sync -rpc.async_batch_size = 256 - -## RPC port discovery -## -## The strategy for discovering the RPC listening port of other nodes. -## -## Value: Enum -## - manual: discover ports by `tcp_server_port` and `tcp_client_port`. -## - stateless: discover ports in a stateless manner. -## If node name is `emqx@127.0.0.1`, where the `` is an integer, -## then the listening port will be `5370 + ` -## -## Defaults to `stateless`. -rpc.port_discovery = stateless - -## TCP server port for RPC. -## -## Only takes effect when `rpc.port_discovery` = `manual`. -## -## Value: Port [1024-65535] -#rpc.tcp_server_port = 5369 - -## TCP port for outgoing RPC connections. -## -## Only takes effect when `rpc.port_discovery` = `manual`. -## -## Value: Port [1024-65535] -#rpc.tcp_client_port = 5369 - -## Number of outgoing RPC connections. -## -## Value: Interger [1-256] -## Defaults to NumberOfCPUSchedulers / 2 -#rpc.tcp_client_num = 1 - -## RCP Client connect timeout. -## -## Value: Seconds -rpc.connect_timeout = 5s - -## TCP send timeout of RPC client and server. -## -## Value: Seconds -rpc.send_timeout = 5s - -## Authentication timeout -## -## Value: Seconds -rpc.authentication_timeout = 5s - -## Default receive timeout for call() functions -## -## Value: Seconds -rpc.call_receive_timeout = 15s - -## Socket idle keepalive. -## -## Value: Seconds -rpc.socket_keepalive_idle = 900s - -## TCP Keepalive probes interval. -## -## Value: Seconds -rpc.socket_keepalive_interval = 75s - -## Probes lost to close the connection -## -## Value: Integer -rpc.socket_keepalive_count = 9 - -## Size of TCP send buffer. -## -## Value: Bytes -rpc.socket_sndbuf = 1MB - -## Size of TCP receive buffer. -## -## Value: Seconds -rpc.socket_recbuf = 1MB - -## Size of user-level software socket buffer. -## -## Value: Seconds -rpc.socket_buffer = 1MB diff --git a/etc/sys_mon.conf b/etc/sys_mon.conf deleted file mode 100644 index abd8baa04..000000000 --- a/etc/sys_mon.conf +++ /dev/null @@ -1,148 +0,0 @@ -##-------------------------------------------------------------------- -## System Monitor -##-------------------------------------------------------------------- - -## Enable Long GC monitoring. Disable if the value is 0. -## Notice: don't enable the monitor in production for: -## https://github.com/erlang/otp/blob/feb45017da36be78d4c5784d758ede619fa7bfd3/erts/emulator/beam/erl_gc.c#L421 -## -## Value: Duration -## - h: hour -## - m: minute -## - s: second -## - ms: milliseconds -## -## Examples: -## - 2h: 2 hours -## - 30m: 30 minutes -## - 0.1s: 0.1 seconds -## - 100ms : 100 milliseconds -## -## Default: 0ms -sysmon.long_gc = 0 - -## Enable Long Schedule(ms) monitoring. -## -## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 -## -## Value: Duration -## - h: hour -## - m: minute -## - s: second -## - ms: milliseconds -## -## Examples: -## - 2h: 2 hours -## - 30m: 30 minutes -## - 0.1s: 0.1 seconds -## - 100ms: 100 milliseconds -## -## Default: 0ms -sysmon.long_schedule = 240ms - -## Enable Large Heap monitoring. -## -## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 -## -## Value: bytes -## -## Default: 8M words. 32MB on 32-bit VM, 64MB on 64-bit VM. -sysmon.large_heap = 8MB - -## Enable Busy Port monitoring. -## -## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 -## -## Value: true | false -sysmon.busy_port = false - -## Enable Busy Dist Port monitoring. -## -## See: http://erlang.org/doc/man/erlang.html#system_monitor-2 -## -## Value: true | false -sysmon.busy_dist_port = true - -## The time interval for the periodic cpu check -## -## Value: Duration -## -h: hour, e.g. '2h' for 2 hours -## -m: minute, e.g. '5m' for 5 minutes -## -s: second, e.g. '30s' for 30 seconds -## -## Default: 60s -os_mon.cpu_check_interval = 60s - -## The threshold, as percentage of system cpu, for how much system cpu can be used before the corresponding alarm is set. -## -## Default: 80% -os_mon.cpu_high_watermark = 80% - -## The threshold, as percentage of system cpu, for how much system cpu can be used before the corresponding alarm is clear. -## -## Default: 60% -os_mon.cpu_low_watermark = 60% - -## The time interval for the periodic memory check -## -## Value: Duration -## -h: hour, e.g. '2h' for 2 hours -## -m: minute, e.g. '5m' for 5 minutes -## -s: second, e.g. '30s' for 30 seconds -## -## Default: 60s -os_mon.mem_check_interval = 60s - -## The threshold, as percentage of system memory, for how much system memory can be allocated before the corresponding alarm is set. -## -## Default: 70% -os_mon.sysmem_high_watermark = 70% - -## The threshold, as percentage of system memory, for how much system memory can be allocated by one Erlang process before the corresponding alarm is set. -## -## Default: 5% -os_mon.procmem_high_watermark = 5% - -## The time interval for the periodic process limit check -## -## Value: Duration -## -## Default: 30s -vm_mon.check_interval = 30s - -## The threshold, as percentage of processes, for how many processes can simultaneously exist at the local node before the corresponding alarm is set. -## -## Default: 80% -vm_mon.process_high_watermark = 80% - -## The threshold, as percentage of processes, for how many processes can simultaneously exist at the local node before the corresponding alarm is clear. -## -## Default: 60% -vm_mon.process_low_watermark = 60% - -## Specifies the actions to take when an alarm is activated -## -## Value: String -## - log -## - publish -## -## Default: log,publish -alarm.actions = log,publish - -## The maximum number of deactivated alarms -## -## Value: Integer -## -## Default: 1000 -alarm.size_limit = 1000 - -## Validity Period of deactivated alarms -## -## Value: Duration -## - h: hour -## - m: minute -## - s: second -## - ms: milliseconds -## -## Default: 24h -alarm.validity_period = 24h \ No newline at end of file diff --git a/etc/zones.conf b/etc/zones.conf deleted file mode 100644 index ea1e1807c..000000000 --- a/etc/zones.conf +++ /dev/null @@ -1,327 +0,0 @@ -##-------------------------------------------------------------------- -## Zones -##-------------------------------------------------------------------- - -##-------------------------------------------------------------------- -## External Zone - -## Idle timeout of the external MQTT connections. -## -## Value: duration -zone.external.idle_timeout = 15s - -## Enable ACL check. -## -## Value: Flag -zone.external.enable_acl = on - -## Enable ban check. -## -## Value: Flag -zone.external.enable_ban = on - -## Enable per connection statistics. -## -## Value: on | off -zone.external.enable_stats = on - -## The action when acl check reject current operation -## -## Value: ignore | disconnect -## Default: ignore -zone.external.acl_deny_action = ignore - -## Force the MQTT connection process GC after this number of -## messages | bytes passed through. -## -## Numbers delimited by `|'. Zero or negative is to disable. -zone.external.force_gc_policy = 16000|16MB - -## Max message queue length and total heap size to force shutdown -## connection/session process. -## Message queue here is the Erlang process mailbox, but not the number -## of queued MQTT messages of QoS 1 and 2. -## -## Numbers delimited by `|'. Zero or negative is to disable. -zone.external.force_shutdown_policy = 10000|32MB - -## Maximum MQTT packet size allowed. -## -## Value: Bytes -## Default: 1MB -## zone.external.max_packet_size = 64KB - -## Maximum length of MQTT clientId allowed. -## -## Value: Number [23-65535] -## zone.external.max_clientid_len = 1024 - -## Maximum topic levels allowed. 0 means no limit. -## -## Value: Number -## zone.external.max_topic_levels = 7 - -## Maximum QoS allowed. -## -## Value: 0 | 1 | 2 -## zone.external.max_qos_allowed = 2 - -## Maximum Topic Alias, 0 means no limit. -## -## Value: 0-65535 -## zone.external.max_topic_alias = 65535 - -## Whether the Server supports retained messages. -## -## Value: boolean -## zone.external.retain_available = true - -## Whether the Server supports Wildcard Subscriptions -## -## Value: boolean -## zone.external.wildcard_subscription = false - -## Whether the Server supports Shared Subscriptions -## -## Value: boolean -## zone.external.shared_subscription = false - -## Server Keep Alive -## -## Value: Number -## zone.external.server_keepalive = 0 - -## The backoff for MQTT keepalive timeout. The broker will kick a connection out -## until 'Keepalive * backoff * 2' timeout. -## -## Value: Float > 0.5 -zone.external.keepalive_backoff = 0.75 - -## Maximum number of subscriptions allowed, 0 means no limit. -## -## Value: Number -zone.external.max_subscriptions = 0 - -## Force to upgrade QoS according to subscription. -## -## Value: on | off -zone.external.upgrade_qos = off - -## Maximum size of the Inflight Window storing QoS1/2 messages delivered but unacked. -## -## Value: Number -zone.external.max_inflight = 32 - -## Retry interval for QoS1/2 message delivering. -## -## Value: Duration -zone.external.retry_interval = 30s - -## Maximum QoS2 packets (Client -> Broker) awaiting PUBREL, 0 means no limit. -## -## Value: Number -zone.external.max_awaiting_rel = 100 - -## The QoS2 messages (Client -> Broker) will be dropped if awaiting PUBREL timeout. -## -## Value: Duration -zone.external.await_rel_timeout = 300s - -## Default session expiry interval for MQTT V3.1.1 connections. -## -## Value: Duration -## -d: day -## -h: hour -## -m: minute -## -s: second -## -## Default: 2h, 2 hours -zone.external.session_expiry_interval = 2h - -## Maximum queue length. Enqueued messages when persistent client disconnected, -## or inflight window is full. 0 means no limit. -## -## Value: Number >= 0 -zone.external.max_mqueue_len = 1000 - -## Topic priorities. -## 'none' to indicate no priority table (by default), hence all messages -## are treated equal -## -## Priority number [1-255] -## Example: topic/1=10,topic/2=8 -## NOTE: comma and equal signs are not allowed for priority topic names -## NOTE: messages for topics not in the priority table are treated as -## either highest or lowest priority depending on the configured -## value for mqueue_default_priority -## -zone.external.mqueue_priorities = none - -## Default to highest priority for topics not matching priority table -## -## Value: highest | lowest -zone.external.mqueue_default_priority = highest - -## Whether to enqueue QoS0 messages. -## -## Value: false | true -zone.external.mqueue_store_qos0 = true - -## Whether to turn on flapping detect -## -## Value: on | off -zone.external.enable_flapping_detect = off - -## Message limit for the a external MQTT connection. -## -## Value: Number,Duration -## Example: 100 messages per 10 seconds. -#zone.external.rate_limit.conn_messages_in = 100,10s - -## Bytes limit for a external MQTT connections. -## -## Value: Number,Duration -## Example: 100KB incoming per 10 seconds. -#zone.external.rate_limit.conn_bytes_in = 100KB,10s - -## Messages quota for the each of external MQTT connection. -## This value consumed by the number of recipient on a message. -## -## Value: Number, Duration -## -## Example: 100 messaegs per 1s -#zone.external.quota.conn_messages_routing = 100,1s - -## Messages quota for the all of external MQTT connections. -## This value consumed by the number of recipient on a message. -## -## Value: Number, Duration -## -## Example: 200000 messaegs per 1s -#zone.external.quota.overall_messages_routing = 200000,1s - -## All the topics will be prefixed with the mountpoint path if this option is enabled. -## -## Variables in mountpoint path: -## - %c: clientid -## - %u: username -## -## Value: String -## zone.external.mountpoint = devicebound/ - -## Whether use username replace client id -## -## Value: boolean -## Default: false -zone.external.use_username_as_clientid = false - -## Whether to ignore loop delivery of messages.(for mqtt v3.1.1) -## -## Value: true | false -zone.external.ignore_loop_deliver = false - -## Whether to parse the MQTT frame in strict mode -## -## Value: true | false -zone.external.strict_mode = false - -## Specify the response information returned to the client -## -## Value: String -## zone.external.response_information = example - -##-------------------------------------------------------------------- -## Internal Zone - -zone.internal.allow_anonymous = true - -## Enable per connection stats. -## -## Value: Flag -zone.internal.enable_stats = on - -## Enable ACL check. -## -## Value: Flag -zone.internal.enable_acl = off - -## The action when acl check reject current operation -## -## Value: ignore | disconnect -## Default: ignore -zone.internal.acl_deny_action = ignore - -## See zone.$name.force_gc_policy -## zone.internal.force_gc_policy = 128000|128MB - -## See zone.$name.wildcard_subscription. -## -## Value: boolean -## zone.internal.wildcard_subscription = true - -## See zone.$name.shared_subscription. -## -## Value: boolean -## zone.internal.shared_subscription = true - -## See zone.$name.max_subscriptions. -## -## Value: Integer -zone.internal.max_subscriptions = 0 - -## See zone.$name.max_inflight -## -## Value: Number -zone.internal.max_inflight = 128 - -## See zone.$name.max_awaiting_rel -## -## Value: Number -zone.internal.max_awaiting_rel = 1000 - -## See zone.$name.max_mqueue_len -## -## Value: Number >= 0 -zone.internal.max_mqueue_len = 10000 - -## Whether to enqueue Qos0 messages. -## -## Value: false | true -zone.internal.mqueue_store_qos0 = true - -## Whether to turn on flapping detect -## -## Value: on | off -zone.internal.enable_flapping_detect = off - -## See zone.$name.force_shutdown_policy -zone.internal.force_shutdown_policy = 128000|128MB - -## All the topics will be prefixed with the mountpoint path if this option is enabled. -## -## Variables in mountpoint path: -## - %c: clientid -## - %u: username -## -## Value: String -## zone.internal.mountpoint = cloudbound/ - -## Whether to ignore loop delivery of messages.(for mqtt v3.1.1) -## -## Value: true | false -zone.internal.ignore_loop_deliver = false - -## Whether to parse the MQTT frame in strict mode -## -## Value: true | false -zone.internal.strict_mode = false - -## Specify the response information returned to the client -## -## Value: String -## zone.internal.response_information = example - -## Allow the zone's clients to bypass authentication step -## -## Value: true | false -zone.internal.bypass_auth_plugins = true diff --git a/priv/emqx.schema b/priv/emqx.schema index 830a0e934..38fd9f9d2 100644 --- a/priv/emqx.schema +++ b/priv/emqx.schema @@ -689,6 +689,12 @@ end}. {datatype, {enum, [allow, deny]}} ]}. +%% @doc Default ACL file. +{mapping, "acl_file", "emqx.acl_file", [ + {datatype, string}, + hidden +]}. + %% @doc Enable ACL cache for publish. {mapping, "enable_acl_cache", "emqx.enable_acl_cache", [ {default, on}, @@ -1239,9 +1245,9 @@ end}. ]}. {mapping, "listener.tcp.$name.high_watermark", "emqx.listeners", [ - {datatype, bytesize}, - {default, "1MB"} -]}. + {datatype, bytesize}, + {default, "1MB"} + ]}. {mapping, "listener.tcp.$name.tune_buffer", "emqx.listeners", [ {datatype, flag}, @@ -1336,9 +1342,9 @@ end}. ]}. {mapping, "listener.ssl.$name.high_watermark", "emqx.listeners", [ - {datatype, bytesize}, - {default, "1MB"} -]}. + {datatype, bytesize}, + {default, "1MB"} + ]}. {mapping, "listener.ssl.$name.tune_buffer", "emqx.listeners", [ {datatype, flag}, From 153977609e6c73b5600a24e0f5c75a44164e96b7 Mon Sep 17 00:00:00 2001 From: Zaiming Shi Date: Sat, 13 Feb 2021 21:07:31 +0100 Subject: [PATCH 26/41] feat(listeners): Add identifier to listeners Listeners are internally identifiered by the listen-on tuple which is not UI friendly when we have to find a listener by this 'signature'. The listeners are actually named in configs, but the names are discarded in the parsing functions. This commit is to keep the name and provide an API to find listener by name (identifier). --- .../emqx_management/src/emqx_mgmt.erl | 1 + .../emqx_management/src/emqx_mgmt_cli.erl | 43 +++++++---- priv/emqx.schema | 24 ++++-- src/emqx_listeners.erl | 77 +++++++++++++++---- 4 files changed, 111 insertions(+), 34 deletions(-) diff --git a/lib-opensource/emqx_management/src/emqx_mgmt.erl b/lib-opensource/emqx_management/src/emqx_mgmt.erl index 4174f3224..63a2b22a3 100644 --- a/lib-opensource/emqx_management/src/emqx_mgmt.erl +++ b/lib-opensource/emqx_management/src/emqx_mgmt.erl @@ -535,6 +535,7 @@ list_listeners(Node) when Node =:= node() -> Tcp = lists:map(fun({{Protocol, ListenOn}, _Pid}) -> #{protocol => Protocol, listen_on => ListenOn, + identifier => emqx_listeners:find_id_by_listen_on(ListenOn), acceptors => esockd:get_acceptors({Protocol, ListenOn}), max_conns => esockd:get_max_connections({Protocol, ListenOn}), current_conns => esockd:get_current_connections({Protocol, ListenOn}), diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl index 8a9f57f67..6d2315acc 100644 --- a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl +++ b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl @@ -510,14 +510,14 @@ trace_off(Who, Name) -> listeners([]) -> foreach(fun({{Protocol, ListenOn}, _Pid}) -> - Info = [{acceptors, esockd:get_acceptors({Protocol, ListenOn})}, + Info = [{identifier, {string, emqx_listeners:find_id_by_listen_on(ListenOn)}}, + {acceptors, esockd:get_acceptors({Protocol, ListenOn})}, {max_conns, esockd:get_max_connections({Protocol, ListenOn})}, {current_conn, esockd:get_current_connections({Protocol, ListenOn})}, - {shutdown_count, esockd:get_shutdown_count({Protocol, ListenOn})}], + {shutdown_count, esockd:get_shutdown_count({Protocol, ListenOn})} + ], emqx_ctl:print("listener on ~s:~s~n", [Protocol, esockd:to_string(ListenOn)]), - foreach(fun({Key, Val}) -> - emqx_ctl:print(" ~-16s: ~w~n", [Key, Val]) - end, Info) + foreach(fun indent_print/1, Info) end, esockd:listeners()), foreach(fun({Protocol, Opts}) -> Info = [{acceptors, maps:get(num_acceptors, proplists:get_value(transport_options, Opts, #{}), 0)}, @@ -525,9 +525,7 @@ listeners([]) -> {current_conn, proplists:get_value(all_connections, Opts)}, {shutdown_count, []}], emqx_ctl:print("listener on ~s:~p~n", [Protocol, proplists:get_value(port, Opts)]), - foreach(fun({Key, Val}) -> - emqx_ctl:print(" ~-16s: ~w~n", [Key, Val]) - end, Info) + foreach(fun indent_print/1, Info) end, ranch:info()); listeners(["stop", Name = "http" ++ _N, ListenOn]) -> @@ -538,22 +536,32 @@ listeners(["stop", Name = "http" ++ _N, ListenOn]) -> emqx_ctl:print("Failed to stop ~s listener on ~s, error:~p~n", [Name, ListenOn, Error]) end; -listeners(["stop", Proto, ListenOn]) -> +listeners(["stop", "mqtt:" ++ _ = Identifier]) -> + stop_listener(emqx_listeners:find_by_id(Identifier), Identifier); + +listeners(["stop", _Proto, ListenOn]) -> + %% this clause is kept to be backward compatible ListenOn1 = case string:tokens(ListenOn, ":") of [Port] -> list_to_integer(Port); [IP, Port] -> {IP, list_to_integer(Port)} end, - case emqx_listeners:stop_listener({list_to_atom(Proto), ListenOn1, []}) of - ok -> - emqx_ctl:print("Stop ~s listener on ~s successfully.~n", [Proto, ListenOn]); - {error, Error} -> - emqx_ctl:print("Failed to stop ~s listener on ~s, error:~p~n", [Proto, ListenOn, Error]) - end; + stop_listener(emqx_listeners:find_by_listen_on(ListenOn1), ListenOn1); listeners(_) -> emqx_ctl:usage([{"listeners", "List listeners"}, {"listeners stop ", "Stop a listener"}]). +stop_listener(false, Input) -> + emqx_ctl:print("No such listener ~p~n", [Input]); +stop_listener(#{listen_on := ListenOn} = Listener, _Input) -> + ID = emqx_listeners:identifier(Listener), + case emqx_listeners:stop_listener(Listener) of + ok -> + emqx_ctl:print("Stop ~s listener on ~s successfully.~n", [ID, ListenOn]); + {error, Error} -> + emqx_ctl:print("Failed to stop ~s listener on ~s, error:~p~n", [ID, ListenOn, Error]) + end. + %%-------------------------------------------------------------------- %% @doc data Command @@ -707,3 +715,8 @@ format(_, Val) -> Val. bin(S) -> iolist_to_binary(S). + +indent_print({Key, {string, Val}}) -> + emqx_ctl:print(" ~-16s: ~s~n", [Key, Val]); +indent_print({Key, Val}) -> + emqx_ctl:print(" ~-16s: ~w~n", [Key, Val]). diff --git a/priv/emqx.schema b/priv/emqx.schema index bdf8a053f..26713ce2a 100644 --- a/priv/emqx.schema +++ b/priv/emqx.schema @@ -1996,8 +1996,15 @@ end}. Other -> Other end end, - [{Atom(Type), ListenOnN, [{deflate_options, DeflateOpts(Prefix)}, - {tcp_options, TcpOpts(Prefix)} | LisOpts(Prefix)]}] + [#{ proto => Atom(Type) + , name => Name + , listen_on => ListenOnN + , opts => [ {deflate_options, DeflateOpts(Prefix)} + , {tcp_options, TcpOpts(Prefix)} + | LisOpts(Prefix) + ] + } + ] end, SslListeners = fun(Type, Name) -> Prefix = string:join(["listener", Type, Name], "."), @@ -2005,9 +2012,16 @@ end}. undefined -> []; ListenOn -> - [{Atom(Type), ListenOn, [{deflate_options, DeflateOpts(Prefix)}, - {tcp_options, TcpOpts(Prefix)}, - {ssl_options, SslOpts(Prefix)} | LisOpts(Prefix)]}] + [#{ proto => Atom(Type) + , name => Name + , listen_on => ListenOn + , opts => [ {deflate_options, DeflateOpts(Prefix)} + , {tcp_options, TcpOpts(Prefix)} + , {ssl_options, SslOpts(Prefix)} + | LisOpts(Prefix) + ] + } + ] end end, diff --git a/src/emqx_listeners.erl b/src/emqx_listeners.erl index 3b642d55f..f7912a7fd 100644 --- a/src/emqx_listeners.erl +++ b/src/emqx_listeners.erl @@ -33,11 +33,43 @@ , restart_listener/3 ]). --type(listener() :: {esockd:proto(), esockd:listen_on(), [esockd:option()]}). +-export([ find_id_by_listen_on/1 + , find_by_listen_on/1 + , find_by_id/1 + , identifier/1 + ]). -%%-------------------------------------------------------------------- -%% APIs -%%-------------------------------------------------------------------- +-type(listener() :: #{ name := binary() + , proto := esockd:proto() + , listen_on := esockd:listen_on() + , opts := [esockd:option()] + }). + +%% @doc Find listener identifier by listen-on. +%% Return empty string (binary) if listener is not found in config. +-spec(find_id_by_listen_on(esockd:listen_on()) -> binary()). +find_id_by_listen_on(ListenOn) -> + case find_by_listen_on(ListenOn) of + false -> <<>>; + L -> identifier(L) + end. + +%% @doc Find listener by listen-on. +%% Return 'false' if not found. +-spec(find_by_listen_on(esockd:listen_on()) -> listener() | false). +find_by_listen_on(ListenOn) -> + find_by_listen_on(ListenOn, emqx:get_env(listeners, [])). + +%% @doc Find listener by identifier. +%% Return 'false' if not found. +-spec(find_by_id(string() | binary()) -> listener() | false). +find_by_id(Id) -> + find_by_id(iolist_to_binary(Id), emqx:get_env(listeners, [])). + +%% @doc Return the ID of the given listener. +-spec identifier(listener()) -> binary(). +identifier(#{proto := Proto, name := Name}) -> + identifier(Proto, Name). %% @doc Start all listeners. -spec(start() -> ok). @@ -45,13 +77,14 @@ start() -> lists:foreach(fun start_listener/1, emqx:get_env(listeners, [])). -spec(start_listener(listener()) -> ok). -start_listener({Proto, ListenOn, Options}) -> +start_listener(#{proto := Proto, name := Name, listen_on := ListenOn, opts := Options}) -> + ID = identifier(Proto, Name), case start_listener(Proto, ListenOn, Options) of - {ok, _} -> io:format("Start mqtt:~s listener on ~s successfully.~n", - [Proto, format(ListenOn)]); + {ok, _} -> io:format("Start ~s listener on ~s successfully.~n", + [ID, format(ListenOn)]); {error, Reason} -> - io:format(standard_error, "Failed to start mqtt:~s listener on ~s - ~0p~n!", - [Proto, format(ListenOn), Reason]), + io:format(standard_error, "Failed to start mqtt listener ~s on ~s - ~0p~n!", + [ID, format(ListenOn), Reason]), error(Reason) end. @@ -115,7 +148,7 @@ restart() -> lists:foreach(fun restart_listener/1, emqx:get_env(listeners, [])). -spec(restart_listener(listener()) -> any()). -restart_listener({Proto, ListenOn, Options}) -> +restart_listener(#{proto := Proto, listen_on := ListenOn, opts := Options}) -> restart_listener(Proto, ListenOn, Options). -spec(restart_listener(esockd:proto(), esockd:listen_on(), [esockd:option()]) -> any()). @@ -138,14 +171,14 @@ stop() -> lists:foreach(fun stop_listener/1, emqx:get_env(listeners, [])). -spec(stop_listener(listener()) -> ok | {error, term()}). -stop_listener({Proto, ListenOn, Opts}) -> +stop_listener(#{proto := Proto, name := Name, listen_on := ListenOn, opts := Opts}) -> + ID = identifier(Proto, Name), StopRet = stop_listener(Proto, ListenOn, Opts), case StopRet of - ok -> io:format("Stop mqtt:~s listener on ~s successfully.~n", - [Proto, format(ListenOn)]); + ok -> io:format("Stop ~s listener on ~s successfully.~n", [ID, format(ListenOn)]); {error, Reason} -> io:format(standard_error, "Failed to stop mqtt:~s listener on ~s - ~p~n.", - [Proto, format(ListenOn), Reason]) + [ID, format(ListenOn), Reason]) end, StopRet. @@ -181,3 +214,19 @@ ws_name(Name, {_Addr, Port}) -> ws_name(Name, Port); ws_name(Name, Port) -> list_to_atom(lists:concat([Name, ":", Port])). + +identifier(Proto, Name) when is_atom(Proto) -> + identifier(atom_to_list(Proto), Name); +identifier(Proto, Name) -> + iolist_to_binary(["mqtt", ":", Proto, ":", Name]). + +find_by_listen_on(ListenOn, []) -> error({unknown_listener, ListenOn}); +find_by_listen_on(ListenOn, [#{listen_on := ListenOn} = L | _]) -> L; +find_by_listen_on(ListenOn, [_ | Rest]) -> find_by_listen_on(ListenOn, Rest). + +find_by_id(_Id, []) -> false; +find_by_id(Id, [L | Rest]) -> + case identifier(L) =:= Id of + true -> L; + false -> find_by_id(Id, Rest) + end. From 2d79c870c1711430b9ff6d20bff46b3e4747bcee Mon Sep 17 00:00:00 2001 From: Zaiming Shi Date: Sun, 14 Feb 2021 20:16:42 +0100 Subject: [PATCH 27/41] fix(mgmt_cli): Do not doulbe print listener stop results --- .../emqx_management/src/emqx_mgmt_cli.erl | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl index 6d2315acc..ea5345772 100644 --- a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl +++ b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl @@ -549,18 +549,17 @@ listeners(["stop", _Proto, ListenOn]) -> listeners(_) -> emqx_ctl:usage([{"listeners", "List listeners"}, - {"listeners stop ", "Stop a listener"}]). + {"listeners stop ", "Stop a listener"}, + {"listeners stop ", "Stop a listener"} + ]). stop_listener(false, Input) -> emqx_ctl:print("No such listener ~p~n", [Input]); -stop_listener(#{listen_on := ListenOn} = Listener, _Input) -> - ID = emqx_listeners:identifier(Listener), - case emqx_listeners:stop_listener(Listener) of - ok -> - emqx_ctl:print("Stop ~s listener on ~s successfully.~n", [ID, ListenOn]); - {error, Error} -> - emqx_ctl:print("Failed to stop ~s listener on ~s, error:~p~n", [ID, ListenOn, Error]) - end. +stop_listener(#{} = Listener, _Input) -> + %% Discard reason here, reasons are io:format logged to group leader + %% in case of emqx_ctl RPC call, it's logged to the remore node. + _ = emqx_listeners:stop_listener(Listener), + ok. %%-------------------------------------------------------------------- %% @doc data Command From dfa9bbc0c282c0b894ec21ad36d940522f942f2d Mon Sep 17 00:00:00 2001 From: Zaiming Shi Date: Sun, 14 Feb 2021 20:40:01 +0100 Subject: [PATCH 28/41] refactor(listeners): use emqx_ctl to print cli messages It's better to keep cli print behaviour consistent. It also makes tests easier as they can meck emqx_ctl:print to validate the output. --- .../emqx_management/src/emqx_mgmt_cli.erl | 17 +++++++++++------ src/emqx_listeners.erl | 18 +++++++----------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl index ea5345772..2ec0dce49 100644 --- a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl +++ b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl @@ -554,12 +554,17 @@ listeners(_) -> ]). stop_listener(false, Input) -> - emqx_ctl:print("No such listener ~p~n", [Input]); -stop_listener(#{} = Listener, _Input) -> - %% Discard reason here, reasons are io:format logged to group leader - %% in case of emqx_ctl RPC call, it's logged to the remore node. - _ = emqx_listeners:stop_listener(Listener), - ok. + ok = emqx_ctl:print("No such listener ~p~n", [Input]); +stop_listener(#{listen_on := ListenOn} = Listener, _Input) -> + ID = emqx_listeners:identifier(Listener), + ListenOnStr = emqx_listeners:format_listen_on(ListenOn), + case emqx_listeners:stop_listener(Listener) of + ok -> + ok = emqx_ctl:print("Stop ~s listener on ~s successfully.~n", [ID, ListenOnStr]); + {error, Reason} -> + ok = emqx_ctl:print("Failed to stop ~s listener on ~s - ~p~n.", + [ID, ListenOnStr, Reason]) + end. %%-------------------------------------------------------------------- %% @doc data Command diff --git a/src/emqx_listeners.erl b/src/emqx_listeners.erl index f7912a7fd..5057922f5 100644 --- a/src/emqx_listeners.erl +++ b/src/emqx_listeners.erl @@ -28,7 +28,6 @@ -export([ start_listener/1 , start_listener/3 , stop_listener/1 - , stop_listener/3 , restart_listener/1 , restart_listener/3 ]). @@ -37,6 +36,7 @@ , find_by_listen_on/1 , find_by_id/1 , identifier/1 + , format_listen_on/1 ]). -type(listener() :: #{ name := binary() @@ -76,6 +76,10 @@ identifier(#{proto := Proto, name := Name}) -> start() -> lists:foreach(fun start_listener/1, emqx:get_env(listeners, [])). +%% @doc Format address:port for logging. +-spec(format_listen_on(esockd:listen_on()) -> binary()). +format_listen_on(ListenOn) -> format(ListenOn). + -spec(start_listener(listener()) -> ok). start_listener(#{proto := Proto, name := Name, listen_on := ListenOn, opts := Options}) -> ID = identifier(Proto, Name), @@ -171,16 +175,8 @@ stop() -> lists:foreach(fun stop_listener/1, emqx:get_env(listeners, [])). -spec(stop_listener(listener()) -> ok | {error, term()}). -stop_listener(#{proto := Proto, name := Name, listen_on := ListenOn, opts := Opts}) -> - ID = identifier(Proto, Name), - StopRet = stop_listener(Proto, ListenOn, Opts), - case StopRet of - ok -> io:format("Stop ~s listener on ~s successfully.~n", [ID, format(ListenOn)]); - {error, Reason} -> - io:format(standard_error, "Failed to stop mqtt:~s listener on ~s - ~p~n.", - [ID, format(ListenOn), Reason]) - end, - StopRet. +stop_listener(#{proto := Proto, listen_on := ListenOn, opts := Opts}) -> + stop_listener(Proto, ListenOn, Opts). -spec(stop_listener(esockd:proto(), esockd:listen_on(), [esockd:option()]) -> ok | {error, term()}). From c5a02c729ad9f03cb0170fb1b8f004d2ef422330 Mon Sep 17 00:00:00 2001 From: Zaiming Shi Date: Sun, 14 Feb 2021 21:30:50 +0100 Subject: [PATCH 29/41] feat(listeners): Add an api to ensure all listeners are started --- .../emqx_management/src/emqx_mgmt_cli.erl | 8 +++---- .../emqx_management/test/emqx_mgmt_SUITE.erl | 20 +++++++++++++---- src/emqx_listeners.erl | 22 +++++++++++++++++++ 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl index 2ec0dce49..6a0a1bd5a 100644 --- a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl +++ b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl @@ -554,16 +554,16 @@ listeners(_) -> ]). stop_listener(false, Input) -> - ok = emqx_ctl:print("No such listener ~p~n", [Input]); + emqx_ctl:print("No such listener ~p~n", [Input]); stop_listener(#{listen_on := ListenOn} = Listener, _Input) -> ID = emqx_listeners:identifier(Listener), ListenOnStr = emqx_listeners:format_listen_on(ListenOn), case emqx_listeners:stop_listener(Listener) of ok -> - ok = emqx_ctl:print("Stop ~s listener on ~s successfully.~n", [ID, ListenOnStr]); + emqx_ctl:print("Stop ~s listener on ~s successfully.~n", [ID, ListenOnStr]); {error, Reason} -> - ok = emqx_ctl:print("Failed to stop ~s listener on ~s - ~p~n.", - [ID, ListenOnStr, Reason]) + emqx_ctl:print("Failed to stop ~s listener on ~s - ~p~n.", + [ID, ListenOnStr, Reason]) end. %%-------------------------------------------------------------------- diff --git a/lib-opensource/emqx_management/test/emqx_mgmt_SUITE.erl b/lib-opensource/emqx_management/test/emqx_mgmt_SUITE.erl index e41b9ee6a..d8cb91dab 100644 --- a/lib-opensource/emqx_management/test/emqx_mgmt_SUITE.erl +++ b/lib-opensource/emqx_management/test/emqx_mgmt_SUITE.erl @@ -49,7 +49,8 @@ groups() -> t_broker_cmd, t_router_cmd, t_subscriptions_cmd, - t_listeners_cmd + t_listeners_cmd_old, + t_listeners_cmd_new ]}]. apps() -> @@ -275,12 +276,23 @@ t_subscriptions_cmd(_) -> ?assertEqual(emqx_mgmt_cli:subscriptions(["del", "client", "b/b/c"]), "ok~n"), unmock_print(). -t_listeners_cmd(_) -> +t_listeners_cmd_old(_) -> + ok = emqx_listeners:ensure_all_started(), mock_print(), ?assertEqual(emqx_mgmt_cli:listeners([]), ok), ?assertEqual( - emqx_mgmt_cli:listeners(["stop", "wss", "8084"]), - "Stop wss listener on 8084 successfully.\n" + "Stop mqtt:wss:external listener on 0.0.0.0:8084 successfully.\n", + emqx_mgmt_cli:listeners(["stop", "wss", "8084"]) + ), + unmock_print(). + +t_listeners_cmd_new(_) -> + ok = emqx_listeners:ensure_all_started(), + mock_print(), + ?assertEqual(emqx_mgmt_cli:listeners([]), ok), + ?assertEqual( + "Stop mqtt:wss:external listener on 0.0.0.0:8084 successfully.\n", + emqx_mgmt_cli:listeners(["stop", "mqtt:wss:external"]) ), unmock_print(). diff --git a/src/emqx_listeners.erl b/src/emqx_listeners.erl index 5057922f5..c1ccae165 100644 --- a/src/emqx_listeners.erl +++ b/src/emqx_listeners.erl @@ -21,6 +21,7 @@ %% APIs -export([ start/0 + , ensure_all_started/0 , restart/0 , stop/0 ]). @@ -76,6 +77,27 @@ identifier(#{proto := Proto, name := Name}) -> start() -> lists:foreach(fun start_listener/1, emqx:get_env(listeners, [])). +%% @doc Ensure all configured listeners are started. +%% Raise exception if any of them failed to start. +-spec(ensure_all_started() -> ok). +ensure_all_started() -> + ensure_all_started(emqx:get_env(listeners, []), []). + +ensure_all_started([], []) -> ok; +ensure_all_started([], Failed) -> error(Failed); +ensure_all_started([L | Rest], Results) -> + #{proto := Proto, listen_on := ListenOn, opts := Options} = L, + NewResults = + case start_listener(Proto, ListenOn, Options) of + {ok, _Pid} -> + Results; + {error, {already_started, _Pid}} -> + Results; + {error, Reason} -> + [{identifier(L), Reason} | Results] + end, + ensure_all_started(Rest, NewResults). + %% @doc Format address:port for logging. -spec(format_listen_on(esockd:listen_on()) -> binary()). format_listen_on(ListenOn) -> format(ListenOn). From 2fc758c49a6cab3e81096bb5039fb4b4cafdffc1 Mon Sep 17 00:00:00 2001 From: Zaiming Shi Date: Sun, 14 Feb 2021 23:10:20 +0100 Subject: [PATCH 30/41] fix(test): Pin emqx-ct-helper 1.3.6 --- rebar.config.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rebar.config.erl b/rebar.config.erl index 08b3e2be9..123c39af5 100644 --- a/rebar.config.erl +++ b/rebar.config.erl @@ -47,8 +47,8 @@ test_plugins() -> test_deps() -> [ {bbmustache, "1.10.0"} - , {emqx_ct_helpers, {git, "https://github.com/emqx/emqx-ct-helpers", {tag, "1.3.5"}}} - , meck + , {emqx_ct_helpers, {git, "https://github.com/emqx/emqx-ct-helpers", {tag, "1.3.6"}}} + , meck ]. default_compile_opts() -> From a93d62ace692ebf2ab293c5beb19b10c7eb5e9a7 Mon Sep 17 00:00:00 2001 From: Zaiming Shi Date: Mon, 15 Feb 2021 10:34:47 +0100 Subject: [PATCH 31/41] refactor(cli): Print listener ID as table head --- .../emqx_management/src/emqx_mgmt_cli.erl | 18 ++++++++++++++---- src/emqx_listeners.erl | 6 +++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl index 6a0a1bd5a..e3f98b4e4 100644 --- a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl +++ b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl @@ -510,21 +510,23 @@ trace_off(Who, Name) -> listeners([]) -> foreach(fun({{Protocol, ListenOn}, _Pid}) -> - Info = [{identifier, {string, emqx_listeners:find_id_by_listen_on(ListenOn)}}, + Info = [{listen_on, {string, emqx_listeners:format_listen_on(ListenOn)}}, {acceptors, esockd:get_acceptors({Protocol, ListenOn})}, {max_conns, esockd:get_max_connections({Protocol, ListenOn})}, {current_conn, esockd:get_current_connections({Protocol, ListenOn})}, {shutdown_count, esockd:get_shutdown_count({Protocol, ListenOn})} ], - emqx_ctl:print("listener on ~s:~s~n", [Protocol, esockd:to_string(ListenOn)]), + emqx_ctl:print("~s~n", [listener_identifier(Protocol, ListenOn)]), foreach(fun indent_print/1, Info) end, esockd:listeners()), foreach(fun({Protocol, Opts}) -> - Info = [{acceptors, maps:get(num_acceptors, proplists:get_value(transport_options, Opts, #{}), 0)}, + Port = proplists:get_value(port, Opts), + Info = [{listen_on, {string, emqx_listeners:format_listen_on(Port)}}, + {acceptors, maps:get(num_acceptors, proplists:get_value(transport_options, Opts, #{}), 0)}, {max_conns, proplists:get_value(max_connections, Opts)}, {current_conn, proplists:get_value(all_connections, Opts)}, {shutdown_count, []}], - emqx_ctl:print("listener on ~s:~p~n", [Protocol, proplists:get_value(port, Opts)]), + emqx_ctl:print("~s~n", [listener_identifier(Protocol, Port)]), foreach(fun indent_print/1, Info) end, ranch:info()); @@ -724,3 +726,11 @@ indent_print({Key, {string, Val}}) -> emqx_ctl:print(" ~-16s: ~s~n", [Key, Val]); indent_print({Key, Val}) -> emqx_ctl:print(" ~-16s: ~w~n", [Key, Val]). + +listener_identifier(Protocol, ListenOn) -> + case emqx_listeners:find_id_by_listen_on(ListenOn) of + false -> + "http" ++ _ = atom_to_list(Protocol); %% assert + ID -> + ID + end. diff --git a/src/emqx_listeners.erl b/src/emqx_listeners.erl index c1ccae165..fad205cb1 100644 --- a/src/emqx_listeners.erl +++ b/src/emqx_listeners.erl @@ -48,10 +48,10 @@ %% @doc Find listener identifier by listen-on. %% Return empty string (binary) if listener is not found in config. --spec(find_id_by_listen_on(esockd:listen_on()) -> binary()). +-spec(find_id_by_listen_on(esockd:listen_on()) -> binary() | false). find_id_by_listen_on(ListenOn) -> case find_by_listen_on(ListenOn) of - false -> <<>>; + false -> false; L -> identifier(L) end. @@ -238,7 +238,7 @@ identifier(Proto, Name) when is_atom(Proto) -> identifier(Proto, Name) -> iolist_to_binary(["mqtt", ":", Proto, ":", Name]). -find_by_listen_on(ListenOn, []) -> error({unknown_listener, ListenOn}); +find_by_listen_on(_ListenOn, []) -> false; find_by_listen_on(ListenOn, [#{listen_on := ListenOn} = L | _]) -> L; find_by_listen_on(ListenOn, [_ | Rest]) -> find_by_listen_on(ListenOn, Rest). From 65f3a2b685dc3287c67d74f9cf9149d1033eca67 Mon Sep 17 00:00:00 2001 From: Zaiming Shi Date: Mon, 15 Feb 2021 10:42:17 +0100 Subject: [PATCH 32/41] fix(cli): Stop http listener without port number --- lib-opensource/emqx_management/src/emqx_mgmt_cli.erl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl index e3f98b4e4..047830e5b 100644 --- a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl +++ b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl @@ -530,12 +530,13 @@ listeners([]) -> foreach(fun indent_print/1, Info) end, ranch:info()); -listeners(["stop", Name = "http" ++ _N, ListenOn]) -> +listeners(["stop", Name = "http" ++ _N | _MaybePort]) -> + %% _MaybePort is to be backward compatible, to stop http listener, there is no need for the port number case minirest:stop_http(list_to_atom(Name)) of ok -> - emqx_ctl:print("Stop ~s listener on ~s successfully.~n", [Name, ListenOn]); + emqx_ctl:print("Stop ~s listener successfully.~n", [Name]); {error, Error} -> - emqx_ctl:print("Failed to stop ~s listener on ~s, error:~p~n", [Name, ListenOn, Error]) + emqx_ctl:print("Failed to stop ~s listener, error:~p~n", [Name, Error]) end; listeners(["stop", "mqtt:" ++ _ = Identifier]) -> From 64cfaf4385d832362121fcaf5c23d2fab1c1688b Mon Sep 17 00:00:00 2001 From: Zaiming Shi Date: Thu, 18 Feb 2021 13:31:02 +0100 Subject: [PATCH 33/41] improve(print): io:format error message without indentation Avoid squeezing lines to the right. --- apps/emqx_coap/src/emqx_coap_server.erl | 4 ++-- apps/emqx_exproto/src/emqx_exproto.erl | 8 ++++---- apps/emqx_lwm2m/src/emqx_lwm2m_coap_server.erl | 4 ++-- apps/emqx_sn/src/emqx_sn_app.erl | 4 ++-- apps/emqx_stomp/src/emqx_stomp.erl | 4 ++-- bin/nodetool | 2 +- lib-opensource/emqx_management/src/emqx_mgmt_cli.erl | 10 +++++----- src/emqx_listeners.erl | 2 +- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/apps/emqx_coap/src/emqx_coap_server.erl b/apps/emqx_coap/src/emqx_coap_server.erl index 0d571fac3..4774bd310 100644 --- a/apps/emqx_coap/src/emqx_coap_server.erl +++ b/apps/emqx_coap/src/emqx_coap_server.erl @@ -55,7 +55,7 @@ start_listener({Proto, ListenOn, Opts}) -> io:format("Start coap:~s listener on ~s successfully.~n", [Proto, format(ListenOn)]); {error, Reason} -> - io:format(standard_error, "Failed to start coap:~s listener on ~s - ~0p~n!", + io:format(standard_error, "Failed to start coap:~s listener on ~s: ~0p~n", [Proto, format(ListenOn), Reason]), error(Reason) end. @@ -71,7 +71,7 @@ stop_listener({Proto, ListenOn, _Opts}) -> ok -> io:format("Stop coap:~s listener on ~s successfully.~n", [Proto, format(ListenOn)]); {error, Reason} -> - io:format(standard_error, "Failed to stop coap:~s listener on ~s - ~p~n.", + io:format(standard_error, "Failed to stop coap:~s listener on ~s: ~0p~n.", [Proto, format(ListenOn), Reason]) end, Ret. diff --git a/apps/emqx_exproto/src/emqx_exproto.erl b/apps/emqx_exproto/src/emqx_exproto.erl index 7d986ecdd..07f56ef1b 100644 --- a/apps/emqx_exproto/src/emqx_exproto.erl +++ b/apps/emqx_exproto/src/emqx_exproto.erl @@ -69,7 +69,7 @@ start_connection_handler_instance({_Proto, _LisType, _ListenOn, Opts}) -> {ok, _ClientChannelPid} -> {_Proto, _LisType, _ListenOn, [{handler, Name} | LisOpts]}; {error, Reason} -> - io:format(standard_error, "Failed to start ~s's connection handler - ~0p~n!", + io:format(standard_error, "Failed to start ~s's connection handler: ~0p~n", [Name, Reason]), error(Reason) end. @@ -85,7 +85,7 @@ start_server({Name, Port, SSLOptions}) -> io:format("Start ~s gRPC server on ~w successfully.~n", [Name, Port]); {error, Reason} -> - io:format(standard_error, "Failed to start ~s gRPC server on ~w - ~0p~n!", + io:format(standard_error, "Failed to start ~s gRPC server on ~w: ~0p~n", [Name, Port, Reason]), error({failed_start_server, Reason}) end. @@ -101,7 +101,7 @@ start_listener({Proto, LisType, ListenOn, Opts}) -> io:format("Start ~s listener on ~s successfully.~n", [Name, format(ListenOn)]); {error, Reason} -> - io:format(standard_error, "Failed to start ~s listener on ~s - ~0p~n!", + io:format(standard_error, "Failed to start ~s listener on ~s: ~0p~n", [Name, format(ListenOn), Reason]), error(Reason) end. @@ -132,7 +132,7 @@ stop_listener({Proto, LisType, ListenOn, Opts}) -> io:format("Stop ~s listener on ~s successfully.~n", [Name, format(ListenOn)]); {error, Reason} -> - io:format(standard_error, "Failed to stop ~s listener on ~s - ~p~n.", + io:format(standard_error, "Failed to stop ~s listener on ~s: ~0p~n", [Name, format(ListenOn), Reason]) end, StopRet. diff --git a/apps/emqx_lwm2m/src/emqx_lwm2m_coap_server.erl b/apps/emqx_lwm2m/src/emqx_lwm2m_coap_server.erl index d366e44e1..47ea6a2ba 100644 --- a/apps/emqx_lwm2m/src/emqx_lwm2m_coap_server.erl +++ b/apps/emqx_lwm2m/src/emqx_lwm2m_coap_server.erl @@ -47,7 +47,7 @@ start_listener({Proto, ListenOn, Opts}) -> io:format("Start lwm2m:~s listener on ~s successfully.~n", [Proto, format(ListenOn)]); {error, Reason} -> - io:format(standard_error, "Failed to start lwm2m:~s listener on ~s - ~0p~n!", + io:format(standard_error, "Failed to start lwm2m:~s listener on ~s: ~0p~n", [Proto, format(ListenOn), Reason]), error(Reason) end. @@ -63,7 +63,7 @@ stop_listener({Proto, ListenOn, _Opts}) -> ok -> io:format("Stop lwm2m:~s listener on ~s successfully.~n", [Proto, format(ListenOn)]); {error, Reason} -> - io:format(standard_error, "Failed to stop lwm2m:~s listener on ~s - ~p~n.", + io:format(standard_error, "Failed to stop lwm2m:~s listener on ~s: ~0p~n", [Proto, format(ListenOn), Reason]) end, Ret. diff --git a/apps/emqx_sn/src/emqx_sn_app.erl b/apps/emqx_sn/src/emqx_sn_app.erl index 1f59edc9d..8a2f15865 100644 --- a/apps/emqx_sn/src/emqx_sn_app.erl +++ b/apps/emqx_sn/src/emqx_sn_app.erl @@ -71,7 +71,7 @@ start_listener({Proto, ListenOn, Options}) -> {ok, _} -> io:format("Start mqttsn:~s listener on ~s successfully.~n", [Proto, format(ListenOn)]); {error, Reason} -> - io:format(standard_error, "Failed to start mqttsn:~s listener on ~s - ~0p~n!", + io:format(standard_error, "Failed to start mqttsn:~s listener on ~s: ~0p~n", [Proto, format(ListenOn), Reason]), error(Reason) end. @@ -101,7 +101,7 @@ stop_listener({Proto, ListenOn, Opts}) -> ok -> io:format("Stop mqttsn:~s listener on ~s successfully.~n", [Proto, format(ListenOn)]); {error, Reason} -> - io:format(standard_error, "Failed to stop mqttsn:~s listener on ~s - ~p~n.", + io:format(standard_error, "Failed to stop mqttsn:~s listener on ~s: ~0p~n", [Proto, format(ListenOn), Reason]) end, StopRet. diff --git a/apps/emqx_stomp/src/emqx_stomp.erl b/apps/emqx_stomp/src/emqx_stomp.erl index d7a6db9ee..3d6396d43 100644 --- a/apps/emqx_stomp/src/emqx_stomp.erl +++ b/apps/emqx_stomp/src/emqx_stomp.erl @@ -73,7 +73,7 @@ start_listener({Proto, ListenOn, Options}) -> {ok, _} -> io:format("Start stomp:~s listener on ~s successfully.~n", [Proto, format(ListenOn)]); {error, Reason} -> - io:format(standard_error, "Failed to start stomp:~s listener on ~s - ~0p~n!", + io:format(standard_error, "Failed to start stomp:~s listener on ~s: ~0p~n", [Proto, format(ListenOn), Reason]), error(Reason) end. @@ -102,7 +102,7 @@ stop_listener({Proto, ListenOn, Opts}) -> ok -> io:format("Stop stomp:~s listener on ~s successfully.~n", [Proto, format(ListenOn)]); {error, Reason} -> - io:format(standard_error, "Failed to stop stomp:~s listener on ~s - ~p~n.", + io:format(standard_error, "Failed to stop stomp:~s listener on ~s: ~0p~n", [Proto, format(ListenOn), Reason]) end, StopRet. diff --git a/bin/nodetool b/bin/nodetool index cf50509f9..1dfc93014 100755 --- a/bin/nodetool +++ b/bin/nodetool @@ -47,7 +47,7 @@ main(Args) -> {true, pong} -> ok; {false, pong} -> - io:format(standard_error, "Failed to connect to node ~p .\n", [TargetNode]), + io:format(standard_error, "Failed to connect to node ~p\n", [TargetNode]), halt(1); {_, pang} -> io:format(standard_error, "Node ~p not responding to pings.\n", [TargetNode]), diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl index 047830e5b..db05cafb8 100644 --- a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl +++ b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl @@ -157,7 +157,7 @@ cluster(["join", SNode]) -> ignore -> emqx_ctl:print("Ignore.~n"); {error, Error} -> - emqx_ctl:print("Failed to join the cluster: ~p~n", [Error]) + emqx_ctl:print("Failed to join the cluster: ~0p~n", [Error]) end; cluster(["leave"]) -> @@ -166,7 +166,7 @@ cluster(["leave"]) -> emqx_ctl:print("Leave the cluster successfully.~n"), cluster(["status"]); {error, Error} -> - emqx_ctl:print("Failed to leave the cluster: ~p~n", [Error]) + emqx_ctl:print("Failed to leave the cluster: ~0p~n", [Error]) end; cluster(["force-leave", SNode]) -> @@ -177,7 +177,7 @@ cluster(["force-leave", SNode]) -> ignore -> emqx_ctl:print("Ignore.~n"); {error, Error} -> - emqx_ctl:print("Failed to remove the node from cluster: ~p~n", [Error]) + emqx_ctl:print("Failed to remove the node from cluster: ~0p~n", [Error]) end; cluster(["status"]) -> @@ -536,7 +536,7 @@ listeners(["stop", Name = "http" ++ _N | _MaybePort]) -> ok -> emqx_ctl:print("Stop ~s listener successfully.~n", [Name]); {error, Error} -> - emqx_ctl:print("Failed to stop ~s listener, error:~p~n", [Name, Error]) + emqx_ctl:print("Failed to stop ~s listener: ~0p~n", [Name, Error]) end; listeners(["stop", "mqtt:" ++ _ = Identifier]) -> @@ -565,7 +565,7 @@ stop_listener(#{listen_on := ListenOn} = Listener, _Input) -> ok -> emqx_ctl:print("Stop ~s listener on ~s successfully.~n", [ID, ListenOnStr]); {error, Reason} -> - emqx_ctl:print("Failed to stop ~s listener on ~s - ~p~n.", + emqx_ctl:print("Failed to stop ~s listener on ~s: ~0p~n", [ID, ListenOnStr, Reason]) end. diff --git a/src/emqx_listeners.erl b/src/emqx_listeners.erl index fad205cb1..eadc93b97 100644 --- a/src/emqx_listeners.erl +++ b/src/emqx_listeners.erl @@ -109,7 +109,7 @@ start_listener(#{proto := Proto, name := Name, listen_on := ListenOn, opts := Op {ok, _} -> io:format("Start ~s listener on ~s successfully.~n", [ID, format(ListenOn)]); {error, Reason} -> - io:format(standard_error, "Failed to start mqtt listener ~s on ~s - ~0p~n!", + io:format(standard_error, "Failed to start mqtt listener ~s on ~s: ~0p~n", [ID, format(ListenOn), Reason]), error(Reason) end. From 706e272410b24e2b8ea5e7f5cd76ffb6a1e075f2 Mon Sep 17 00:00:00 2001 From: z8674558 Date: Fri, 19 Feb 2021 16:10:51 +0900 Subject: [PATCH 34/41] chore(emqx_auth_http): fix dialyzer warnings (match returned values) --- apps/emqx_auth_http/src/emqx_auth_http_app.erl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/emqx_auth_http/src/emqx_auth_http_app.erl b/apps/emqx_auth_http/src/emqx_auth_http_app.erl index 9b6b265d4..2988dac78 100644 --- a/apps/emqx_auth_http/src/emqx_auth_http_app.erl +++ b/apps/emqx_auth_http/src/emqx_auth_http_app.erl @@ -106,7 +106,7 @@ load_hooks() -> ok = emqx_auth_http:register_metrics(), PoolOpts = proplists:get_value(pool_opts, AuthReq), PoolName = proplists:get_value(pool_name, AuthReq), - ehttpc_sup:start_pool(PoolName, PoolOpts), + {ok, _} = ehttpc_sup:start_pool(PoolName, PoolOpts), case application:get_env(?APP, super_req) of undefined -> emqx:hook('client.authenticate', {emqx_auth_http, check, [#{auth => maps:from_list(AuthReq), @@ -114,7 +114,7 @@ load_hooks() -> {ok, SuperReq} -> PoolOpts1 = proplists:get_value(pool_opts, SuperReq), PoolName1 = proplists:get_value(pool_name, SuperReq), - ehttpc_sup:start_pool(PoolName1, PoolOpts1), + {ok, _} = ehttpc_sup:start_pool(PoolName1, PoolOpts1), emqx:hook('client.authenticate', {emqx_auth_http, check, [#{auth => maps:from_list(AuthReq), super => maps:from_list(SuperReq)}]}) end @@ -125,7 +125,7 @@ load_hooks() -> ok = emqx_acl_http:register_metrics(), PoolOpts2 = proplists:get_value(pool_opts, ACLReq), PoolName2 = proplists:get_value(pool_name, ACLReq), - ehttpc_sup:start_pool(PoolName2, PoolOpts2), + {ok, _} = ehttpc_sup:start_pool(PoolName2, PoolOpts2), emqx:hook('client.check_acl', {emqx_acl_http, check_acl, [#{acl => maps:from_list(ACLReq)}]}) end, ok. @@ -133,9 +133,9 @@ load_hooks() -> unload_hooks() -> emqx:unhook('client.authenticate', {emqx_auth_http, check}), emqx:unhook('client.check_acl', {emqx_acl_http, check_acl}), - ehttpc_sup:stop_pool('emqx_auth_http/auth_req'), - ehttpc_sup:stop_pool('emqx_auth_http/super_req'), - ehttpc_sup:stop_pool('emqx_auth_http/acl_req'), + _ = ehttpc_sup:stop_pool('emqx_auth_http/auth_req'), + _ = ehttpc_sup:stop_pool('emqx_auth_http/super_req'), + _ = ehttpc_sup:stop_pool('emqx_auth_http/acl_req'), ok. parse_host(Host) -> From e341387837786188fa2919ebf6ae2106702818a3 Mon Sep 17 00:00:00 2001 From: z8674558 Date: Fri, 19 Feb 2021 16:13:44 +0900 Subject: [PATCH 35/41] chore(emqx_auth_mnesia): fix dialyzer warnings (do_update_user only receives Login and NewPassword)' --- apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl b/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl index e7c9d982b..aeed5b85c 100644 --- a/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl +++ b/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl @@ -59,12 +59,12 @@ insert_user(User = #emqx_user{login = Login}) -> %% @doc Update User -spec(update_user(tuple(), binary()) -> ok | {error, any()}). update_user(Login, NewPassword) -> - User = #emqx_user{login = Login, password = encrypted_data(NewPassword)}, - ret(mnesia:transaction(fun do_update_user/1, [User])). + ret(mnesia:transaction(fun do_update_user/2, [Login, encrypted_data(NewPassword)])). -do_update_user(User = #emqx_user{login = Login}) -> +do_update_user(Login, NewPassword) -> case mnesia:read(?TABLE, Login) of - [{?TABLE, Login, _, CreateAt}] -> mnesia:write(User#emqx_user{created_at = CreateAt}); + [#emqx_user{} = User] -> + mnesia:write(User#emqx_user{password = NewPassword}); [] -> mnesia:abort(noexisted) end. From 91d00b2586033f976982e46478061c3f17d7eab1 Mon Sep 17 00:00:00 2001 From: z8674558 Date: Fri, 19 Feb 2021 16:15:34 +0900 Subject: [PATCH 36/41] chore(emqx_auth_mnesia): fix dialyzer warnings (return error tuple to minirest) --- apps/emqx_auth_mnesia/src/emqx_acl_mnesia_api.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/emqx_auth_mnesia/src/emqx_acl_mnesia_api.erl b/apps/emqx_auth_mnesia/src/emqx_acl_mnesia_api.erl index 38087135f..efc2d2fbb 100644 --- a/apps/emqx_auth_mnesia/src/emqx_acl_mnesia_api.erl +++ b/apps/emqx_auth_mnesia/src/emqx_acl_mnesia_api.erl @@ -129,7 +129,7 @@ add(_Bindings, Params) -> case Re of #{result := ok} -> return({ok, Re}); #{result := <<"ok">>} -> return({ok, Re}); - _ -> return({error, Re}) + _ -> return({error, {add, Re}}) end end. From 5a960fdabcd7c0ed870b6dabe35588efde8e555e Mon Sep 17 00:00:00 2001 From: z8674558 Date: Fri, 19 Feb 2021 16:16:24 +0900 Subject: [PATCH 37/41] chore(emqx_auth_mnesia): fix dialyzer warnings (match returned values) --- apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl b/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl index aeed5b85c..adefa704b 100644 --- a/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl +++ b/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl @@ -119,7 +119,7 @@ hash(Password, SaltBin, HashType) -> emqx_passwd:hash(HashType, <>). salt() -> - rand:seed(exsplus, erlang:timestamp()), + {_AlgHandler, _AlgState} = rand:seed(exsplus, erlang:timestamp()), Salt = rand:uniform(16#ffffffff), <>. %%-------------------------------------------------------------------- From ca1d24a98d21ac54c48b6b92dc86005c21568113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Gro=C3=9Fe?= Date: Sat, 13 Feb 2021 14:26:12 +0100 Subject: [PATCH 38/41] feature(mgmt): restart a listener example: ``` emqx_ctl listener restart mqtt:ssl:external ``` or ``` PUT /api/v4/listeners/mqtt:ssl:external/restart ``` thank you @zmstone for providing the listener-identifier apis :) --- .../emqx_management/src/emqx_mgmt.erl | 8 +++++ .../src/emqx_mgmt_api_listeners.erl | 29 ++++++++++++++++++- .../emqx_management/src/emqx_mgmt_cli.erl | 11 ++++++- .../emqx_management/test/emqx_mgmt_SUITE.erl | 12 ++++++++ src/emqx_listeners.erl | 20 +++++++++---- 5 files changed, 73 insertions(+), 7 deletions(-) diff --git a/lib-opensource/emqx_management/src/emqx_mgmt.erl b/lib-opensource/emqx_management/src/emqx_mgmt.erl index 587e4152f..19474e5a1 100644 --- a/lib-opensource/emqx_management/src/emqx_mgmt.erl +++ b/lib-opensource/emqx_management/src/emqx_mgmt.erl @@ -102,6 +102,7 @@ %% Listeners -export([ list_listeners/0 , list_listeners/1 + , restart_listener/2 ]). %% Alarms @@ -560,6 +561,12 @@ list_listeners(Node) when Node =:= node() -> list_listeners(Node) -> rpc_call(Node, list_listeners, [Node]). +restart_listener(Node, Identifier) when Node =:= node() -> + emqx_listeners:restart_listener(Identifier); + +restart_listener(Node, Identifier) -> + rpc_call(Node, restart_listener, [Node, Identifier]). + %%-------------------------------------------------------------------- %% Get Alarms %%-------------------------------------------------------------------- @@ -978,3 +985,4 @@ action_to_prop_list({action_instance, ActionInstId, Name, FallbackActions, Args} {name, Name}, {fallbacks, actions_to_prop_list(FallbackActions)}, {args, Args}]. + diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_listeners.erl b/lib-opensource/emqx_management/src/emqx_mgmt_api_listeners.erl index 153d20d38..7acbe8107 100644 --- a/lib-opensource/emqx_management/src/emqx_mgmt_api_listeners.erl +++ b/lib-opensource/emqx_management/src/emqx_mgmt_api_listeners.erl @@ -30,7 +30,19 @@ func => list, descr => "A list of listeners on the node"}). --export([list/2]). +-rest_api(#{name => restart_listener, + method => 'PUT', + path => "/listeners/:bin:identifier/restart", + func => restart, + descr => "Restart a listener in the cluster"}). + +-rest_api(#{name => restart_node_listener, + method => 'PUT', + path => "/nodes/:atom:node/listeners/:bin:identifier/restart", + func => restart, + descr => "Restart a listener on a node"}). + +-export([list/2, restart/2]). %% List listeners on a node. list(#{node := Node}, _Params) -> @@ -41,6 +53,21 @@ list(_Binding, _Params) -> return({ok, [#{node => Node, listeners => format(Listeners)} || {Node, Listeners} <- emqx_mgmt:list_listeners()]}). +%% Restart listeners on a node. +restart(#{node := Node, identifier := Identifier}, _Params) -> + case emqx_mgmt:restart_listener(Node, Identifier) of + ok -> return({ok, "Listener restarted."}); + {error, Error} -> return({error, Error}) + end; + +%% Restart listeners in the cluster. +restart(#{identifier := Identifier}, _Params) -> + Results = [{Node, emqx_mgmt:restart_listener(Node, Identifier)} || {Node, _Info} <- emqx_mgmt:list_nodes()], + case lists:filter(fun({_, Result}) -> Result =/= ok end, Results) of + [] -> return(ok); + Errors -> return({error, Errors}) + end. + format(Listeners) when is_list(Listeners) -> [ Info#{listen_on => list_to_binary(esockd:to_string(ListenOn))} || Info = #{listen_on := ListenOn} <- Listeners ]; diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl index db05cafb8..8f3a09026 100644 --- a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl +++ b/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl @@ -550,10 +550,19 @@ listeners(["stop", _Proto, ListenOn]) -> end, stop_listener(emqx_listeners:find_by_listen_on(ListenOn1), ListenOn1); +listeners(["restart", Identifier]) -> + case emqx_listeners:restart_listener(Identifier) of + ok -> + emqx_ctl:print("Restarted ~s listener successfully.~n", [Identifier]); + {error, Error} -> + emqx_ctl:print("Failed to restart ~s listener: ~0p~n", [Identifier, Error]) + end; + listeners(_) -> emqx_ctl:usage([{"listeners", "List listeners"}, {"listeners stop ", "Stop a listener"}, - {"listeners stop ", "Stop a listener"} + {"listeners stop ", "Stop a listener"}, + {"listeners restart ", "Restart a listener"} ]). stop_listener(false, Input) -> diff --git a/lib-opensource/emqx_management/test/emqx_mgmt_SUITE.erl b/lib-opensource/emqx_management/test/emqx_mgmt_SUITE.erl index d8cb91dab..56db2d118 100644 --- a/lib-opensource/emqx_management/test/emqx_mgmt_SUITE.erl +++ b/lib-opensource/emqx_management/test/emqx_mgmt_SUITE.erl @@ -294,6 +294,18 @@ t_listeners_cmd_new(_) -> "Stop mqtt:wss:external listener on 0.0.0.0:8084 successfully.\n", emqx_mgmt_cli:listeners(["stop", "mqtt:wss:external"]) ), + ?assertEqual( + emqx_mgmt_cli:listeners(["restart", "mqtt:tcp:external"]), + "Restarted mqtt:tcp:external listener successfully.\n" + ), + ?assertEqual( + emqx_mgmt_cli:listeners(["restart", "mqtt:ssl:external"]), + "Restarted mqtt:ssl:external listener successfully.\n" + ), + ?assertEqual( + emqx_mgmt_cli:listeners(["restart", "bad:listener:identifier"]), + "Failed to restart bad:listener:identifier listener: {no_such_listener,\"bad:listener:identifier\"}\n" + ), unmock_print(). t_plugins_cmd(_) -> diff --git a/src/emqx_listeners.erl b/src/emqx_listeners.erl index eadc93b97..651be0e8e 100644 --- a/src/emqx_listeners.erl +++ b/src/emqx_listeners.erl @@ -173,24 +173,34 @@ with_port({Addr, Port}, Opts = #{socket_opts := SocketOption}) -> restart() -> lists:foreach(fun restart_listener/1, emqx:get_env(listeners, [])). --spec(restart_listener(listener()) -> any()). +-spec(restart_listener(listener() | string() | binary()) -> ok | {error, any()}). restart_listener(#{proto := Proto, listen_on := ListenOn, opts := Options}) -> - restart_listener(Proto, ListenOn, Options). + restart_listener(Proto, ListenOn, Options); +restart_listener(Identifier) -> + case emqx_listeners:find_by_id(Identifier) of + false -> {error, {no_such_listener, Identifier}}; + Listener -> restart_listener(Listener) + end. --spec(restart_listener(esockd:proto(), esockd:listen_on(), [esockd:option()]) -> any()). +-spec(restart_listener(esockd:proto(), esockd:listen_on(), [esockd:option()]) -> + ok | {error, any()}). restart_listener(tcp, ListenOn, _Options) -> esockd:reopen('mqtt:tcp', ListenOn); restart_listener(Proto, ListenOn, _Options) when Proto == ssl; Proto == tls -> esockd:reopen('mqtt:ssl', ListenOn); restart_listener(Proto, ListenOn, Options) when Proto == http; Proto == ws -> _ = cowboy:stop_listener(ws_name('mqtt:ws', ListenOn)), - start_listener(Proto, ListenOn, Options); + ok(start_listener(Proto, ListenOn, Options)); restart_listener(Proto, ListenOn, Options) when Proto == https; Proto == wss -> _ = cowboy:stop_listener(ws_name('mqtt:wss', ListenOn)), - start_listener(Proto, ListenOn, Options); + ok(start_listener(Proto, ListenOn, Options)); restart_listener(Proto, ListenOn, _Opts) -> esockd:reopen(Proto, ListenOn). +ok(ok) -> ok; +ok({ok, _}) -> ok; +ok(Error) -> Error. + %% @doc Stop all listeners. -spec(stop() -> ok). stop() -> From 71d02e80119ebde8db25f13a47c05a8132da98a6 Mon Sep 17 00:00:00 2001 From: Zaiming Shi Date: Fri, 19 Feb 2021 10:20:16 +0100 Subject: [PATCH 39/41] chore(emqx_connection): delete stale code --- src/emqx_connection.erl | 56 ----------------------------------------- 1 file changed, 56 deletions(-) diff --git a/src/emqx_connection.erl b/src/emqx_connection.erl index eb9a95dc4..11a3a9418 100644 --- a/src/emqx_connection.erl +++ b/src/emqx_connection.erl @@ -465,62 +465,6 @@ system_continue(Parent, _Debug, State) -> system_terminate(Reason, _Parent, _Debug, State) -> terminate(Reason, State). -system_code_change(State, _Mod, {down, Vsn}, _Extra) - when Vsn == "4.2.0"; - Vsn == "4.2.1" -> - Channel = State#state.channel, - NSerialize = emqx_frame:serialize_fun(State#state.serialize), - case {State#state.parse_state, element(10, Channel)} of - {{none, _}, undefined} -> - {ok, State#state{serialize = NSerialize}}; - {Ps, Quota} -> - %% BACKW: e4.2.0-e4.2.1 - %% We can't recover/reconstruct anonymous function state for - %% Parser or Quota consumer. So just close it. - ?LOG(error, "Unsupport downgrade connection ~0p, peername: ~0p." - " Due to it have an incomplete frame or unsafed quota counter," - " parser_state: ~0p, quota: ~0p." - " Force close it now!!!", [self(), State#state.peername, Ps, Quota]), - self() ! {close, unsupported_downgrade_connection_state}, - {ok, State#state{serialize = NSerialize}} - end; - -system_code_change(State, _Mod, Vsn, _Extra) - when Vsn == "4.2.0"; - Vsn == "4.2.1" -> - Channel = State#state.channel, - NChannel = - case element(10, Channel) of - undefined -> Channel; - Quoter -> - Zone = element(2, Quoter), - Cks = element(3, Quoter), - NCks = [case Name == overall_messages_routing of - true -> Ck#{consumer => Zone}; - _ -> Ck - end || Ck = #{name := Name} <- Cks], - setelement(10, Channel, setelement(3, Quoter, NCks)) - end, - - NParseState = - case State#state.parse_state of - Ps = {none, _} -> Ps; - Ps when is_function(Ps) -> - case erlang:fun_info(Ps, env) of - {_, [Hdr, Opts]} -> - {{len, #{hdr => Hdr, len => {1, 0}}}, Opts}; - {_, [Bin, Hdr, Len, Opts]} when is_binary(Bin) -> - {{body, #{hdr => Hdr, len => Len, rest => Bin}}, Opts}; - {_, [Hdr, Multip, Len, Opts]} -> - {{len, #{hdr => Hdr, len => {Multip, Len}}}, Opts} - end - end, - - {_, [Ver, MaxSize]} = erlang:fun_info(State#state.serialize, env), - NSerialize = #{version => Ver, max_size => MaxSize}, - - {ok, State#state{channel = NChannel, parse_state = NParseState, serialize = NSerialize}}; - system_code_change(State, _Mod, _OldVsn, _Extra) -> {ok, State}. From 4a877a3a6993b9c6d094d5e6bd1599f7095c2eff Mon Sep 17 00:00:00 2001 From: Zaiming Shi Date: Fri, 19 Feb 2021 11:22:06 +0100 Subject: [PATCH 40/41] chore(apps): relocate some apps emqx_telemetry is for opensource onlyh emqx_rule_engiune is common --- {lib-opensource => apps}/emqx_rule_engine/.gitignore | 0 {lib-opensource => apps}/emqx_rule_engine/README.md | 0 {lib-opensource => apps}/emqx_rule_engine/docs/api_examples.md | 0 {lib-opensource => apps}/emqx_rule_engine/docs/cli_examples.md | 0 {lib-opensource => apps}/emqx_rule_engine/docs/design.md | 0 .../emqx_rule_engine/etc/emqx_rule_engine.conf | 0 .../emqx_rule_engine/include/rule_actions.hrl | 0 {lib-opensource => apps}/emqx_rule_engine/include/rule_engine.hrl | 0 .../emqx_rule_engine/priv/emqx_rule_engine.schema | 0 {lib-opensource => apps}/emqx_rule_engine/rebar.config | 0 .../emqx_rule_engine/src/emqx_rule_actions.erl | 0 .../emqx_rule_engine/src/emqx_rule_actions_trans.erl | 0 .../emqx_rule_engine/src/emqx_rule_engine.app.src | 0 .../emqx_rule_engine/src/emqx_rule_engine.erl | 0 .../emqx_rule_engine/src/emqx_rule_engine_api.erl | 0 .../emqx_rule_engine/src/emqx_rule_engine_app.erl | 0 .../emqx_rule_engine/src/emqx_rule_engine_cli.erl | 0 .../emqx_rule_engine/src/emqx_rule_engine_sup.erl | 0 .../emqx_rule_engine/src/emqx_rule_events.erl | 0 {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_funcs.erl | 0 {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_id.erl | 0 .../emqx_rule_engine/src/emqx_rule_locker.erl | 0 {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_maps.erl | 0 .../emqx_rule_engine/src/emqx_rule_metrics.erl | 0 .../emqx_rule_engine/src/emqx_rule_registry.erl | 0 .../emqx_rule_engine/src/emqx_rule_runtime.erl | 0 .../emqx_rule_engine/src/emqx_rule_sqlparser.erl | 0 .../emqx_rule_engine/src/emqx_rule_sqltester.erl | 0 {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_utils.erl | 0 .../emqx_rule_engine/src/emqx_rule_validator.erl | 0 .../emqx_rule_engine/test/emqx_rule_engine_SUITE.erl | 0 .../emqx_rule_engine/test/emqx_rule_events_SUITE.erl | 0 .../emqx_rule_engine/test/emqx_rule_funcs_SUITE.erl | 0 .../emqx_rule_engine/test/emqx_rule_id_SUITE.erl | 0 .../emqx_rule_engine/test/emqx_rule_maps_SUITE.erl | 0 .../emqx_rule_engine/test/emqx_rule_metrics_SUITE.erl | 0 .../emqx_rule_engine/test/emqx_rule_registry_SUITE.erl | 0 .../emqx_rule_engine/test/emqx_rule_utils_SUITE.erl | 0 .../emqx_rule_engine/test/emqx_rule_validator_SUITE.erl | 0 {lib-opensource => apps}/emqx_rule_engine/test/prop_rule_maps.erl | 0 {apps => lib-opensource}/emqx_telemetry/.gitignore | 0 {apps => lib-opensource}/emqx_telemetry/README.md | 0 {apps => lib-opensource}/emqx_telemetry/etc/emqx_telemetry.conf | 0 .../emqx_telemetry/priv/emqx_telemetry.schema | 0 {apps => lib-opensource}/emqx_telemetry/rebar.config | 0 .../emqx_telemetry/src/emqx_telemetry.app.src | 0 {apps => lib-opensource}/emqx_telemetry/src/emqx_telemetry.erl | 0 .../emqx_telemetry/src/emqx_telemetry_api.erl | 0 .../emqx_telemetry/src/emqx_telemetry_app.erl | 0 .../emqx_telemetry/src/emqx_telemetry_sup.erl | 0 .../emqx_telemetry/test/emqx_telemetry_SUITE.erl | 0 51 files changed, 0 insertions(+), 0 deletions(-) rename {lib-opensource => apps}/emqx_rule_engine/.gitignore (100%) rename {lib-opensource => apps}/emqx_rule_engine/README.md (100%) rename {lib-opensource => apps}/emqx_rule_engine/docs/api_examples.md (100%) rename {lib-opensource => apps}/emqx_rule_engine/docs/cli_examples.md (100%) rename {lib-opensource => apps}/emqx_rule_engine/docs/design.md (100%) rename {lib-opensource => apps}/emqx_rule_engine/etc/emqx_rule_engine.conf (100%) rename {lib-opensource => apps}/emqx_rule_engine/include/rule_actions.hrl (100%) rename {lib-opensource => apps}/emqx_rule_engine/include/rule_engine.hrl (100%) rename {lib-opensource => apps}/emqx_rule_engine/priv/emqx_rule_engine.schema (100%) rename {lib-opensource => apps}/emqx_rule_engine/rebar.config (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_actions.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_actions_trans.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_engine.app.src (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_engine.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_engine_api.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_engine_app.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_engine_cli.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_engine_sup.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_events.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_funcs.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_id.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_locker.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_maps.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_metrics.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_registry.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_runtime.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_sqlparser.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_sqltester.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_utils.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/src/emqx_rule_validator.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/test/emqx_rule_events_SUITE.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/test/emqx_rule_funcs_SUITE.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/test/emqx_rule_id_SUITE.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/test/emqx_rule_maps_SUITE.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/test/emqx_rule_metrics_SUITE.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/test/emqx_rule_registry_SUITE.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/test/emqx_rule_utils_SUITE.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/test/emqx_rule_validator_SUITE.erl (100%) rename {lib-opensource => apps}/emqx_rule_engine/test/prop_rule_maps.erl (100%) rename {apps => lib-opensource}/emqx_telemetry/.gitignore (100%) rename {apps => lib-opensource}/emqx_telemetry/README.md (100%) rename {apps => lib-opensource}/emqx_telemetry/etc/emqx_telemetry.conf (100%) rename {apps => lib-opensource}/emqx_telemetry/priv/emqx_telemetry.schema (100%) rename {apps => lib-opensource}/emqx_telemetry/rebar.config (100%) rename {apps => lib-opensource}/emqx_telemetry/src/emqx_telemetry.app.src (100%) rename {apps => lib-opensource}/emqx_telemetry/src/emqx_telemetry.erl (100%) rename {apps => lib-opensource}/emqx_telemetry/src/emqx_telemetry_api.erl (100%) rename {apps => lib-opensource}/emqx_telemetry/src/emqx_telemetry_app.erl (100%) rename {apps => lib-opensource}/emqx_telemetry/src/emqx_telemetry_sup.erl (100%) rename {apps => lib-opensource}/emqx_telemetry/test/emqx_telemetry_SUITE.erl (100%) diff --git a/lib-opensource/emqx_rule_engine/.gitignore b/apps/emqx_rule_engine/.gitignore similarity index 100% rename from lib-opensource/emqx_rule_engine/.gitignore rename to apps/emqx_rule_engine/.gitignore diff --git a/lib-opensource/emqx_rule_engine/README.md b/apps/emqx_rule_engine/README.md similarity index 100% rename from lib-opensource/emqx_rule_engine/README.md rename to apps/emqx_rule_engine/README.md diff --git a/lib-opensource/emqx_rule_engine/docs/api_examples.md b/apps/emqx_rule_engine/docs/api_examples.md similarity index 100% rename from lib-opensource/emqx_rule_engine/docs/api_examples.md rename to apps/emqx_rule_engine/docs/api_examples.md diff --git a/lib-opensource/emqx_rule_engine/docs/cli_examples.md b/apps/emqx_rule_engine/docs/cli_examples.md similarity index 100% rename from lib-opensource/emqx_rule_engine/docs/cli_examples.md rename to apps/emqx_rule_engine/docs/cli_examples.md diff --git a/lib-opensource/emqx_rule_engine/docs/design.md b/apps/emqx_rule_engine/docs/design.md similarity index 100% rename from lib-opensource/emqx_rule_engine/docs/design.md rename to apps/emqx_rule_engine/docs/design.md diff --git a/lib-opensource/emqx_rule_engine/etc/emqx_rule_engine.conf b/apps/emqx_rule_engine/etc/emqx_rule_engine.conf similarity index 100% rename from lib-opensource/emqx_rule_engine/etc/emqx_rule_engine.conf rename to apps/emqx_rule_engine/etc/emqx_rule_engine.conf diff --git a/lib-opensource/emqx_rule_engine/include/rule_actions.hrl b/apps/emqx_rule_engine/include/rule_actions.hrl similarity index 100% rename from lib-opensource/emqx_rule_engine/include/rule_actions.hrl rename to apps/emqx_rule_engine/include/rule_actions.hrl diff --git a/lib-opensource/emqx_rule_engine/include/rule_engine.hrl b/apps/emqx_rule_engine/include/rule_engine.hrl similarity index 100% rename from lib-opensource/emqx_rule_engine/include/rule_engine.hrl rename to apps/emqx_rule_engine/include/rule_engine.hrl diff --git a/lib-opensource/emqx_rule_engine/priv/emqx_rule_engine.schema b/apps/emqx_rule_engine/priv/emqx_rule_engine.schema similarity index 100% rename from lib-opensource/emqx_rule_engine/priv/emqx_rule_engine.schema rename to apps/emqx_rule_engine/priv/emqx_rule_engine.schema diff --git a/lib-opensource/emqx_rule_engine/rebar.config b/apps/emqx_rule_engine/rebar.config similarity index 100% rename from lib-opensource/emqx_rule_engine/rebar.config rename to apps/emqx_rule_engine/rebar.config diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_actions.erl b/apps/emqx_rule_engine/src/emqx_rule_actions.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_actions.erl rename to apps/emqx_rule_engine/src/emqx_rule_actions.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_actions_trans.erl b/apps/emqx_rule_engine/src/emqx_rule_actions_trans.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_actions_trans.erl rename to apps/emqx_rule_engine/src/emqx_rule_actions_trans.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_engine.app.src b/apps/emqx_rule_engine/src/emqx_rule_engine.app.src similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_engine.app.src rename to apps/emqx_rule_engine/src/emqx_rule_engine.app.src diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_engine.erl b/apps/emqx_rule_engine/src/emqx_rule_engine.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_engine.erl rename to apps/emqx_rule_engine/src/emqx_rule_engine.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_engine_api.erl b/apps/emqx_rule_engine/src/emqx_rule_engine_api.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_engine_api.erl rename to apps/emqx_rule_engine/src/emqx_rule_engine_api.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_engine_app.erl b/apps/emqx_rule_engine/src/emqx_rule_engine_app.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_engine_app.erl rename to apps/emqx_rule_engine/src/emqx_rule_engine_app.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_engine_cli.erl b/apps/emqx_rule_engine/src/emqx_rule_engine_cli.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_engine_cli.erl rename to apps/emqx_rule_engine/src/emqx_rule_engine_cli.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_engine_sup.erl b/apps/emqx_rule_engine/src/emqx_rule_engine_sup.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_engine_sup.erl rename to apps/emqx_rule_engine/src/emqx_rule_engine_sup.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_events.erl b/apps/emqx_rule_engine/src/emqx_rule_events.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_events.erl rename to apps/emqx_rule_engine/src/emqx_rule_events.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_funcs.erl b/apps/emqx_rule_engine/src/emqx_rule_funcs.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_funcs.erl rename to apps/emqx_rule_engine/src/emqx_rule_funcs.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_id.erl b/apps/emqx_rule_engine/src/emqx_rule_id.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_id.erl rename to apps/emqx_rule_engine/src/emqx_rule_id.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_locker.erl b/apps/emqx_rule_engine/src/emqx_rule_locker.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_locker.erl rename to apps/emqx_rule_engine/src/emqx_rule_locker.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_maps.erl b/apps/emqx_rule_engine/src/emqx_rule_maps.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_maps.erl rename to apps/emqx_rule_engine/src/emqx_rule_maps.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_metrics.erl b/apps/emqx_rule_engine/src/emqx_rule_metrics.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_metrics.erl rename to apps/emqx_rule_engine/src/emqx_rule_metrics.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_registry.erl b/apps/emqx_rule_engine/src/emqx_rule_registry.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_registry.erl rename to apps/emqx_rule_engine/src/emqx_rule_registry.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_runtime.erl b/apps/emqx_rule_engine/src/emqx_rule_runtime.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_runtime.erl rename to apps/emqx_rule_engine/src/emqx_rule_runtime.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_sqlparser.erl b/apps/emqx_rule_engine/src/emqx_rule_sqlparser.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_sqlparser.erl rename to apps/emqx_rule_engine/src/emqx_rule_sqlparser.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_sqltester.erl b/apps/emqx_rule_engine/src/emqx_rule_sqltester.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_sqltester.erl rename to apps/emqx_rule_engine/src/emqx_rule_sqltester.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_utils.erl b/apps/emqx_rule_engine/src/emqx_rule_utils.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_utils.erl rename to apps/emqx_rule_engine/src/emqx_rule_utils.erl diff --git a/lib-opensource/emqx_rule_engine/src/emqx_rule_validator.erl b/apps/emqx_rule_engine/src/emqx_rule_validator.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/src/emqx_rule_validator.erl rename to apps/emqx_rule_engine/src/emqx_rule_validator.erl diff --git a/lib-opensource/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl rename to apps/emqx_rule_engine/test/emqx_rule_engine_SUITE.erl diff --git a/lib-opensource/emqx_rule_engine/test/emqx_rule_events_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_events_SUITE.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/test/emqx_rule_events_SUITE.erl rename to apps/emqx_rule_engine/test/emqx_rule_events_SUITE.erl diff --git a/lib-opensource/emqx_rule_engine/test/emqx_rule_funcs_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_funcs_SUITE.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/test/emqx_rule_funcs_SUITE.erl rename to apps/emqx_rule_engine/test/emqx_rule_funcs_SUITE.erl diff --git a/lib-opensource/emqx_rule_engine/test/emqx_rule_id_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_id_SUITE.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/test/emqx_rule_id_SUITE.erl rename to apps/emqx_rule_engine/test/emqx_rule_id_SUITE.erl diff --git a/lib-opensource/emqx_rule_engine/test/emqx_rule_maps_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_maps_SUITE.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/test/emqx_rule_maps_SUITE.erl rename to apps/emqx_rule_engine/test/emqx_rule_maps_SUITE.erl diff --git a/lib-opensource/emqx_rule_engine/test/emqx_rule_metrics_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_metrics_SUITE.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/test/emqx_rule_metrics_SUITE.erl rename to apps/emqx_rule_engine/test/emqx_rule_metrics_SUITE.erl diff --git a/lib-opensource/emqx_rule_engine/test/emqx_rule_registry_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_registry_SUITE.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/test/emqx_rule_registry_SUITE.erl rename to apps/emqx_rule_engine/test/emqx_rule_registry_SUITE.erl diff --git a/lib-opensource/emqx_rule_engine/test/emqx_rule_utils_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_utils_SUITE.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/test/emqx_rule_utils_SUITE.erl rename to apps/emqx_rule_engine/test/emqx_rule_utils_SUITE.erl diff --git a/lib-opensource/emqx_rule_engine/test/emqx_rule_validator_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_validator_SUITE.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/test/emqx_rule_validator_SUITE.erl rename to apps/emqx_rule_engine/test/emqx_rule_validator_SUITE.erl diff --git a/lib-opensource/emqx_rule_engine/test/prop_rule_maps.erl b/apps/emqx_rule_engine/test/prop_rule_maps.erl similarity index 100% rename from lib-opensource/emqx_rule_engine/test/prop_rule_maps.erl rename to apps/emqx_rule_engine/test/prop_rule_maps.erl diff --git a/apps/emqx_telemetry/.gitignore b/lib-opensource/emqx_telemetry/.gitignore similarity index 100% rename from apps/emqx_telemetry/.gitignore rename to lib-opensource/emqx_telemetry/.gitignore diff --git a/apps/emqx_telemetry/README.md b/lib-opensource/emqx_telemetry/README.md similarity index 100% rename from apps/emqx_telemetry/README.md rename to lib-opensource/emqx_telemetry/README.md diff --git a/apps/emqx_telemetry/etc/emqx_telemetry.conf b/lib-opensource/emqx_telemetry/etc/emqx_telemetry.conf similarity index 100% rename from apps/emqx_telemetry/etc/emqx_telemetry.conf rename to lib-opensource/emqx_telemetry/etc/emqx_telemetry.conf diff --git a/apps/emqx_telemetry/priv/emqx_telemetry.schema b/lib-opensource/emqx_telemetry/priv/emqx_telemetry.schema similarity index 100% rename from apps/emqx_telemetry/priv/emqx_telemetry.schema rename to lib-opensource/emqx_telemetry/priv/emqx_telemetry.schema diff --git a/apps/emqx_telemetry/rebar.config b/lib-opensource/emqx_telemetry/rebar.config similarity index 100% rename from apps/emqx_telemetry/rebar.config rename to lib-opensource/emqx_telemetry/rebar.config diff --git a/apps/emqx_telemetry/src/emqx_telemetry.app.src b/lib-opensource/emqx_telemetry/src/emqx_telemetry.app.src similarity index 100% rename from apps/emqx_telemetry/src/emqx_telemetry.app.src rename to lib-opensource/emqx_telemetry/src/emqx_telemetry.app.src diff --git a/apps/emqx_telemetry/src/emqx_telemetry.erl b/lib-opensource/emqx_telemetry/src/emqx_telemetry.erl similarity index 100% rename from apps/emqx_telemetry/src/emqx_telemetry.erl rename to lib-opensource/emqx_telemetry/src/emqx_telemetry.erl diff --git a/apps/emqx_telemetry/src/emqx_telemetry_api.erl b/lib-opensource/emqx_telemetry/src/emqx_telemetry_api.erl similarity index 100% rename from apps/emqx_telemetry/src/emqx_telemetry_api.erl rename to lib-opensource/emqx_telemetry/src/emqx_telemetry_api.erl diff --git a/apps/emqx_telemetry/src/emqx_telemetry_app.erl b/lib-opensource/emqx_telemetry/src/emqx_telemetry_app.erl similarity index 100% rename from apps/emqx_telemetry/src/emqx_telemetry_app.erl rename to lib-opensource/emqx_telemetry/src/emqx_telemetry_app.erl diff --git a/apps/emqx_telemetry/src/emqx_telemetry_sup.erl b/lib-opensource/emqx_telemetry/src/emqx_telemetry_sup.erl similarity index 100% rename from apps/emqx_telemetry/src/emqx_telemetry_sup.erl rename to lib-opensource/emqx_telemetry/src/emqx_telemetry_sup.erl diff --git a/apps/emqx_telemetry/test/emqx_telemetry_SUITE.erl b/lib-opensource/emqx_telemetry/test/emqx_telemetry_SUITE.erl similarity index 100% rename from apps/emqx_telemetry/test/emqx_telemetry_SUITE.erl rename to lib-opensource/emqx_telemetry/test/emqx_telemetry_SUITE.erl From aed58a14ee57e2cab673327a824a8994e0033ea3 Mon Sep 17 00:00:00 2001 From: Zaiming Shi Date: Fri, 19 Feb 2021 11:54:45 +0100 Subject: [PATCH 41/41] chore(build): rename lib-opensource to lib-ce for shorter name --- elvis.config | 4 ++-- get-dashboard.sh | 4 ++-- {lib-opensource => lib-ce}/emqx_dashboard/.gitignore | 0 {lib-opensource => lib-ce}/emqx_dashboard/README.md | 0 .../emqx_dashboard/etc/emqx_dashboard.conf | 0 .../emqx_dashboard/include/emqx_dashboard.hrl | 0 .../emqx_dashboard/priv/emqx_dashboard.schema | 0 {lib-opensource => lib-ce}/emqx_dashboard/rebar.config | 0 .../emqx_dashboard/src/emqx_dashboard.app.src | 0 .../emqx_dashboard/src/emqx_dashboard.erl | 0 .../emqx_dashboard/src/emqx_dashboard_admin.erl | 0 .../emqx_dashboard/src/emqx_dashboard_api.erl | 0 .../emqx_dashboard/src/emqx_dashboard_app.erl | 0 .../emqx_dashboard/src/emqx_dashboard_cli.erl | 0 .../emqx_dashboard/src/emqx_dashboard_sup.erl | 0 {lib-opensource => lib-ce}/emqx_dashboard/test/.placeholder | 0 .../emqx_dashboard/test/emqx_dashboard_SUITE.erl | 0 {lib-opensource => lib-ce}/emqx_management/.gitignore | 0 {lib-opensource => lib-ce}/emqx_management/README.md | 0 .../emqx_management/etc/emqx_management.conf | 0 .../emqx_management/include/emqx_mgmt.hrl | 0 .../emqx_management/priv/emqx_management.schema | 0 {lib-opensource => lib-ce}/emqx_management/rebar.config | 0 .../emqx_management/src/emqx_management.app.src | 0 .../emqx_management/src/emqx_mgmt.erl | 0 .../emqx_management/src/emqx_mgmt_api.erl | 0 .../emqx_management/src/emqx_mgmt_api_alarms.erl | 0 .../emqx_management/src/emqx_mgmt_api_apps.erl | 0 .../emqx_management/src/emqx_mgmt_api_banned.erl | 0 .../emqx_management/src/emqx_mgmt_api_brokers.erl | 0 .../emqx_management/src/emqx_mgmt_api_clients.erl | 0 .../emqx_management/src/emqx_mgmt_api_data.erl | 0 .../emqx_management/src/emqx_mgmt_api_listeners.erl | 0 .../emqx_management/src/emqx_mgmt_api_metrics.erl | 0 .../emqx_management/src/emqx_mgmt_api_modules.erl | 0 .../emqx_management/src/emqx_mgmt_api_nodes.erl | 0 .../emqx_management/src/emqx_mgmt_api_plugins.erl | 0 .../emqx_management/src/emqx_mgmt_api_pubsub.erl | 0 .../emqx_management/src/emqx_mgmt_api_routes.erl | 0 .../emqx_management/src/emqx_mgmt_api_stats.erl | 0 .../emqx_management/src/emqx_mgmt_api_subscriptions.erl | 0 .../emqx_management/src/emqx_mgmt_api_topic_metrics.erl | 0 .../emqx_management/src/emqx_mgmt_app.erl | 0 .../emqx_management/src/emqx_mgmt_auth.erl | 0 .../emqx_management/src/emqx_mgmt_cli.erl | 0 .../emqx_management/src/emqx_mgmt_http.erl | 0 .../emqx_management/src/emqx_mgmt_sup.erl | 0 .../emqx_management/src/emqx_mgmt_util.erl | 0 .../emqx_management/test/emqx_mgmt_SUITE.erl | 0 .../emqx_management/test/emqx_mgmt_api_SUITE.erl | 0 .../emqx_management/test/etc/emqx_management.conf | 0 .../emqx_management/test/etc/emqx_reloader.conf | 0 .../emqx_management/test/rfc6455_client.erl | 0 .../emqx_modules/etc/emqx_modules.conf | 0 .../emqx_modules/priv/emqx_modules.schema | 0 {lib-opensource => lib-ce}/emqx_modules/rebar.config | 0 .../emqx_modules/src/emqx_mod_acl_internal.erl | 0 .../emqx_modules/src/emqx_mod_delayed.erl | 0 .../emqx_modules/src/emqx_mod_presence.erl | 0 .../emqx_modules/src/emqx_mod_rewrite.erl | 0 .../emqx_modules/src/emqx_mod_subscription.erl | 0 .../emqx_modules/src/emqx_mod_sup.erl | 0 .../emqx_modules/src/emqx_mod_topic_metrics.erl | 0 .../emqx_modules/src/emqx_modules.app.src | 0 .../emqx_modules/src/emqx_modules.erl | 0 .../emqx_modules/src/emqx_modules_app.erl | 0 .../emqx_modules/test/emqx_mod_acl_internal_SUITE.erl | 0 .../emqx_modules/test/emqx_mod_delayed_SUITE.erl | 0 .../emqx_modules/test/emqx_mod_presence_SUITE.erl | 0 .../emqx_modules/test/emqx_mod_rewrite_SUITE.erl | 0 .../emqx_modules/test/emqx_mod_subscription_SUITE.erl | 0 .../emqx_modules/test/emqx_mod_sup_SUITE.erl | 0 .../emqx_modules/test/emqx_mod_topic_metrics_SUITE.erl | 0 .../emqx_modules/test/emqx_modules_SUITE.erl | 0 {lib-opensource => lib-ce}/emqx_telemetry/.gitignore | 0 {lib-opensource => lib-ce}/emqx_telemetry/README.md | 0 .../emqx_telemetry/etc/emqx_telemetry.conf | 0 .../emqx_telemetry/priv/emqx_telemetry.schema | 0 {lib-opensource => lib-ce}/emqx_telemetry/rebar.config | 0 .../emqx_telemetry/src/emqx_telemetry.app.src | 0 .../emqx_telemetry/src/emqx_telemetry.erl | 0 .../emqx_telemetry/src/emqx_telemetry_api.erl | 0 .../emqx_telemetry/src/emqx_telemetry_app.erl | 0 .../emqx_telemetry/src/emqx_telemetry_sup.erl | 0 .../emqx_telemetry/test/emqx_telemetry_SUITE.erl | 0 rebar.config.erl | 6 +++--- sync-apps.sh | 6 +++--- 87 files changed, 10 insertions(+), 10 deletions(-) rename {lib-opensource => lib-ce}/emqx_dashboard/.gitignore (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/README.md (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/etc/emqx_dashboard.conf (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/include/emqx_dashboard.hrl (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/priv/emqx_dashboard.schema (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/rebar.config (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/src/emqx_dashboard.app.src (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/src/emqx_dashboard.erl (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/src/emqx_dashboard_admin.erl (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/src/emqx_dashboard_api.erl (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/src/emqx_dashboard_app.erl (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/src/emqx_dashboard_cli.erl (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/src/emqx_dashboard_sup.erl (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/test/.placeholder (100%) rename {lib-opensource => lib-ce}/emqx_dashboard/test/emqx_dashboard_SUITE.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/.gitignore (100%) rename {lib-opensource => lib-ce}/emqx_management/README.md (100%) rename {lib-opensource => lib-ce}/emqx_management/etc/emqx_management.conf (100%) rename {lib-opensource => lib-ce}/emqx_management/include/emqx_mgmt.hrl (100%) rename {lib-opensource => lib-ce}/emqx_management/priv/emqx_management.schema (100%) rename {lib-opensource => lib-ce}/emqx_management/rebar.config (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_management.app.src (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_alarms.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_apps.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_banned.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_brokers.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_clients.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_data.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_listeners.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_metrics.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_modules.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_nodes.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_plugins.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_pubsub.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_routes.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_stats.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_subscriptions.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_api_topic_metrics.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_app.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_auth.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_cli.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_http.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_sup.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/src/emqx_mgmt_util.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/test/emqx_mgmt_SUITE.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/test/emqx_mgmt_api_SUITE.erl (100%) rename {lib-opensource => lib-ce}/emqx_management/test/etc/emqx_management.conf (100%) rename {lib-opensource => lib-ce}/emqx_management/test/etc/emqx_reloader.conf (100%) rename {lib-opensource => lib-ce}/emqx_management/test/rfc6455_client.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/etc/emqx_modules.conf (100%) rename {lib-opensource => lib-ce}/emqx_modules/priv/emqx_modules.schema (100%) rename {lib-opensource => lib-ce}/emqx_modules/rebar.config (100%) rename {lib-opensource => lib-ce}/emqx_modules/src/emqx_mod_acl_internal.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/src/emqx_mod_delayed.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/src/emqx_mod_presence.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/src/emqx_mod_rewrite.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/src/emqx_mod_subscription.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/src/emqx_mod_sup.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/src/emqx_mod_topic_metrics.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/src/emqx_modules.app.src (100%) rename {lib-opensource => lib-ce}/emqx_modules/src/emqx_modules.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/src/emqx_modules_app.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/test/emqx_mod_acl_internal_SUITE.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/test/emqx_mod_delayed_SUITE.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/test/emqx_mod_presence_SUITE.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/test/emqx_mod_rewrite_SUITE.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/test/emqx_mod_subscription_SUITE.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/test/emqx_mod_sup_SUITE.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/test/emqx_mod_topic_metrics_SUITE.erl (100%) rename {lib-opensource => lib-ce}/emqx_modules/test/emqx_modules_SUITE.erl (100%) rename {lib-opensource => lib-ce}/emqx_telemetry/.gitignore (100%) rename {lib-opensource => lib-ce}/emqx_telemetry/README.md (100%) rename {lib-opensource => lib-ce}/emqx_telemetry/etc/emqx_telemetry.conf (100%) rename {lib-opensource => lib-ce}/emqx_telemetry/priv/emqx_telemetry.schema (100%) rename {lib-opensource => lib-ce}/emqx_telemetry/rebar.config (100%) rename {lib-opensource => lib-ce}/emqx_telemetry/src/emqx_telemetry.app.src (100%) rename {lib-opensource => lib-ce}/emqx_telemetry/src/emqx_telemetry.erl (100%) rename {lib-opensource => lib-ce}/emqx_telemetry/src/emqx_telemetry_api.erl (100%) rename {lib-opensource => lib-ce}/emqx_telemetry/src/emqx_telemetry_app.erl (100%) rename {lib-opensource => lib-ce}/emqx_telemetry/src/emqx_telemetry_sup.erl (100%) rename {lib-opensource => lib-ce}/emqx_telemetry/test/emqx_telemetry_SUITE.erl (100%) diff --git a/elvis.config b/elvis.config index bb551e81a..bed4ba2e8 100644 --- a/elvis.config +++ b/elvis.config @@ -5,7 +5,7 @@ [ {config, [ - #{dirs => ["src", "apps/**/src", "lib-opensource/**/src"], + #{dirs => ["src", "apps/**/src", "lib-ce/**/src"], filter => "*.erl", ruleset => erl_files, rules => [ @@ -16,7 +16,7 @@ ]}} ] }, - #{dirs => ["test", "apps/**/test", "lib-opensource/**/src"], + #{dirs => ["test", "apps/**/test", "lib-ce/**/src"], filter => "*.erl", rules => [ {elvis_text_style, line_length, #{ limit => 100 diff --git a/get-dashboard.sh b/get-dashboard.sh index 885a68f77..991f2b39d 100755 --- a/get-dashboard.sh +++ b/get-dashboard.sh @@ -10,9 +10,9 @@ cd -P -- "$(dirname -- "$0")" DOWNLOAD_URL='https://github.com/emqx/emqx-dashboard-frontend/releases/download' if [ "$EMQX_ENTERPRISE" = 'true' ] || [ "$EMQX_ENTERPRISE" == '1' ]; then - DASHBOARD_PATH='lib-enterprise/emqx_dashboard/priv' + DASHBOARD_PATH='lib-ee/emqx_dashboard/priv' else - DASHBOARD_PATH='lib-opensource/emqx_dashboard/priv' + DASHBOARD_PATH='lib-ce/emqx_dashboard/priv' fi case $(uname) in diff --git a/lib-opensource/emqx_dashboard/.gitignore b/lib-ce/emqx_dashboard/.gitignore similarity index 100% rename from lib-opensource/emqx_dashboard/.gitignore rename to lib-ce/emqx_dashboard/.gitignore diff --git a/lib-opensource/emqx_dashboard/README.md b/lib-ce/emqx_dashboard/README.md similarity index 100% rename from lib-opensource/emqx_dashboard/README.md rename to lib-ce/emqx_dashboard/README.md diff --git a/lib-opensource/emqx_dashboard/etc/emqx_dashboard.conf b/lib-ce/emqx_dashboard/etc/emqx_dashboard.conf similarity index 100% rename from lib-opensource/emqx_dashboard/etc/emqx_dashboard.conf rename to lib-ce/emqx_dashboard/etc/emqx_dashboard.conf diff --git a/lib-opensource/emqx_dashboard/include/emqx_dashboard.hrl b/lib-ce/emqx_dashboard/include/emqx_dashboard.hrl similarity index 100% rename from lib-opensource/emqx_dashboard/include/emqx_dashboard.hrl rename to lib-ce/emqx_dashboard/include/emqx_dashboard.hrl diff --git a/lib-opensource/emqx_dashboard/priv/emqx_dashboard.schema b/lib-ce/emqx_dashboard/priv/emqx_dashboard.schema similarity index 100% rename from lib-opensource/emqx_dashboard/priv/emqx_dashboard.schema rename to lib-ce/emqx_dashboard/priv/emqx_dashboard.schema diff --git a/lib-opensource/emqx_dashboard/rebar.config b/lib-ce/emqx_dashboard/rebar.config similarity index 100% rename from lib-opensource/emqx_dashboard/rebar.config rename to lib-ce/emqx_dashboard/rebar.config diff --git a/lib-opensource/emqx_dashboard/src/emqx_dashboard.app.src b/lib-ce/emqx_dashboard/src/emqx_dashboard.app.src similarity index 100% rename from lib-opensource/emqx_dashboard/src/emqx_dashboard.app.src rename to lib-ce/emqx_dashboard/src/emqx_dashboard.app.src diff --git a/lib-opensource/emqx_dashboard/src/emqx_dashboard.erl b/lib-ce/emqx_dashboard/src/emqx_dashboard.erl similarity index 100% rename from lib-opensource/emqx_dashboard/src/emqx_dashboard.erl rename to lib-ce/emqx_dashboard/src/emqx_dashboard.erl diff --git a/lib-opensource/emqx_dashboard/src/emqx_dashboard_admin.erl b/lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl similarity index 100% rename from lib-opensource/emqx_dashboard/src/emqx_dashboard_admin.erl rename to lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl diff --git a/lib-opensource/emqx_dashboard/src/emqx_dashboard_api.erl b/lib-ce/emqx_dashboard/src/emqx_dashboard_api.erl similarity index 100% rename from lib-opensource/emqx_dashboard/src/emqx_dashboard_api.erl rename to lib-ce/emqx_dashboard/src/emqx_dashboard_api.erl diff --git a/lib-opensource/emqx_dashboard/src/emqx_dashboard_app.erl b/lib-ce/emqx_dashboard/src/emqx_dashboard_app.erl similarity index 100% rename from lib-opensource/emqx_dashboard/src/emqx_dashboard_app.erl rename to lib-ce/emqx_dashboard/src/emqx_dashboard_app.erl diff --git a/lib-opensource/emqx_dashboard/src/emqx_dashboard_cli.erl b/lib-ce/emqx_dashboard/src/emqx_dashboard_cli.erl similarity index 100% rename from lib-opensource/emqx_dashboard/src/emqx_dashboard_cli.erl rename to lib-ce/emqx_dashboard/src/emqx_dashboard_cli.erl diff --git a/lib-opensource/emqx_dashboard/src/emqx_dashboard_sup.erl b/lib-ce/emqx_dashboard/src/emqx_dashboard_sup.erl similarity index 100% rename from lib-opensource/emqx_dashboard/src/emqx_dashboard_sup.erl rename to lib-ce/emqx_dashboard/src/emqx_dashboard_sup.erl diff --git a/lib-opensource/emqx_dashboard/test/.placeholder b/lib-ce/emqx_dashboard/test/.placeholder similarity index 100% rename from lib-opensource/emqx_dashboard/test/.placeholder rename to lib-ce/emqx_dashboard/test/.placeholder diff --git a/lib-opensource/emqx_dashboard/test/emqx_dashboard_SUITE.erl b/lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl similarity index 100% rename from lib-opensource/emqx_dashboard/test/emqx_dashboard_SUITE.erl rename to lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl diff --git a/lib-opensource/emqx_management/.gitignore b/lib-ce/emqx_management/.gitignore similarity index 100% rename from lib-opensource/emqx_management/.gitignore rename to lib-ce/emqx_management/.gitignore diff --git a/lib-opensource/emqx_management/README.md b/lib-ce/emqx_management/README.md similarity index 100% rename from lib-opensource/emqx_management/README.md rename to lib-ce/emqx_management/README.md diff --git a/lib-opensource/emqx_management/etc/emqx_management.conf b/lib-ce/emqx_management/etc/emqx_management.conf similarity index 100% rename from lib-opensource/emqx_management/etc/emqx_management.conf rename to lib-ce/emqx_management/etc/emqx_management.conf diff --git a/lib-opensource/emqx_management/include/emqx_mgmt.hrl b/lib-ce/emqx_management/include/emqx_mgmt.hrl similarity index 100% rename from lib-opensource/emqx_management/include/emqx_mgmt.hrl rename to lib-ce/emqx_management/include/emqx_mgmt.hrl diff --git a/lib-opensource/emqx_management/priv/emqx_management.schema b/lib-ce/emqx_management/priv/emqx_management.schema similarity index 100% rename from lib-opensource/emqx_management/priv/emqx_management.schema rename to lib-ce/emqx_management/priv/emqx_management.schema diff --git a/lib-opensource/emqx_management/rebar.config b/lib-ce/emqx_management/rebar.config similarity index 100% rename from lib-opensource/emqx_management/rebar.config rename to lib-ce/emqx_management/rebar.config diff --git a/lib-opensource/emqx_management/src/emqx_management.app.src b/lib-ce/emqx_management/src/emqx_management.app.src similarity index 100% rename from lib-opensource/emqx_management/src/emqx_management.app.src rename to lib-ce/emqx_management/src/emqx_management.app.src diff --git a/lib-opensource/emqx_management/src/emqx_mgmt.erl b/lib-ce/emqx_management/src/emqx_mgmt.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt.erl rename to lib-ce/emqx_management/src/emqx_mgmt.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api.erl b/lib-ce/emqx_management/src/emqx_mgmt_api.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_alarms.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_alarms.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_alarms.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_alarms.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_apps.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_apps.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_apps.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_apps.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_banned.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_banned.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_banned.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_banned.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_brokers.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_brokers.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_brokers.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_brokers.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_clients.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_clients.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_clients.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_clients.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_data.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_data.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_data.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_data.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_listeners.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_listeners.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_listeners.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_listeners.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_metrics.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_metrics.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_metrics.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_metrics.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_modules.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_modules.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_modules.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_modules.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_nodes.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_nodes.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_nodes.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_nodes.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_plugins.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_plugins.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_plugins.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_plugins.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_pubsub.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_pubsub.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_pubsub.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_pubsub.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_routes.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_routes.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_routes.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_routes.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_stats.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_stats.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_stats.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_stats.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_subscriptions.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_subscriptions.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_subscriptions.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_subscriptions.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_api_topic_metrics.erl b/lib-ce/emqx_management/src/emqx_mgmt_api_topic_metrics.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_api_topic_metrics.erl rename to lib-ce/emqx_management/src/emqx_mgmt_api_topic_metrics.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_app.erl b/lib-ce/emqx_management/src/emqx_mgmt_app.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_app.erl rename to lib-ce/emqx_management/src/emqx_mgmt_app.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_auth.erl b/lib-ce/emqx_management/src/emqx_mgmt_auth.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_auth.erl rename to lib-ce/emqx_management/src/emqx_mgmt_auth.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_cli.erl b/lib-ce/emqx_management/src/emqx_mgmt_cli.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_cli.erl rename to lib-ce/emqx_management/src/emqx_mgmt_cli.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_http.erl b/lib-ce/emqx_management/src/emqx_mgmt_http.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_http.erl rename to lib-ce/emqx_management/src/emqx_mgmt_http.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_sup.erl b/lib-ce/emqx_management/src/emqx_mgmt_sup.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_sup.erl rename to lib-ce/emqx_management/src/emqx_mgmt_sup.erl diff --git a/lib-opensource/emqx_management/src/emqx_mgmt_util.erl b/lib-ce/emqx_management/src/emqx_mgmt_util.erl similarity index 100% rename from lib-opensource/emqx_management/src/emqx_mgmt_util.erl rename to lib-ce/emqx_management/src/emqx_mgmt_util.erl diff --git a/lib-opensource/emqx_management/test/emqx_mgmt_SUITE.erl b/lib-ce/emqx_management/test/emqx_mgmt_SUITE.erl similarity index 100% rename from lib-opensource/emqx_management/test/emqx_mgmt_SUITE.erl rename to lib-ce/emqx_management/test/emqx_mgmt_SUITE.erl diff --git a/lib-opensource/emqx_management/test/emqx_mgmt_api_SUITE.erl b/lib-ce/emqx_management/test/emqx_mgmt_api_SUITE.erl similarity index 100% rename from lib-opensource/emqx_management/test/emqx_mgmt_api_SUITE.erl rename to lib-ce/emqx_management/test/emqx_mgmt_api_SUITE.erl diff --git a/lib-opensource/emqx_management/test/etc/emqx_management.conf b/lib-ce/emqx_management/test/etc/emqx_management.conf similarity index 100% rename from lib-opensource/emqx_management/test/etc/emqx_management.conf rename to lib-ce/emqx_management/test/etc/emqx_management.conf diff --git a/lib-opensource/emqx_management/test/etc/emqx_reloader.conf b/lib-ce/emqx_management/test/etc/emqx_reloader.conf similarity index 100% rename from lib-opensource/emqx_management/test/etc/emqx_reloader.conf rename to lib-ce/emqx_management/test/etc/emqx_reloader.conf diff --git a/lib-opensource/emqx_management/test/rfc6455_client.erl b/lib-ce/emqx_management/test/rfc6455_client.erl similarity index 100% rename from lib-opensource/emqx_management/test/rfc6455_client.erl rename to lib-ce/emqx_management/test/rfc6455_client.erl diff --git a/lib-opensource/emqx_modules/etc/emqx_modules.conf b/lib-ce/emqx_modules/etc/emqx_modules.conf similarity index 100% rename from lib-opensource/emqx_modules/etc/emqx_modules.conf rename to lib-ce/emqx_modules/etc/emqx_modules.conf diff --git a/lib-opensource/emqx_modules/priv/emqx_modules.schema b/lib-ce/emqx_modules/priv/emqx_modules.schema similarity index 100% rename from lib-opensource/emqx_modules/priv/emqx_modules.schema rename to lib-ce/emqx_modules/priv/emqx_modules.schema diff --git a/lib-opensource/emqx_modules/rebar.config b/lib-ce/emqx_modules/rebar.config similarity index 100% rename from lib-opensource/emqx_modules/rebar.config rename to lib-ce/emqx_modules/rebar.config diff --git a/lib-opensource/emqx_modules/src/emqx_mod_acl_internal.erl b/lib-ce/emqx_modules/src/emqx_mod_acl_internal.erl similarity index 100% rename from lib-opensource/emqx_modules/src/emqx_mod_acl_internal.erl rename to lib-ce/emqx_modules/src/emqx_mod_acl_internal.erl diff --git a/lib-opensource/emqx_modules/src/emqx_mod_delayed.erl b/lib-ce/emqx_modules/src/emqx_mod_delayed.erl similarity index 100% rename from lib-opensource/emqx_modules/src/emqx_mod_delayed.erl rename to lib-ce/emqx_modules/src/emqx_mod_delayed.erl diff --git a/lib-opensource/emqx_modules/src/emqx_mod_presence.erl b/lib-ce/emqx_modules/src/emqx_mod_presence.erl similarity index 100% rename from lib-opensource/emqx_modules/src/emqx_mod_presence.erl rename to lib-ce/emqx_modules/src/emqx_mod_presence.erl diff --git a/lib-opensource/emqx_modules/src/emqx_mod_rewrite.erl b/lib-ce/emqx_modules/src/emqx_mod_rewrite.erl similarity index 100% rename from lib-opensource/emqx_modules/src/emqx_mod_rewrite.erl rename to lib-ce/emqx_modules/src/emqx_mod_rewrite.erl diff --git a/lib-opensource/emqx_modules/src/emqx_mod_subscription.erl b/lib-ce/emqx_modules/src/emqx_mod_subscription.erl similarity index 100% rename from lib-opensource/emqx_modules/src/emqx_mod_subscription.erl rename to lib-ce/emqx_modules/src/emqx_mod_subscription.erl diff --git a/lib-opensource/emqx_modules/src/emqx_mod_sup.erl b/lib-ce/emqx_modules/src/emqx_mod_sup.erl similarity index 100% rename from lib-opensource/emqx_modules/src/emqx_mod_sup.erl rename to lib-ce/emqx_modules/src/emqx_mod_sup.erl diff --git a/lib-opensource/emqx_modules/src/emqx_mod_topic_metrics.erl b/lib-ce/emqx_modules/src/emqx_mod_topic_metrics.erl similarity index 100% rename from lib-opensource/emqx_modules/src/emqx_mod_topic_metrics.erl rename to lib-ce/emqx_modules/src/emqx_mod_topic_metrics.erl diff --git a/lib-opensource/emqx_modules/src/emqx_modules.app.src b/lib-ce/emqx_modules/src/emqx_modules.app.src similarity index 100% rename from lib-opensource/emqx_modules/src/emqx_modules.app.src rename to lib-ce/emqx_modules/src/emqx_modules.app.src diff --git a/lib-opensource/emqx_modules/src/emqx_modules.erl b/lib-ce/emqx_modules/src/emqx_modules.erl similarity index 100% rename from lib-opensource/emqx_modules/src/emqx_modules.erl rename to lib-ce/emqx_modules/src/emqx_modules.erl diff --git a/lib-opensource/emqx_modules/src/emqx_modules_app.erl b/lib-ce/emqx_modules/src/emqx_modules_app.erl similarity index 100% rename from lib-opensource/emqx_modules/src/emqx_modules_app.erl rename to lib-ce/emqx_modules/src/emqx_modules_app.erl diff --git a/lib-opensource/emqx_modules/test/emqx_mod_acl_internal_SUITE.erl b/lib-ce/emqx_modules/test/emqx_mod_acl_internal_SUITE.erl similarity index 100% rename from lib-opensource/emqx_modules/test/emqx_mod_acl_internal_SUITE.erl rename to lib-ce/emqx_modules/test/emqx_mod_acl_internal_SUITE.erl diff --git a/lib-opensource/emqx_modules/test/emqx_mod_delayed_SUITE.erl b/lib-ce/emqx_modules/test/emqx_mod_delayed_SUITE.erl similarity index 100% rename from lib-opensource/emqx_modules/test/emqx_mod_delayed_SUITE.erl rename to lib-ce/emqx_modules/test/emqx_mod_delayed_SUITE.erl diff --git a/lib-opensource/emqx_modules/test/emqx_mod_presence_SUITE.erl b/lib-ce/emqx_modules/test/emqx_mod_presence_SUITE.erl similarity index 100% rename from lib-opensource/emqx_modules/test/emqx_mod_presence_SUITE.erl rename to lib-ce/emqx_modules/test/emqx_mod_presence_SUITE.erl diff --git a/lib-opensource/emqx_modules/test/emqx_mod_rewrite_SUITE.erl b/lib-ce/emqx_modules/test/emqx_mod_rewrite_SUITE.erl similarity index 100% rename from lib-opensource/emqx_modules/test/emqx_mod_rewrite_SUITE.erl rename to lib-ce/emqx_modules/test/emqx_mod_rewrite_SUITE.erl diff --git a/lib-opensource/emqx_modules/test/emqx_mod_subscription_SUITE.erl b/lib-ce/emqx_modules/test/emqx_mod_subscription_SUITE.erl similarity index 100% rename from lib-opensource/emqx_modules/test/emqx_mod_subscription_SUITE.erl rename to lib-ce/emqx_modules/test/emqx_mod_subscription_SUITE.erl diff --git a/lib-opensource/emqx_modules/test/emqx_mod_sup_SUITE.erl b/lib-ce/emqx_modules/test/emqx_mod_sup_SUITE.erl similarity index 100% rename from lib-opensource/emqx_modules/test/emqx_mod_sup_SUITE.erl rename to lib-ce/emqx_modules/test/emqx_mod_sup_SUITE.erl diff --git a/lib-opensource/emqx_modules/test/emqx_mod_topic_metrics_SUITE.erl b/lib-ce/emqx_modules/test/emqx_mod_topic_metrics_SUITE.erl similarity index 100% rename from lib-opensource/emqx_modules/test/emqx_mod_topic_metrics_SUITE.erl rename to lib-ce/emqx_modules/test/emqx_mod_topic_metrics_SUITE.erl diff --git a/lib-opensource/emqx_modules/test/emqx_modules_SUITE.erl b/lib-ce/emqx_modules/test/emqx_modules_SUITE.erl similarity index 100% rename from lib-opensource/emqx_modules/test/emqx_modules_SUITE.erl rename to lib-ce/emqx_modules/test/emqx_modules_SUITE.erl diff --git a/lib-opensource/emqx_telemetry/.gitignore b/lib-ce/emqx_telemetry/.gitignore similarity index 100% rename from lib-opensource/emqx_telemetry/.gitignore rename to lib-ce/emqx_telemetry/.gitignore diff --git a/lib-opensource/emqx_telemetry/README.md b/lib-ce/emqx_telemetry/README.md similarity index 100% rename from lib-opensource/emqx_telemetry/README.md rename to lib-ce/emqx_telemetry/README.md diff --git a/lib-opensource/emqx_telemetry/etc/emqx_telemetry.conf b/lib-ce/emqx_telemetry/etc/emqx_telemetry.conf similarity index 100% rename from lib-opensource/emqx_telemetry/etc/emqx_telemetry.conf rename to lib-ce/emqx_telemetry/etc/emqx_telemetry.conf diff --git a/lib-opensource/emqx_telemetry/priv/emqx_telemetry.schema b/lib-ce/emqx_telemetry/priv/emqx_telemetry.schema similarity index 100% rename from lib-opensource/emqx_telemetry/priv/emqx_telemetry.schema rename to lib-ce/emqx_telemetry/priv/emqx_telemetry.schema diff --git a/lib-opensource/emqx_telemetry/rebar.config b/lib-ce/emqx_telemetry/rebar.config similarity index 100% rename from lib-opensource/emqx_telemetry/rebar.config rename to lib-ce/emqx_telemetry/rebar.config diff --git a/lib-opensource/emqx_telemetry/src/emqx_telemetry.app.src b/lib-ce/emqx_telemetry/src/emqx_telemetry.app.src similarity index 100% rename from lib-opensource/emqx_telemetry/src/emqx_telemetry.app.src rename to lib-ce/emqx_telemetry/src/emqx_telemetry.app.src diff --git a/lib-opensource/emqx_telemetry/src/emqx_telemetry.erl b/lib-ce/emqx_telemetry/src/emqx_telemetry.erl similarity index 100% rename from lib-opensource/emqx_telemetry/src/emqx_telemetry.erl rename to lib-ce/emqx_telemetry/src/emqx_telemetry.erl diff --git a/lib-opensource/emqx_telemetry/src/emqx_telemetry_api.erl b/lib-ce/emqx_telemetry/src/emqx_telemetry_api.erl similarity index 100% rename from lib-opensource/emqx_telemetry/src/emqx_telemetry_api.erl rename to lib-ce/emqx_telemetry/src/emqx_telemetry_api.erl diff --git a/lib-opensource/emqx_telemetry/src/emqx_telemetry_app.erl b/lib-ce/emqx_telemetry/src/emqx_telemetry_app.erl similarity index 100% rename from lib-opensource/emqx_telemetry/src/emqx_telemetry_app.erl rename to lib-ce/emqx_telemetry/src/emqx_telemetry_app.erl diff --git a/lib-opensource/emqx_telemetry/src/emqx_telemetry_sup.erl b/lib-ce/emqx_telemetry/src/emqx_telemetry_sup.erl similarity index 100% rename from lib-opensource/emqx_telemetry/src/emqx_telemetry_sup.erl rename to lib-ce/emqx_telemetry/src/emqx_telemetry_sup.erl diff --git a/lib-opensource/emqx_telemetry/test/emqx_telemetry_SUITE.erl b/lib-ce/emqx_telemetry/test/emqx_telemetry_SUITE.erl similarity index 100% rename from lib-opensource/emqx_telemetry/test/emqx_telemetry_SUITE.erl rename to lib-ce/emqx_telemetry/test/emqx_telemetry_SUITE.erl diff --git a/rebar.config.erl b/rebar.config.erl index 123c39af5..2365e9999 100644 --- a/rebar.config.erl +++ b/rebar.config.erl @@ -28,8 +28,8 @@ config() -> extra_lib_dir() -> EnterpriseFlag = os:getenv("EMQX_ENTERPRISE"), case EnterpriseFlag =:= "true" orelse EnterpriseFlag =:= "1" of - true -> "lib-enterprise"; - false -> "lib-opensource" + true -> "lib-ee"; + false -> "lib-ce" end. project_app_dirs() -> @@ -279,7 +279,7 @@ provide_bcrypt_release(ReleaseType) -> %% rebar3 does not handle umberella project's cross-app parse_transform well compile_and_load_pase_transforms(Dir) -> PtFiles = - [ "lib-opensource/emqx_rule_engine/src/emqx_rule_actions_trans.erl" + [ "apps/emqx_rule_engine/src/emqx_rule_actions_trans.erl" ], CompileOpts = [verbose,report_errors,report_warnings,return_errors,debug_info], lists:foreach(fun(PtFile) -> {ok, _Mod} = compile:file(path(Dir, PtFile), CompileOpts) end, PtFiles). diff --git a/sync-apps.sh b/sync-apps.sh index e5c36228f..1e8da78cc 100755 --- a/sync-apps.sh +++ b/sync-apps.sh @@ -15,17 +15,17 @@ apps=( "emqx_auth_redis" "emqx_bridge_mqtt" "emqx_coap" -# "emqx_dashboard" # moved to lib-opensource +# "emqx_dashboard" # moved to lib-ce "emqx_exhook" "emqx_exproto" "emqx_lua_hook" "emqx_lwm2m" -# "emqx_management" # moved to lib-opensource +# "emqx_management" # moved to lib-ce "emqx_prometheus" "emqx_psk_file" "emqx_recon" "emqx_retainer" -# "emqx_rule_engine" # moved to lib-opensource +# "emqx_rule_engine" # moved to lib-ce "emqx_sasl" "emqx_sn" "emqx_stomp"