commit
8566d2e246
|
@ -0,0 +1,25 @@
|
||||||
|
name: Spellcheck
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: [Build slim packages]
|
||||||
|
types:
|
||||||
|
- completed
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
spellcheck_schema:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: emqx-24.1.5-4-ubuntu20.04
|
||||||
|
path: .
|
||||||
|
- name: Run spellcheck
|
||||||
|
run: |
|
||||||
|
tar zxf *.tar.gz
|
||||||
|
find . -name schema.json -exec scripts/spellcheck \{\} \;
|
|
@ -72,7 +72,7 @@ fields(limiter_opts) ->
|
||||||
[ {global, sc(ref(rate_burst), #{})}
|
[ {global, sc(ref(rate_burst), #{})}
|
||||||
, {zone, sc(map("zone name", ref(rate_burst)), #{})}
|
, {zone, sc(map("zone name", ref(rate_burst)), #{})}
|
||||||
, {bucket, sc(map("bucket_id", ref(bucket)),
|
, {bucket, sc(map("bucket_id", ref(bucket)),
|
||||||
#{desc => "token bucket"})}
|
#{desc => "Token bucket"})}
|
||||||
];
|
];
|
||||||
|
|
||||||
fields(rate_burst) ->
|
fields(rate_burst) ->
|
||||||
|
@ -81,7 +81,7 @@ fields(rate_burst) ->
|
||||||
];
|
];
|
||||||
|
|
||||||
fields(bucket) ->
|
fields(bucket) ->
|
||||||
[ {zone, sc(atom(), #{desc => "the zone which the bucket in"})}
|
[ {zone, sc(atom(), #{desc => "The bucket's zone"})}
|
||||||
, {aggregated, sc(ref(bucket_aggregated), #{})}
|
, {aggregated, sc(ref(bucket_aggregated), #{})}
|
||||||
, {per_client, sc(ref(client_bucket), #{})}
|
, {per_client, sc(ref(client_bucket), #{})}
|
||||||
];
|
];
|
||||||
|
@ -100,18 +100,18 @@ fields(client_bucket) ->
|
||||||
%% so we need to use this value to prevent excessive consumption
|
%% so we need to use this value to prevent excessive consumption
|
||||||
%% (e.g, consumption from an empty bucket)
|
%% (e.g, consumption from an empty bucket)
|
||||||
, {low_water_mark, sc(initial(),
|
, {low_water_mark, sc(initial(),
|
||||||
#{desc => "if the remaining tokens are lower than this value,
|
#{desc => "If the remaining tokens are lower than this value,
|
||||||
the check/consume will succeed, but it will be forced to hang for a short period of time",
|
the check/consume will succeed, but it will be forced to wait for a short period of time.",
|
||||||
default => "0"})}
|
default => "0"})}
|
||||||
, {capacity, sc(capacity(), #{desc => "the capacity of the token bucket"})}
|
, {capacity, sc(capacity(), #{desc => "The capacity of the token bucket."})}
|
||||||
, {divisible, sc(boolean(),
|
, {divisible, sc(boolean(),
|
||||||
#{desc => "is it possible to split the number of tokens requested",
|
#{desc => "Is it possible to split the number of requested tokens?",
|
||||||
default => false})}
|
default => false})}
|
||||||
, {max_retry_time, sc(emqx_schema:duration(),
|
, {max_retry_time, sc(emqx_schema:duration(),
|
||||||
#{ desc => "the maximum retry time when acquire failed"
|
#{ desc => "The maximum retry time when acquire failed."
|
||||||
, default => "5s"})}
|
, default => "5s"})}
|
||||||
, {failure_strategy, sc(failure_strategy(),
|
, {failure_strategy, sc(failure_strategy(),
|
||||||
#{ desc => "the strategy when all retry failed"
|
#{ desc => "The strategy when all the retries failed."
|
||||||
, default => force})}
|
, default => force})}
|
||||||
].
|
].
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ roots(high) ->
|
||||||
"""A zone is a set of configs grouped by the zone <code>name</code>.<br>
|
"""A zone is a set of configs grouped by the zone <code>name</code>.<br>
|
||||||
For flexible configuration mapping, the <code>name</code>
|
For flexible configuration mapping, the <code>name</code>
|
||||||
can be set to a listener's <code>zone</code> config.<br>
|
can be set to a listener's <code>zone</code> config.<br>
|
||||||
NOTE: A builtin zone named <code>default</code> is auto created
|
NOTE: A built-in zone named <code>default</code> is auto created
|
||||||
and can not be deleted."""
|
and can not be deleted."""
|
||||||
})}
|
})}
|
||||||
, {"mqtt",
|
, {"mqtt",
|
||||||
|
@ -337,7 +337,7 @@ message within this interval."""
|
||||||
, {"ignore_loop_deliver",
|
, {"ignore_loop_deliver",
|
||||||
sc(boolean(),
|
sc(boolean(),
|
||||||
#{ default => false,
|
#{ default => false,
|
||||||
desc => "Ignore loop delivery of messages for mqtt v3.1.1."
|
desc => "Ignore loop delivery of messages for MQTT v3.1.1."
|
||||||
})}
|
})}
|
||||||
, {"strict_mode",
|
, {"strict_mode",
|
||||||
sc(boolean(),
|
sc(boolean(),
|
||||||
|
@ -357,9 +357,9 @@ This feature is disabled if is set to \"\"."""
|
||||||
sc(hoconsc:union([integer(), disabled]),
|
sc(hoconsc:union([integer(), disabled]),
|
||||||
#{ default => disabled,
|
#{ default => disabled,
|
||||||
desc =>
|
desc =>
|
||||||
"""Server Keep Alive of MQTT 5.0.
|
"""'Server Keep Alive' of MQTT 5.0.
|
||||||
If the Server returns a Server Keep Alive on the CONNACK packet,
|
If the server returns a 'Server Keep Alive' in the CONNACK packet,
|
||||||
the Client MUST use that value instead of the value it sent as the Keep Alive."""
|
the client MUST use that value instead of the value it sent as the 'Keep Alive'."""
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
, {"keepalive_backoff",
|
, {"keepalive_backoff",
|
||||||
|
@ -430,17 +430,18 @@ Priority number [1-255]<br>
|
||||||
|
|
||||||
**NOTE**: Comma and equal signs are not allowed for priority topic names.<br>
|
**NOTE**: Comma and equal signs are not allowed for priority topic names.<br>
|
||||||
**NOTE**: Messages for topics not in the priority table are treated as
|
**NOTE**: Messages for topics not in the priority table are treated as
|
||||||
either highest or lowest priority depending on the configured value for mqtt.mqueue_default_priority.
|
either highest or lowest priority depending on the configured value for
|
||||||
|
<code>mqtt.mqueue_default_priority</code>.
|
||||||
<br><br>
|
<br><br>
|
||||||
**Examples**:
|
**Examples**:
|
||||||
To configure \"topic/1\" > \"topic/2\":
|
To configure <code>\"topic/1\" > \"topic/2\"</code>:<br/>
|
||||||
mqueue_priorities: {\"topic/1\": 10, \"topic/2\": 8}"""
|
<code>mqueue_priorities: {\"topic/1\": 10, \"topic/2\": 8}</code>"""
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
, {"mqueue_default_priority",
|
, {"mqueue_default_priority",
|
||||||
sc(hoconsc:enum([highest, lowest]),
|
sc(hoconsc:enum([highest, lowest]),
|
||||||
#{ default => lowest,
|
#{ default => lowest,
|
||||||
desc => "Default to highest priority for topics not matching priority table."
|
desc => "Default to the highest priority for topics not matching priority table."
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
, {"mqueue_store_qos0",
|
, {"mqueue_store_qos0",
|
||||||
|
@ -452,7 +453,7 @@ mqueue_priorities: {\"topic/1\": 10, \"topic/2\": 8}"""
|
||||||
, {"use_username_as_clientid",
|
, {"use_username_as_clientid",
|
||||||
sc(boolean(),
|
sc(boolean(),
|
||||||
#{ default => false,
|
#{ default => false,
|
||||||
desc => "Replace client id with the username."
|
desc => "Replace client ID with the username."
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
, {"peer_cert_as_username",
|
, {"peer_cert_as_username",
|
||||||
|
@ -1071,10 +1072,10 @@ fields("alarm") ->
|
||||||
validator => fun ?MODULE:validate_alarm_actions/1,
|
validator => fun ?MODULE:validate_alarm_actions/1,
|
||||||
example => [log, publish],
|
example => [log, publish],
|
||||||
desc =>
|
desc =>
|
||||||
"""The actions triggered when the alarm is activated.<\br>
|
"""The actions triggered when the alarm is activated.<br/>
|
||||||
Currently support two actions, 'log' and 'publish'.
|
Currently, the following actions are supported: <code>log</code> and <code>publish</code>.
|
||||||
'log' is to write the alarm to log (console or file).
|
<code>log</code> is to write the alarm to log (console or file).
|
||||||
'publish' is to publish the alarm as an MQTT message to the system topics:
|
<code>publish</code> is to publish the alarm as an MQTT message to the system topics:
|
||||||
<code>$SYS/brokers/emqx@xx.xx.xx.x/alarms/activate</code> and
|
<code>$SYS/brokers/emqx@xx.xx.xx.x/alarms/activate</code> and
|
||||||
<code>$SYS/brokers/emqx@xx.xx.xx.x/alarms/deactivate</code>"""
|
<code>$SYS/brokers/emqx@xx.xx.xx.x/alarms/deactivate</code>"""
|
||||||
})
|
})
|
||||||
|
@ -1216,7 +1217,7 @@ already established connections.
|
||||||
The certificates in this file should be in reversed order of the certificate
|
The certificates in this file should be in reversed order of the certificate
|
||||||
issue chain. That is, the host's certificate should be placed in the beginning
|
issue chain. That is, the host's certificate should be placed in the beginning
|
||||||
of the file, followed by the immediate issuer certificate and so on.
|
of the file, followed by the immediate issuer certificate and so on.
|
||||||
Although the root CA certificate is optional, it should placed at the end of
|
Although the root CA certificate is optional, it should be placed at the end of
|
||||||
the file if it is to be added.
|
the file if it is to be added.
|
||||||
"""
|
"""
|
||||||
})
|
})
|
||||||
|
@ -1302,7 +1303,7 @@ server_ssl_opts_schema(Defaults, IsRanchListener) ->
|
||||||
to be used by the server if a cipher suite using Diffie Hellman
|
to be used by the server if a cipher suite using Diffie Hellman
|
||||||
key exchange is negotiated. If not specified, default parameters
|
key exchange is negotiated. If not specified, default parameters
|
||||||
are used.<br>
|
are used.<br>
|
||||||
NOTE: The dhfile option is not supported by TLS 1.3."""
|
NOTE: The <code>dhfile</code> option is not supported by TLS 1.3."""
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
, {"fail_if_no_peer_cert",
|
, {"fail_if_no_peer_cert",
|
||||||
|
@ -1463,7 +1464,7 @@ ref(Field) -> hoconsc:ref(?MODULE, Field).
|
||||||
ref(Module, Field) -> hoconsc:ref(Module, Field).
|
ref(Module, Field) -> hoconsc:ref(Module, Field).
|
||||||
|
|
||||||
mk_duration(Desc, OverrideMeta) ->
|
mk_duration(Desc, OverrideMeta) ->
|
||||||
DefaultMeta = #{desc => Desc ++ " Time span. A text string with number followed by time units:
|
DefaultMeta = #{desc => Desc ++ " time span. A text string with number followed by time units:
|
||||||
`ms` for milliseconds,
|
`ms` for milliseconds,
|
||||||
`s` for seconds,
|
`s` for seconds,
|
||||||
`m` for minutes,
|
`m` for minutes,
|
||||||
|
|
|
@ -69,11 +69,10 @@ fields("authorization") ->
|
||||||
"""
|
"""
|
||||||
Authorization data sources.<br>
|
Authorization data sources.<br>
|
||||||
An array of authorization (ACL) data providers.
|
An array of authorization (ACL) data providers.
|
||||||
It is designed as an array but not a hash-map so the sources can be
|
It is designed as an array, not a hash-map, so the sources can be
|
||||||
ordered to form a chain of access controls.<br>
|
ordered to form a chain of access controls.<br>
|
||||||
|
|
||||||
|
When authorizing a 'publish' or 'subscribe' action, the configured
|
||||||
When authorizing a publish or subscribe action, the configured
|
|
||||||
sources are checked in order. When checking an ACL source,
|
sources are checked in order. When checking an ACL source,
|
||||||
in case the client (identified by username or client ID) is not found,
|
in case the client (identified by username or client ID) is not found,
|
||||||
it moves on to the next source. And it stops immediately
|
it moves on to the next source. And it stops immediately
|
||||||
|
@ -145,7 +144,7 @@ fields(redis_cluster) ->
|
||||||
|
|
||||||
http_common_fields() ->
|
http_common_fields() ->
|
||||||
[ {url, fun url/1}
|
[ {url, fun url/1}
|
||||||
, {request_timeout, mk_duration("request timeout", #{default => "30s"})}
|
, {request_timeout, mk_duration("Request timeout", #{default => "30s"})}
|
||||||
, {body, #{type => map(), nullable => true}}
|
, {body, #{type => map(), nullable => true}}
|
||||||
] ++ proplists:delete(base_url, connector_fields(http)).
|
] ++ proplists:delete(base_url, connector_fields(http)).
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,9 @@ is not allowed.
|
||||||
})}
|
})}
|
||||||
, {local_topic, mk(binary(),
|
, {local_topic, mk(binary(),
|
||||||
#{ desc =>"""
|
#{ desc =>"""
|
||||||
The MQTT topic filter to be forwarded to the HTTP server. All MQTT PUBLISH messages which topic
|
The MQTT topic filter to be forwarded to the HTTP server. All MQTT 'PUBLISH' messages with the topic
|
||||||
match the local_topic will be forwarded.<br>
|
matching the local_topic will be forwarded.<br/>
|
||||||
NOTE: if this bridge is used as the output of a rule (emqx rule engine), and also local_topic is configured, then both the data got from the rule and the MQTT messages that matches
|
NOTE: if this bridge is used as the output of a rule (EMQX rule engine), and also local_topic is configured, then both the data got from the rule and the MQTT messages that match
|
||||||
local_topic will be forwarded.
|
local_topic will be forwarded.
|
||||||
"""
|
"""
|
||||||
})}
|
})}
|
||||||
|
@ -89,7 +89,7 @@ basic_config() ->
|
||||||
})}
|
})}
|
||||||
, {direction,
|
, {direction,
|
||||||
mk(egress,
|
mk(egress,
|
||||||
#{ desc => "The direction of this bridge, MUST be egress"
|
#{ desc => "The direction of this bridge, MUST be 'egress'"
|
||||||
, default => egress
|
, default => egress
|
||||||
})}
|
})}
|
||||||
]
|
]
|
||||||
|
@ -97,7 +97,7 @@ basic_config() ->
|
||||||
|
|
||||||
%%======================================================================================
|
%%======================================================================================
|
||||||
id_field() ->
|
id_field() ->
|
||||||
{id, mk(binary(), #{desc => "The Bridge Id", example => "http:my_http_bridge"})}.
|
{id, mk(binary(), #{desc => "The Bridge ID", example => "http:my_http_bridge"})}.
|
||||||
|
|
||||||
type_field() ->
|
type_field() ->
|
||||||
{type, mk(http, #{desc => "The Bridge Type"})}.
|
{type, mk(http, #{desc => "The Bridge Type"})}.
|
||||||
|
|
|
@ -43,7 +43,7 @@ fields("get_egress") ->
|
||||||
|
|
||||||
%%======================================================================================
|
%%======================================================================================
|
||||||
id_field() ->
|
id_field() ->
|
||||||
{id, mk(binary(), #{desc => "The Bridge Id", example => "mqtt:my_mqtt_bridge"})}.
|
{id, mk(binary(), #{desc => "The bridge ID", example => "mqtt:my_mqtt_bridge"})}.
|
||||||
|
|
||||||
type_field() ->
|
type_field() ->
|
||||||
{type, mk(mqtt, #{desc => "The Bridge Type"})}.
|
{type, mk(mqtt, #{desc => "The bridge type"})}.
|
||||||
|
|
|
@ -55,7 +55,8 @@ common_bridge_fields() ->
|
||||||
#{ nullable => false
|
#{ nullable => false
|
||||||
, example => <<"mqtt:my_mqtt_connector">>
|
, example => <<"mqtt:my_mqtt_connector">>
|
||||||
, desc =>"""
|
, desc =>"""
|
||||||
The connector Id to be used for this bridge. Connector Ids must be of format: '{type}:{name}'.<br>
|
The connector ID to be used for this bridge. Connector IDs must be of format:
|
||||||
|
<code>{type}:{name}</code>.<br>
|
||||||
In config files, you can find the corresponding config entry for a connector by such path: 'connectors.{type}.{name}'.<br>
|
In config files, you can find the corresponding config entry for a connector by such path: 'connectors.{type}.{name}'.<br>
|
||||||
"""
|
"""
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -111,7 +111,7 @@ Environment variables can be used to define or override config values.
|
||||||
Due to the fact that dots (`.`) are not allowed in environment variables, dots are
|
Due to the fact that dots (`.`) are not allowed in environment variables, dots are
|
||||||
replaced with double-underscores (`__`).
|
replaced with double-underscores (`__`).
|
||||||
|
|
||||||
And a the `EMQX_` prefix is used as the namespace.
|
And the `EMQX_` prefix is used as the namespace.
|
||||||
|
|
||||||
For example `node.name` can be represented as `EMQX_NODE__NAME`
|
For example `node.name` can be represented as `EMQX_NODE__NAME`
|
||||||
|
|
||||||
|
|
|
@ -317,7 +317,7 @@ a crash dump
|
||||||
})}
|
})}
|
||||||
, {"etc_dir",
|
, {"etc_dir",
|
||||||
sc(string(),
|
sc(string(),
|
||||||
#{ desc => "`etc` dir for the node"
|
#{ desc => "<code>etc</code> dir for the node"
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
, {"cluster_call",
|
, {"cluster_call",
|
||||||
|
@ -915,9 +915,9 @@ emqx_schema_high_prio_roots() ->
|
||||||
Authz = {"authorization",
|
Authz = {"authorization",
|
||||||
sc(hoconsc:ref("authorization"),
|
sc(hoconsc:ref("authorization"),
|
||||||
#{ desc => """
|
#{ desc => """
|
||||||
Authorization a.k.a ACL.<br>
|
Authorization a.k.a. ACL.<br>
|
||||||
In EMQX, MQTT client access control is extremely flexible.<br>
|
In EMQX, MQTT client access control is extremely flexible.<br>
|
||||||
An out of the box set of authorization data sources are supported.
|
An out-of-the-box set of authorization data sources are supported.
|
||||||
For example,<br>
|
For example,<br>
|
||||||
'file' source is to support concise and yet generic ACL rules in a file;<br>
|
'file' source is to support concise and yet generic ACL rules in a file;<br>
|
||||||
'built-in-database' source can be used to store per-client customizable rule sets,
|
'built-in-database' source can be used to store per-client customizable rule sets,
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
-define(REDIS_DEFAULT_PORT, 6379).
|
-define(REDIS_DEFAULT_PORT, 6379).
|
||||||
-define(PGSQL_DEFAULT_PORT, 5432).
|
-define(PGSQL_DEFAULT_PORT, 5432).
|
||||||
|
|
||||||
-define(SERVERS_DESC, "A Node list for Cluster to connect to. The nodes should be splited with ',', such as: 'Node[,Node]'<br>\nFor each Node should be:<br>").
|
-define(SERVERS_DESC, "A Node list for Cluster to connect to. The nodes should be split with ',', such as: 'Node[,Node]'<br>\nFor each Node should be:<br>").
|
||||||
|
|
||||||
-define(SERVER_DESC(TYPE, DEFAULT_PORT), """
|
-define(SERVER_DESC(TYPE, DEFAULT_PORT), """
|
||||||
The IPv4 or IPv6 address or host name to connect to.<br>
|
The IPv4 or IPv6 address or host name to connect to.<br>
|
||||||
|
|
|
@ -44,7 +44,7 @@ fields("connector") ->
|
||||||
, desc => """
|
, desc => """
|
||||||
The mode of the MQTT Bridge. Can be one of 'cluster_singleton' or 'cluster_shareload'<br>
|
The mode of the MQTT Bridge. Can be one of 'cluster_singleton' or 'cluster_shareload'<br>
|
||||||
|
|
||||||
- cluster_singleton: create an unique MQTT connection within the emqx cluster.<br>
|
- cluster_singleton: create a unique MQTT connection within the emqx cluster.<br>
|
||||||
In 'cluster_singleton' node, all messages toward the remote broker go through the same
|
In 'cluster_singleton' node, all messages toward the remote broker go through the same
|
||||||
MQTT connection.<br>
|
MQTT connection.<br>
|
||||||
- cluster_shareload: create an MQTT connection on each node in the emqx cluster.<br>
|
- cluster_shareload: create an MQTT connection on each node in the emqx cluster.<br>
|
||||||
|
@ -65,7 +65,7 @@ topic filters for 'remote_topic' of ingress connections.
|
||||||
#{ default => "127.0.0.1:1883"
|
#{ default => "127.0.0.1:1883"
|
||||||
, desc => "The host and port of the remote MQTT broker"
|
, desc => "The host and port of the remote MQTT broker"
|
||||||
})}
|
})}
|
||||||
, {reconnect_interval, mk_duration("reconnect interval", #{default => "15s"})}
|
, {reconnect_interval, mk_duration("Reconnect interval", #{default => "15s"})}
|
||||||
, {proto_ver,
|
, {proto_ver,
|
||||||
sc(hoconsc:enum([v3, v4, v5]),
|
sc(hoconsc:enum([v3, v4, v5]),
|
||||||
#{ default => v4
|
#{ default => v4
|
||||||
|
@ -86,12 +86,12 @@ topic filters for 'remote_topic' of ingress connections.
|
||||||
#{ default => true
|
#{ default => true
|
||||||
, desc => "The clean-start or the clean-session of the MQTT protocol"
|
, desc => "The clean-start or the clean-session of the MQTT protocol"
|
||||||
})}
|
})}
|
||||||
, {keepalive, mk_duration("keepalive", #{default => "300s"})}
|
, {keepalive, mk_duration("Keepalive", #{default => "300s"})}
|
||||||
, {retry_interval, mk_duration("retry interval", #{default => "15s"})}
|
, {retry_interval, mk_duration("Retry interval", #{default => "15s"})}
|
||||||
, {max_inflight,
|
, {max_inflight,
|
||||||
sc(integer(),
|
sc(integer(),
|
||||||
#{ default => 32
|
#{ default => 32
|
||||||
, desc => "Max inflight messages (sent but ACK has not received) of the MQTT protocol"
|
, desc => "Max inflight (sent, but un-acked) messages of the MQTT protocol"
|
||||||
})}
|
})}
|
||||||
, {replayq,
|
, {replayq,
|
||||||
sc(ref("replayq"),
|
sc(ref("replayq"),
|
||||||
|
@ -180,7 +180,7 @@ A segment is mapping to a file in the replayq dir. If the current segment is ful
|
||||||
#{ default => false
|
#{ default => false
|
||||||
, desc => """
|
, desc => """
|
||||||
In offload mode, the disk queue is only used to offload queue tail segments.<br>
|
In offload mode, the disk queue is only used to offload queue tail segments.<br>
|
||||||
The messages are cached in the memory first, then it write to the replayq files after the size of
|
The messages are cached in the memory first, then it writes to the replayq files after the size of
|
||||||
the memory cache reaches 'seg_bytes'.
|
the memory cache reaches 'seg_bytes'.
|
||||||
"""
|
"""
|
||||||
})}
|
})}
|
||||||
|
@ -223,7 +223,7 @@ common_inout_confs() ->
|
||||||
sc(hoconsc:union([boolean(), binary()]),
|
sc(hoconsc:union([boolean(), binary()]),
|
||||||
#{ default => <<"${retain}">>
|
#{ default => <<"${retain}">>
|
||||||
, desc => """
|
, desc => """
|
||||||
The retain flag of the MQTT message to be sent.<br>
|
The 'retain' flag of the MQTT message to be sent.<br>
|
||||||
Template with variables is allowed."""
|
Template with variables is allowed."""
|
||||||
})}
|
})}
|
||||||
, {payload,
|
, {payload,
|
||||||
|
|
|
@ -643,7 +643,7 @@ fields(subscription) ->
|
||||||
fields(extra_sub_props) ->
|
fields(extra_sub_props) ->
|
||||||
[ {subid,
|
[ {subid,
|
||||||
mk(binary(),
|
mk(binary(),
|
||||||
#{ desc => <<"Only stomp protocol, an uniquely identity for "
|
#{ desc => <<"Only stomp protocol, a unique identity for "
|
||||||
"the subscription. range: 1-65535.">>})}
|
"the subscription. range: 1-65535.">>})}
|
||||||
].
|
].
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,7 @@ fields(mqttsn) ->
|
||||||
#{ default => 1
|
#{ default => 1
|
||||||
, nullable => false
|
, nullable => false
|
||||||
, desc =>
|
, desc =>
|
||||||
"MQTT-SN Gateway Id.<br>
|
"MQTT-SN Gateway ID.<br>
|
||||||
When the <code>broadcast</code> option is enabled,
|
When the <code>broadcast</code> option is enabled,
|
||||||
the gateway will broadcast ADVERTISE message with this value"
|
the gateway will broadcast ADVERTISE message with this value"
|
||||||
})}
|
})}
|
||||||
|
@ -140,22 +140,22 @@ the gateway will broadcast ADVERTISE message with this value"
|
||||||
This feature is defined for very simple client implementations
|
This feature is defined for very simple client implementations
|
||||||
which do not support any other features except this one.<br>
|
which do not support any other features except this one.<br>
|
||||||
There is no connection setup nor tear down, no registration nor subscription.<br>
|
There is no connection setup nor tear down, no registration nor subscription.<br>
|
||||||
The client just sends its PUBLISH messages to a GW"
|
The client just sends its 'PUBLISH' messages to a GW"
|
||||||
})}
|
})}
|
||||||
, {predefined,
|
, {predefined,
|
||||||
sc(hoconsc:array(ref(mqttsn_predefined)),
|
sc(hoconsc:array(ref(mqttsn_predefined)),
|
||||||
#{ default => []
|
#{ default => []
|
||||||
, nullable => {true, recursively}
|
, nullable => {true, recursively}
|
||||||
, desc =>
|
, desc =>
|
||||||
<<"The Pre-defined topic ids and topic names.<br>
|
<<"The pre-defined topic IDs and topic names.<br>
|
||||||
A 'pre-defined' topic id is a topic id whose mapping to a topic name
|
A 'pre-defined' topic ID is a topic ID whose mapping to a topic name
|
||||||
is known in advance by both the client’s application and the gateway">>
|
is known in advance by both the client's application and the gateway">>
|
||||||
})}
|
})}
|
||||||
, {listeners, sc(ref(udp_listeners))}
|
, {listeners, sc(ref(udp_listeners))}
|
||||||
] ++ gateway_common_options();
|
] ++ gateway_common_options();
|
||||||
|
|
||||||
fields(mqttsn_predefined) ->
|
fields(mqttsn_predefined) ->
|
||||||
[ {id, sc(integer(), #{desc => "Topic Id.<br>Range: 1-65535"})}
|
[ {id, sc(integer(), #{desc => "Topic ID.<br>Range: 1-65535"})}
|
||||||
, {topic, sc(binary(), #{desc => "Topic Name"})}
|
, {topic, sc(binary(), #{desc => "Topic Name"})}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -322,7 +322,7 @@ fields(lwm2m_translators) ->
|
||||||
#{ desc =>
|
#{ desc =>
|
||||||
"The topic for receiving downstream commands.<br>
|
"The topic for receiving downstream commands.<br>
|
||||||
For each new LwM2M client that succeeds in going online, the gateway creates
|
For each new LwM2M client that succeeds in going online, the gateway creates
|
||||||
a the subscription relationship to receive downstream commands and send it to
|
a subscription relationship to receive downstream commands and send it to
|
||||||
the LwM2M client"
|
the LwM2M client"
|
||||||
, nullable => false
|
, nullable => false
|
||||||
})}
|
})}
|
||||||
|
@ -425,7 +425,7 @@ authentication_schema() ->
|
||||||
sc(emqx_authn_schema:authenticator_type(),
|
sc(emqx_authn_schema:authenticator_type(),
|
||||||
#{ nullable => {true, recursively}
|
#{ nullable => {true, recursively}
|
||||||
, desc =>
|
, desc =>
|
||||||
"""Default authentication configs for all of the gateway listeners.<br>
|
"""Default authentication configs for all the gateway listeners.<br>
|
||||||
For per-listener overrides see <code>authentication</code>
|
For per-listener overrides see <code>authentication</code>
|
||||||
in listener configs"""
|
in listener configs"""
|
||||||
}).
|
}).
|
||||||
|
@ -446,7 +446,7 @@ gateway_common_options() ->
|
||||||
#{ default => <<"30s">>
|
#{ default => <<"30s">>
|
||||||
, desc =>
|
, desc =>
|
||||||
"The idle time of the client connection process.<br>
|
"The idle time of the client connection process.<br>
|
||||||
it has two purposes:
|
It has two purposes:
|
||||||
1. A newly created client process that does not receive any client requests
|
1. A newly created client process that does not receive any client requests
|
||||||
after that time will be closed directly.
|
after that time will be closed directly.
|
||||||
2. A running client process that does not receive any client requests after
|
2. A running client process that does not receive any client requests after
|
||||||
|
|
|
@ -80,10 +80,10 @@ install_dir(nullable) -> true;
|
||||||
install_dir(default) -> "plugins"; %% runner's root dir
|
install_dir(default) -> "plugins"; %% runner's root dir
|
||||||
install_dir(T) when T =/= desc -> undefined;
|
install_dir(T) when T =/= desc -> undefined;
|
||||||
install_dir(desc) -> """
|
install_dir(desc) -> """
|
||||||
In which directory are the external plugins installed.
|
The installation directory for the external plugins.
|
||||||
The plugin beam files and configuration files should reside in
|
The plugin beam files and configuration files should reside in
|
||||||
the sub-directory named as <code>emqx_foo_bar-0.1.0</code>.
|
the subdirectory named as <code>emqx_foo_bar-0.1.0</code>.
|
||||||
<br>
|
<br>
|
||||||
NOTE: For security reasons, this directory should **NOT** be writable
|
NOTE: For security reasons, this directory should **NOT** be writable
|
||||||
by anyone expect for <code>emqx</code> (or any user which runs EMQX)
|
by anyone except <code>emqx</code> (or any user which runs EMQX).
|
||||||
""".
|
""".
|
||||||
|
|
|
@ -58,14 +58,14 @@ init_file(desc) ->
|
||||||
<<"If init_file is specified, emqx will import PSKs from the file ",
|
<<"If init_file is specified, emqx will import PSKs from the file ",
|
||||||
"into the built-in database at startup for use by the runtime. ",
|
"into the built-in database at startup for use by the runtime. ",
|
||||||
"The file has to be structured line-by-line, each line must be in ",
|
"The file has to be structured line-by-line, each line must be in ",
|
||||||
"the format of 'PSKIdentity:SharedSecret' for example: ",
|
"the format of <code>PSKIdentity:SharedSecret</code>. For example: ",
|
||||||
"<code>mydevice1:c2VjcmV0</code>">>;
|
"<code>mydevice1:c2VjcmV0</code>">>;
|
||||||
init_file(nullable) -> true;
|
init_file(nullable) -> true;
|
||||||
init_file(_) -> undefined.
|
init_file(_) -> undefined.
|
||||||
|
|
||||||
separator(type) -> binary();
|
separator(type) -> binary();
|
||||||
separator(desc) ->
|
separator(desc) ->
|
||||||
<<"The separator between PSKIdentity and SharedSecret in the psk file">>;
|
<<"The separator between <code>PSKIdentity</code> and <code>SharedSecret</code> in the psk file">>;
|
||||||
separator(default) -> <<":">>;
|
separator(default) -> <<":">>;
|
||||||
separator(_) -> undefined.
|
separator(_) -> undefined.
|
||||||
|
|
||||||
|
|
|
@ -211,7 +211,7 @@ qos() ->
|
||||||
|
|
||||||
rule_id() ->
|
rule_id() ->
|
||||||
{"id", sc(binary(),
|
{"id", sc(binary(),
|
||||||
#{ desc => "The Id of the rule", nullable => false
|
#{ desc => "The ID of the rule", nullable => false
|
||||||
, example => "293fb66f"
|
, example => "293fb66f"
|
||||||
})}.
|
})}.
|
||||||
|
|
||||||
|
|
|
@ -52,12 +52,12 @@ Example: <code>SELECT * FROM \"test/topic\" WHERE payload.x = 1</code><br>
|
||||||
, {"outputs", sc(hoconsc:array(hoconsc:union(outputs())),
|
, {"outputs", sc(hoconsc:array(hoconsc:union(outputs())),
|
||||||
#{ desc => """
|
#{ desc => """
|
||||||
A list of outputs of the rule.<br>
|
A list of outputs of the rule.<br>
|
||||||
An output can be a string that refers to the channel Id of a emqx bridge, or a object
|
An output can be a string that refers to the channel ID of an EMQX bridge, or an object
|
||||||
that refers to a function.<br>
|
that refers to a function.<br>
|
||||||
There a some built-in functions like \"republish\" and \"console\", and we also support user
|
There a some built-in functions like \"republish\" and \"console\", and we also support user
|
||||||
provided functions in the format: \"{module}:{function}\".<br>
|
provided functions in the format: \"{module}:{function}\".<br>
|
||||||
The outputs in the list is executed one by one in order.
|
The outputs in the list are executed sequentially.
|
||||||
This means that if one of the output is executing slowly, all of the outputs comes after it will not
|
This means that if one of the output is executing slowly, all the following outputs will not
|
||||||
be executed until it returns.<br>
|
be executed until it returns.<br>
|
||||||
If one of the output crashed, all other outputs come after it will still be executed, in the
|
If one of the output crashed, all other outputs come after it will still be executed, in the
|
||||||
original order.<br>
|
original order.<br>
|
||||||
|
@ -149,7 +149,7 @@ Template with variables is allowed, see description of the 'republish_args'.
|
||||||
, {qos, sc(qos(),
|
, {qos, sc(qos(),
|
||||||
#{ desc => """
|
#{ desc => """
|
||||||
The qos of the message to be re-published.
|
The qos of the message to be re-published.
|
||||||
Template with with variables is allowed, see description of the 'republish_args.<br>
|
Template with variables is allowed, see description of the 'republish_args'.<br>
|
||||||
Defaults to ${qos}. If variable ${qos} is not found from the selected result of the rule,
|
Defaults to ${qos}. If variable ${qos} is not found from the selected result of the rule,
|
||||||
0 is used.
|
0 is used.
|
||||||
"""
|
"""
|
||||||
|
@ -158,8 +158,8 @@ Defaults to ${qos}. If variable ${qos} is not found from the selected result of
|
||||||
})}
|
})}
|
||||||
, {retain, sc(hoconsc:union([binary(), boolean()]),
|
, {retain, sc(hoconsc:union([binary(), boolean()]),
|
||||||
#{ desc => """
|
#{ desc => """
|
||||||
The retain flag of the message to be re-published.
|
The 'retain' flag of the message to be re-published.
|
||||||
Template with with variables is allowed, see description of the 'republish_args.<br>
|
Template with variables is allowed, see description of the 'republish_args'.<br>
|
||||||
Defaults to ${retain}. If variable ${retain} is not found from the selected result
|
Defaults to ${retain}. If variable ${retain} is not found from the selected result
|
||||||
of the rule, false is used.
|
of the rule, false is used.
|
||||||
"""
|
"""
|
||||||
|
@ -169,7 +169,7 @@ of the rule, false is used.
|
||||||
, {payload, sc(binary(),
|
, {payload, sc(binary(),
|
||||||
#{ desc => """
|
#{ desc => """
|
||||||
The payload of the message to be re-published.
|
The payload of the message to be re-published.
|
||||||
Template with with variables is allowed, see description of the 'republish_args.<br>.
|
Template with variables is allowed, see description of the 'republish_args'.<br>.
|
||||||
Defaults to ${payload}. If variable ${payload} is not found from the selected result
|
Defaults to ${payload}. If variable ${payload} is not found from the selected result
|
||||||
of the rule, then the string \"undefined\" is used.
|
of the rule, then the string \"undefined\" is used.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace() -> "slow_subs".
|
||||||
roots() -> ["slow_subs"].
|
roots() -> ["slow_subs"].
|
||||||
|
|
||||||
fields("slow_subs") ->
|
fields("slow_subs") ->
|
||||||
[ {enable, sc(boolean(), false, "switch of this function")}
|
[ {enable, sc(boolean(), false, "Enable this feature")}
|
||||||
, {threshold,
|
, {threshold,
|
||||||
sc(emqx_schema:duration_ms(),
|
sc(emqx_schema:duration_ms(),
|
||||||
"500ms",
|
"500ms",
|
||||||
|
|
|
@ -1,246 +0,0 @@
|
||||||
personal_ws-1.1 en 254
|
|
||||||
ACL
|
|
||||||
AES
|
|
||||||
APIs
|
|
||||||
BPAPI
|
|
||||||
BSON
|
|
||||||
Backplane
|
|
||||||
CHACHA
|
|
||||||
CLI
|
|
||||||
CMD
|
|
||||||
CN
|
|
||||||
CONNACK
|
|
||||||
CoAP
|
|
||||||
Cygwin
|
|
||||||
DES
|
|
||||||
DN
|
|
||||||
DNS
|
|
||||||
DTLS
|
|
||||||
DevOps
|
|
||||||
Dialyzer
|
|
||||||
Diffie
|
|
||||||
EIP
|
|
||||||
EMQ
|
|
||||||
EPMD
|
|
||||||
ERL
|
|
||||||
ETS
|
|
||||||
FIXME
|
|
||||||
GCM
|
|
||||||
Gw
|
|
||||||
HOCON
|
|
||||||
HTTPS
|
|
||||||
JSON
|
|
||||||
Kubernetes
|
|
||||||
LwM
|
|
||||||
MQTT
|
|
||||||
Makefile
|
|
||||||
MitM
|
|
||||||
Multicast
|
|
||||||
NIF
|
|
||||||
OTP
|
|
||||||
PEM
|
|
||||||
PINGREQ
|
|
||||||
PSK
|
|
||||||
PUBREL
|
|
||||||
QoS
|
|
||||||
RESTful
|
|
||||||
ROADMAP
|
|
||||||
RSA
|
|
||||||
Req
|
|
||||||
Riak
|
|
||||||
SHA
|
|
||||||
SMS
|
|
||||||
Struct
|
|
||||||
TCP
|
|
||||||
TLS
|
|
||||||
TTL
|
|
||||||
UDP
|
|
||||||
URI
|
|
||||||
XMLs
|
|
||||||
acceptors
|
|
||||||
ack
|
|
||||||
acked
|
|
||||||
addr
|
|
||||||
api
|
|
||||||
apiserver
|
|
||||||
arg
|
|
||||||
args
|
|
||||||
async
|
|
||||||
attr
|
|
||||||
auth
|
|
||||||
authenticator
|
|
||||||
authenticators
|
|
||||||
authn
|
|
||||||
authz
|
|
||||||
autoclean
|
|
||||||
autoheal
|
|
||||||
backend
|
|
||||||
backends
|
|
||||||
backoff
|
|
||||||
backplane
|
|
||||||
backtrace
|
|
||||||
badarg
|
|
||||||
badkey
|
|
||||||
bcrypt
|
|
||||||
behaviour
|
|
||||||
bhvr
|
|
||||||
boolean
|
|
||||||
bytesize
|
|
||||||
cacert
|
|
||||||
cacertfile
|
|
||||||
certfile
|
|
||||||
ci
|
|
||||||
clientid
|
|
||||||
clientinfo
|
|
||||||
cmake
|
|
||||||
coap
|
|
||||||
conf
|
|
||||||
config
|
|
||||||
configs
|
|
||||||
confirmable
|
|
||||||
conn
|
|
||||||
connectionless
|
|
||||||
cors
|
|
||||||
cpu
|
|
||||||
ctx
|
|
||||||
customizable
|
|
||||||
desc
|
|
||||||
dir
|
|
||||||
dns
|
|
||||||
downlink
|
|
||||||
downlink
|
|
||||||
dtls
|
|
||||||
ekka
|
|
||||||
emqx
|
|
||||||
enablement
|
|
||||||
enqueue
|
|
||||||
enqueued
|
|
||||||
env
|
|
||||||
eof
|
|
||||||
epmd
|
|
||||||
erl
|
|
||||||
erts
|
|
||||||
escript
|
|
||||||
etcd
|
|
||||||
eval
|
|
||||||
exe
|
|
||||||
executables
|
|
||||||
exhook
|
|
||||||
exproto
|
|
||||||
extensibility
|
|
||||||
formatter
|
|
||||||
gRPC
|
|
||||||
github
|
|
||||||
goto
|
|
||||||
grpcbox
|
|
||||||
hocon
|
|
||||||
hoconsc
|
|
||||||
hostname
|
|
||||||
hrl
|
|
||||||
http
|
|
||||||
https
|
|
||||||
iface
|
|
||||||
img
|
|
||||||
impl
|
|
||||||
inet
|
|
||||||
inflight
|
|
||||||
ini
|
|
||||||
init
|
|
||||||
ip
|
|
||||||
ipv
|
|
||||||
jenkins
|
|
||||||
jq
|
|
||||||
kb
|
|
||||||
keepalive
|
|
||||||
libcoap
|
|
||||||
lifecycle
|
|
||||||
localhost
|
|
||||||
lwm
|
|
||||||
mnesia
|
|
||||||
mountpoint
|
|
||||||
mqueue
|
|
||||||
mria
|
|
||||||
msg
|
|
||||||
multicalls
|
|
||||||
multicasts
|
|
||||||
namespace
|
|
||||||
natively
|
|
||||||
nodelay
|
|
||||||
nodetool
|
|
||||||
nullable
|
|
||||||
num
|
|
||||||
os
|
|
||||||
params
|
|
||||||
peerhost
|
|
||||||
peername
|
|
||||||
perf
|
|
||||||
powershell
|
|
||||||
procmem
|
|
||||||
procs
|
|
||||||
progname
|
|
||||||
prometheus
|
|
||||||
proto
|
|
||||||
ps
|
|
||||||
psk
|
|
||||||
pubsub
|
|
||||||
qlen
|
|
||||||
qmode
|
|
||||||
qos
|
|
||||||
quic
|
|
||||||
ratelimit
|
|
||||||
rebar
|
|
||||||
recbuf
|
|
||||||
relup
|
|
||||||
replayq
|
|
||||||
replicant
|
|
||||||
repo
|
|
||||||
reuseaddr
|
|
||||||
rh
|
|
||||||
rlog
|
|
||||||
rootdir
|
|
||||||
rpc
|
|
||||||
runtime
|
|
||||||
sc
|
|
||||||
scalable
|
|
||||||
seg
|
|
||||||
setcookie
|
|
||||||
sharded
|
|
||||||
shareload
|
|
||||||
sn
|
|
||||||
sndbuf
|
|
||||||
sockname
|
|
||||||
sql
|
|
||||||
src
|
|
||||||
ssl
|
|
||||||
statsd
|
|
||||||
structs
|
|
||||||
subprotocol
|
|
||||||
subprotocols
|
|
||||||
superset
|
|
||||||
sys
|
|
||||||
sysmem
|
|
||||||
sysmon
|
|
||||||
tcp
|
|
||||||
ticktime
|
|
||||||
tlog
|
|
||||||
tls
|
|
||||||
tlsv
|
|
||||||
travis
|
|
||||||
trie
|
|
||||||
ttl
|
|
||||||
typerefl
|
|
||||||
udp
|
|
||||||
uid
|
|
||||||
unsub
|
|
||||||
uplink
|
|
||||||
url
|
|
||||||
utc
|
|
||||||
util
|
|
||||||
ver
|
|
||||||
vm
|
|
||||||
vsn
|
|
||||||
wakaama
|
|
||||||
websocket
|
|
||||||
ws
|
|
||||||
wss
|
|
||||||
xml
|
|
|
@ -1,72 +1,21 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# shellcheck disable=SC2015
|
set -uo pipefail
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
aspell -v > /dev/null && [ "$#" -eq 1 ] || {
|
if [ -z "${1:-}" ]; then
|
||||||
echo "Usage:
|
SCHEMA="_build/emqx/lib/emqx_dashboard/priv/www/static/schema.json"
|
||||||
$(basename "$0") check
|
else
|
||||||
or
|
SCHEMA="$1"
|
||||||
$(basename "$0") fix
|
|
||||||
|
|
||||||
Note: this script needs aspell to run"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
action=$1
|
|
||||||
|
|
||||||
dict_dir="$(git rev-parse --show-toplevel)/$(dirname "$0")/dict"
|
|
||||||
echo "${dict_dir}"
|
|
||||||
dict="${dict_dir}/.aspell.en"
|
|
||||||
|
|
||||||
export fail=0
|
|
||||||
|
|
||||||
aspellcmd() {
|
|
||||||
local mode
|
|
||||||
mode="${1}"
|
|
||||||
shift
|
|
||||||
aspell --mode "${mode}" --camel-case --add-filter html --add-html-skip code -p "$dict" "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
check() {
|
|
||||||
local mode file typos ntypos
|
|
||||||
mode="$1"
|
|
||||||
file="$2"
|
|
||||||
|
|
||||||
echo "!! Spellchecking ${file}"
|
|
||||||
typos="$(mktemp)"
|
|
||||||
echo "!! Typos:"
|
|
||||||
aspellcmd "$mode" list < "$file" |
|
|
||||||
sort -u |
|
|
||||||
tee "$typos"
|
|
||||||
ntypos="$(wc -l "$typos")"
|
|
||||||
rm "$typos"
|
|
||||||
[ "$ntypos" = 0 ] || export fail=1
|
|
||||||
}
|
|
||||||
|
|
||||||
fix() {
|
|
||||||
local mode file
|
|
||||||
mode=$1
|
|
||||||
file=$2
|
|
||||||
|
|
||||||
aspellcmd "$mode" check "$file"
|
|
||||||
}
|
|
||||||
|
|
||||||
case $action in
|
|
||||||
fix)
|
|
||||||
for i in $(git ls-tree -r --name-only HEAD | grep -E '_schema.erl$'); do
|
|
||||||
fix perl "$i"
|
|
||||||
done
|
|
||||||
# for i in $(git ls-tree -r --name-only HEAD | grep -E '.md$'); do
|
|
||||||
# fix markdown $i
|
|
||||||
# done
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
check markdown _build/emqx/lib/emqx_dashboard/priv/www/static/config.md
|
|
||||||
esac
|
|
||||||
|
|
||||||
|
|
||||||
if [ $fail -eq 1 ]; then
|
|
||||||
echo
|
|
||||||
echo "!! Bad spelling in the documentation. Run script in fix mode to resolve problems."
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
docker run -d --name langtool "ghcr.io/k32/emqx-schema-validate:0.1.0"
|
||||||
|
|
||||||
|
docker exec -i langtool ./emqx_schema_validate - < "${SCHEMA}"
|
||||||
|
success="$?"
|
||||||
|
|
||||||
|
docker kill langtool || true
|
||||||
|
docker rm langtool || true
|
||||||
|
|
||||||
|
echo "If this script finds a false positive (e.g. when it things that a protocol name is a typo),
|
||||||
|
make a PR here: https://github.com/k32/emqx-schema-validate/blob/master/dict/en_spelling_additions.txt"
|
||||||
|
|
||||||
|
exit "$success"
|
||||||
|
|
Loading…
Reference in New Issue