diff --git a/docs/assets/images/favicon.png b/docs/assets/images/favicon.png new file mode 100644 index 0000000..4355171 Binary files /dev/null and b/docs/assets/images/favicon.png differ diff --git a/docs/references/amqtt_pub.md b/docs/references/amqtt_pub.md index 1b84a20..65ab22d 100644 --- a/docs/references/amqtt_pub.md +++ b/docs/references/amqtt_pub.md @@ -44,7 +44,7 @@ Note that for simplicity, `amqtt_pub` uses mostly the same argument syntax as [m - `--will-retain` - If given, if the client disconnects unexpectedly the message sent out will be treated as a retained message. This must be used in conjunction with `--will-topic`. - `--extra-headers` - Specify a JSON object string with key-value pairs representing additional headers that are transmitted on the initial connection, but only when using a websocket connection -## Configuration +## Default Configuration Without the `-c` argument, the broker will run with the following, default configuration: @@ -57,8 +57,6 @@ Using the `-c` argument allows for configuration with a YAML structured file; se ## Examples -Examples below are adapted from [mosquitto_pub](http://mosquitto.org/man/mosquitto_pub-1.html) documentation. - Publish temperature information to localhost with QoS 1: ```bash diff --git a/docs/references/amqtt_sub.md b/docs/references/amqtt_sub.md index 9d5335d..37e1125 100644 --- a/docs/references/amqtt_sub.md +++ b/docs/references/amqtt_sub.md @@ -39,22 +39,19 @@ Note that for simplicity, `amqtt_sub` uses mostly the same argument syntax as [m - `--will-retain` - If given, if the client disconnects unexpectedly the message sent out will be treated as a retained message. This must be used in conjunction with `--will-topic`. - `--extra-headers` - Specify a JSON object string with key-value pairs representing additional headers that are transmitted on the initial connection, but only when using a websocket connection -## Configuration +## Default Configuration -If `-c` argument is given, `amqtt_sub` will read specific MQTT settings for the given configuration file. This file must be a valid [YAML](http://yaml.org/) file which may contain the following configuration elements: +Without the `-c` argument, the broker will run with the following, default configuration: + +```yaml +--8<-- "../amqtt/amqtt/scripts/default_client.yaml" +``` + +Using the `-c` argument allows for configuration with a YAML structured file; see [client configuration](client_config.md). -- `keep_alive`: Keep-alive timeout sent to the broker. Defaults to `10` seconds. -- `ping_delay`: Auto-ping delay before keep-alive timeout. Defaults to 1. Setting to `0` will disable to 0 and may lead to broker disconnection. -- `default_qos`: Default QoS for messages published. Defaults to 0. -- `default_retain`: Default retain value to messages published. Defaults to `false`. -- `auto_reconnect`: Enable or disable auto-reconnect if connection with the broker is interrupted. Defaults to `false`. -- `reconnect_retries`: Maximum reconnection retries. Defaults to `2`. Negative value will cause client to reconnect infinitely. -- `reconnect_max_interval`: Maximum interval between 2 connection retry. Defaults to `10`. ## Examples -Examples below are adapted from [mosquitto_sub](http://mosquitto.org/man/mosquitto_sub-1.html) documentation. - Subscribe with QoS 0 to all messages published under $SYS/: ```bash diff --git a/docs/references/broker_config.md b/docs/references/broker_config.md new file mode 100644 index 0000000..157679d --- /dev/null +++ b/docs/references/broker_config.md @@ -0,0 +1,124 @@ +# Broker Configuration + +This configuration structure is valid as a python dictionary passed to the `amqtt.broker.Broker` class's `__init__` method or +as a yaml formatted file passed to the `amqtt` script. + +### `listeners` *(list[mapping])* + +Defines the network listeners used by the service. Items defined in the `default` listener will be +applied to all other listeners, unless they are overridden by the configuration for the specific +listener. + +- `default` | ``: Named listener + - `type` *(string)*: Transport type. Can be `tcp` or `ws`. + - `bind` *(string)*: IP address and port (e.g., `0.0.0.0:1883`) + - `max-connections` *(integer)*: Maximum number of clients that can connect to this interface + - `ssl` *(string)*: Enable SSL connection. Can be `on` or `off` (default: off). + - `cafile` *(string)*: Path to a file of concatenated CA certificates in PEM format. See [Certificates](https://docs.python.org/3/library/ssl.html#ssl-certificates) for more info. + - `capath` *(string)*: Path to a directory containing several CA certificates in PEM format, following an [OpenSSL specific layout](https://docs.openssl.org/master/man3/SSL_CTX_load_verify_locations/). + - `cadata` *(string)*: Either an ASCII string of one or more PEM-encoded certificates or a bytes-like object of DER-encoded certificates. + - `certfile` *(string)*: Path to a single file in PEM format containing the certificate as well as any number of CA certificates needed to establish the certificate's authenticity. + - `keyfile` *(string): A file containing the private key. Otherwise the private key will be taken from `certfile` as well. + +### `sys_interval` *(int)* + +System status report interval in seconds (`broker_sys` plugin) + +### `timeout-disconnect-delay` *(int)* + +Client disconnect timeout without a keep-alive + + +### `auth` *(mapping)* + +Configuration for authentication behaviour: + +- `plugins` *(list[string])*: defines the list of plugins which are activated as authentication plugins. Note the plugins must be defined in the `amqtt.broker.plugins` [entry point](https://packaging.python.org/en/latest/guides/creating-and-discovering-plugins/#using-package-metadata). +- `allow-anonymous` *(bool)*: used by the internal `amqtt.plugins.authentication.AnonymousAuthPlugin` plugin. This parameter enables (`on`) or disable anonymous connection, i.e. connection without username. +- `password-file` *(string)*: used by the internal `amqtt.plugins.authentication.FileAuthPlugin` plugin. Path to file which includes `username:password` pair, one per line. The password should be encoded using sha-512 with `mkpasswd -m sha-512` or: + ```python + import sys + from getpass import getpass + from passlib.hash import sha512_crypt + + passwd = input() if not sys.stdin.isatty() else getpass() + print(sha512_crypt.hash(passwd)) + ``` + +### `topic-check` *(mapping)* + +Configuration for access control policies for publishing and subscribing to topics: + +- `enabled` *(bool)*: Enable access control policies (`true`). `false` will allow clients to publish and subscribe to any topic. +- `plugins` *(list[string])*: defines the list of plugins which are activated as access control plugins. Note the plugins must be defined in the `amqtt.broker.plugins` [entry point](https://pythonhosted.org/setuptools/setuptools.html#dynamic-discovery-of-services-and-plugins). +- `acl` *(list)*: used by the internal `amqtt.plugins.topic_acl.TopicAclPlugin` plugin to determine subscription access. This parameter defines the list of access control rules; each item is a key-value pair, where: +`:[, , ...]` *(string, list[string])*: username of the client followed by a list of allowed topics (wildcards are supported: `#`, `+`). +use `anonymous` username for the list of allowed topics if using the `auth_anonymous` plugin. +- `publish-acl` *(list)*: used by the internal `amqtt.plugins.topic_acl.TopicAclPlugin` plugin to determine publish access. This parameter defines the list of access control rules; each item is a key-value pair, where: +`:[, , ...]` *(string, list[string])*: username of the client followed by a list of allowed topics (wildcards are supported: `#`, `+`). +use `anonymous` username for the list of allowed topics if using the `auth_anonymous` plugin. + + + +## Default Configuration + +```yaml +--8<-- "../amqtt/amqtt/scripts/default_broker.yaml" +``` + +## Example + +```yaml +listeners: + default: + max-connections: 500 + type: tcp + my-tcp-1: + bind: 127.0.0.1:1883 + my-tcp-2: + bind: 1.2.3.4:1884 + max-connections: 1000 + my-tcp-ssl-1: + bind: 127.0.0.1:8885 + ssl: on + cafile: /some/cafile + capath: /some/folder + capath: certificate data + certfile: /some/certfile + keyfile: /some/key + my-ws-1: + bind: 0.0.0.0:8080 + type: ws + my-wss-1: + bind: 0.0.0.0:9003 + type: ws + ssl: on + certfile: /some/certfile + keyfile: /some/key +timeout-disconnect-delay: 2 +auth: + plugins: ['auth_anonymous', 'auth_file'] + allow-anonymous: true + password-file: /some/password-file +topic-check: + enabled: true + plugins: ['topic_acl'] + acl: + username1: ['repositories/+/master', 'calendar/#', 'data/memes'] + username2: [ 'calendar/2025/#', 'data/memes'] + anonymous: ['calendar/2025/#'] +``` + +This configuration file would create the following listeners: + +- `my-tcp-1`: an unsecured TCP listener on port 1883 allowing `500` clients connections simultaneously +- `my-tcp-2`: an unsecured TCP listener on port 1884 allowing `1000` client connections +- `my-tcp-ssl-1`: a secured TCP listener on port 8883 allowing `500` clients connections simultaneously +- `my-ws-1`: an unsecured websocket listener on port 9001 allowing `500` clients connections simultaneously +- `my-wss-1`: a secured websocket listener on port 9003 allowing `500` + +And enable the following access controls: + +- `username1` to login and subscribe/publish to topics `repositories/+/master`, `calendar/#` and `data/memes` +- `username2` to login and subscribe/publish to topics `calendar/2025/#` and `data/memes` +- any user not providing credentials (`anonymous`) can only subscribe/publish to `calendar/2025/#` diff --git a/docs/references/client.md b/docs/references/client.md index 923e899..74cc887 100644 --- a/docs/references/client.md +++ b/docs/references/client.md @@ -136,14 +136,8 @@ The `MQTTClient` class's `__init__` method accepts a `config` parameter which al Details on the `config` parameter structure is a dictionary whose structure is identical to yaml formatted file[^1] used by the included broker script: [client configuration](client_config.md) - - -::: amqtt.broker.Broker +::: amqtt.client.MQTTClient [^1]: See [PyYAML](http://pyyaml.org/wiki/PyYAMLDocumentation) for loading YAML files as Python dict. - - - -::: amqtt.client.MQTTClient diff --git a/docs/references/client_config.md b/docs/references/client_config.md new file mode 100644 index 0000000..3616b1c --- /dev/null +++ b/docs/references/client_config.md @@ -0,0 +1,68 @@ +# Client Configuration + +This configuration structure is valid as a python dictionary passed to the `amqtt.broker.MQTTClient` class's `__init__` method or +as a yaml formatted file passed to the `amqtt_pub` script. + +### `keep_alive` *(int)* + +Keep-alive timeout sent to the broker. Defaults to `10` seconds. + +### `ping_delay` *(int)* + +Auto-ping delay before keep-alive timeout. Defaults to 1. Setting to `0` will disable to 0 and may lead to broker disconnection. + +### `default_qos` *(int: 0-2)* + +Default QoS for messages published. Defaults to 0. + + +### `default_retain` *(bool)* + +Default retain value to messages published. Defaults to `false`. + + +### `auto_reconnect` *(bool)* + +Enable or disable auto-reconnect if connection with the broker is interrupted. Defaults to `false`. + +### `reconnect_retries` *(int)* + +Maximum reconnection retries. Defaults to `2`. Negative value will cause client to reconnect infinitely. + +### `reconnect_max_interval` *(int)* + +Maximum interval between 2 connection retry. Defaults to `10`. + +### `topics` *(list[mapping])* + +Specify the topics and what flags should be set for messages published to them. + +- ``: Named listener + - `qos` *(int, 0-3)*: + - `retain` *(bool)*: + + +## Default Configuration + +```yaml +--8<-- "../amqtt/amqtt/scripts/default_client.yaml" +``` + +## Example + +```yaml + +keep_alive: 10 +ping_delay: 1 +default_qos': 0 +default_retain: false +auto_reconnect: true +reconnect_max_interval: 5, +reconnect_retries: 10 +topics: + - test: + qos: 0 + - some_topic: + qos: 2 + retain: true +``` diff --git a/samples/broker_simple.py b/samples/broker_simple.py new file mode 100644 index 0000000..22c4639 --- /dev/null +++ b/samples/broker_simple.py @@ -0,0 +1,21 @@ +import asyncio +import logging + +from amqtt.broker import Broker + +broker = Broker() + + +async def test_coro() -> None: + await broker.start() + + +if __name__ == "__main__": + formatter = "[%(asctime)s] :: %(levelname)s :: %(name)s :: %(message)s" + logging.basicConfig(level=logging.INFO, format=formatter) + + asyncio.get_event_loop().run_until_complete(test_coro()) + try: + asyncio.get_event_loop().run_forever() + except KeyboardInterrupt: + asyncio.get_event_loop().run_until_complete(broker.shutdown())