From 319d02498128106d7547361313c0f3e92e45761d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korina=20=C5=A0imi=C4=8Devi=C4=87?= Date: Fri, 29 Nov 2024 09:53:34 +0100 Subject: [PATCH] Document LoggerType concept and improve Getting Started chapter Summary: related to T15252, T15261, T15263, #24 - documented LoggerType concept - configuring the client chapter changed to getting started chapter with new additions: - code examples for each section (choosing underlying type, configuring the client, and using it) - added a secion on debugging the client using our logger implementation - minor fixes related to reviewer's suggestions Reviewers: ivica Reviewed By: ivica Subscribers: iljazovic, miljen Differential Revision: https://repo.mireo.local/D32487 --- doc/qbk/00_main.qbk | 20 ++++- ..._the_client.qbk => 02_getting_started.qbk} | 72 +++++++++++---- doc/qbk/03_auto_reconnect.qbk | 14 +-- .../04_maintaining_a_stable_connection.qbk | 6 +- doc/qbk/05_optimising_communication.qbk | 8 +- doc/qbk/06_disconnecting_the_client.qbk | 5 +- doc/qbk/07_asio_compliance.qbk | 2 +- doc/qbk/11_multithreading.qbk | 8 +- doc/qbk/{15_examples.qbk => 12_examples.qbk} | 0 doc/qbk/examples/Examples.qbk | 11 --- doc/qbk/reference/concepts/LoggerType.qbk | 87 +++++++++++++++++++ doc/qbk/reference/quickref.xml | 8 +- doc/reference.xsl | 18 ++-- example/hello_world_over_tcp.cpp | 15 +++- include/async_mqtt5/logger.hpp | 4 +- include/async_mqtt5/mqtt_client.hpp | 19 ++-- include/async_mqtt5/types.hpp | 9 +- test/unit/logger.cpp | 4 +- 18 files changed, 235 insertions(+), 75 deletions(-) rename doc/qbk/{02_configuring_the_client.qbk => 02_getting_started.qbk} (64%) rename doc/qbk/{15_examples.qbk => 12_examples.qbk} (100%) create mode 100644 doc/qbk/reference/concepts/LoggerType.qbk diff --git a/doc/qbk/00_main.qbk b/doc/qbk/00_main.qbk index be2d1ed..4267dc5 100644 --- a/doc/qbk/00_main.qbk +++ b/doc/qbk/00_main.qbk @@ -37,6 +37,7 @@ [template mqttlink[id text][@https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc[id] [text]]] [def __OPENSSL__ [@https://www.openssl.org/ OpenSSL]] +[def __HIVEMQ__ [@https://www.hivemq.com/ HiveMQ]] [def __CompletionToken__ [@boost:/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.completion_tokens_and_handlers CompletionToken]] [def __Executor__ [@boost:/doc/html/boost_asio/reference/Executor1.html Executor]] @@ -44,6 +45,7 @@ [def __StreamType__ [reflink StreamType]] [def __TlsContext__ [reflink TlsContext]] [def __is_authenticator__ [reflink is_authenticator]] +[def __LoggerType__ [reflink LoggerType]] [def __Boost__ [@https://www.boost.org/ Boost]] [def __Asio__ [@boost:/libs/asio/index.html Boost.Asio]] @@ -58,6 +60,7 @@ [def __STRAND__ [@boost:doc/html/boost_asio/reference/io_context__strand.html `boost::asio::io_context::strand`]] [def __DISPATCH__ [@boost:doc/html/boost_asio/reference/dispatch.html `boost::asio::dispatch`]] [def __POST__ [@boost:doc/html/boost_asio/reference/post.html `boost::asio::post`]] +[def __ASYNC_IMMEDIATE__ [@https://www.boost.org/doc/libs/1_86_0/doc/html/boost_asio/reference/async_immediate.html `boost::asio::async_immediate`]] [def __CO_SPAWN__ [@boost:/doc/html/boost_asio/reference/co_spawn.html `boost::asio::co_spawn`]] [def __USE_AWAITABLE__ [@boost:/doc/html/boost_asio/reference/use_awaitable.html `boost::asio::use_awaitable`]] [def __USE_FUTURE__ [@boost:/doc/html/boost_asio/reference/use_future.html `boost::asio::use_future`]] @@ -125,16 +128,27 @@ [def __REASON_CODES__ [reflink2 Reason_codes `Reason Codes`]] [def __ERROR_HANDLING__ [reflink2 Error_handling `Error handling`]] +[import ../../example/hello_world_over_tcp.cpp] +[import ../../example/hello_world_over_tls.cpp] +[import ../../example/hello_world_over_websocket_tcp.cpp] +[import ../../example/hello_world_over_websocket_tls.cpp] +[import ../../example/publisher.cpp] +[import ../../example/receiver.cpp] +[import ../../example/multiflight_client.cpp] +[import ../../example/timeout_with_parallel_group.cpp] +[import ../../example/timeout_with_awaitable_operators.cpp] +[import ../../example/hello_world_in_multithreaded_env.cpp] +[import ../../example/hello_world_in_coro_multithreaded_env.cpp] + [include 01_intro.qbk] -[include 02_configuring_the_client.qbk] +[include 02_getting_started.qbk] [include 03_auto_reconnect.qbk] [include 04_maintaining_a_stable_connection.qbk] [include 05_optimising_communication.qbk] [include 06_disconnecting_the_client.qbk] [include 07_asio_compliance.qbk] [include 11_multithreading.qbk] - -[include 15_examples.qbk] +[include 12_examples.qbk] [include examples/Examples.qbk] diff --git a/doc/qbk/02_configuring_the_client.qbk b/doc/qbk/02_getting_started.qbk similarity index 64% rename from doc/qbk/02_configuring_the_client.qbk rename to doc/qbk/02_getting_started.qbk index 95a7a7d..529113c 100644 --- a/doc/qbk/02_configuring_the_client.qbk +++ b/doc/qbk/02_getting_started.qbk @@ -4,7 +4,7 @@ (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:configuring_the_client Configuring the Client] +[section:getting_started Getting Started] [nochunk] This section guides you through the steps to properly configure the __Client__ to establish a connection with your chosen MQTT Broker. @@ -14,7 +14,7 @@ Instead, it features a function that will start the Client (see [refmem mqtt_cli All configuration of the __Client__ must be finalised before invoking [refmem mqtt_client async_run]. Upon calling this function, the __Client__ makes its initial attempt to connect. -[section:transport_protocol Choosing a suitable transport protocol] +[section:transport_protocol Choosing a Suitable Transport Protocol] The initial step is selecting an appropriate transport protocol for your MQTT connection. @@ -25,23 +25,19 @@ and WebSocket over TCP/IP and TLS/SSL. MQTT Brokers come in various implementations and support different transport protocols. Therefore, it is important to familiarise yourself with the protocols your chosen Broker supports. -Additionally, gather any necessary details such as certificate authority, client certificate, or private keys, +Additionally, gather any necessary details, such as certificate authority, client certificate, or private keys, which might be required for establishing a secure connection. -The upcoming examples will demonstrate the configuration and the publishing of a "Hello World!" application message at `QoS` 0, -using various transport protocols: +In this example, we choose TCP/IP as the underlying protocol to initialize the __Client__. -* [link async_mqtt5.hello_world_over_tcp hello_world_over_tcp.cpp] -* [link async_mqtt5.hello_world_over_tls hello_world_over_tls.cpp] -* [link async_mqtt5.hello_world_over_websocket_tcp hello_world_over_websocket_tcp.cpp] -* [link async_mqtt5.hello_world_over_websocket_tls hello_world_over_websocket_tls.cpp] +[init_tcp_client] [endsect] [/transport_protocol] -[section:customisation Customising your MQTT connection] +[section:configuration Configuring Your MQTT Connection] -The __Client__ offers a variety of functions for customising your MQTT connection settings. - These functionalities include: +The __Client__ offers a variety of functions for configuring your MQTT connection settings. +These functionalities include: * *Specifying a list of Brokers:* You *must* use this function to assign a list of Brokers that the __Client__ will try to connect to (see [refmem mqtt_client brokers]). The __Client__ allows for the specification of multiple Brokers for the connections. @@ -52,13 +48,22 @@ Listing Brokers from different clusters may lead to inconsistencies between MQTT * *Assign a custom user-implemented authenticator:* The custom authentication will be used for __ENHANCED_AUTH__ ([refmem mqtt_client authenticator]). * *Defining CONNECT Packet Properties:* Specify properties that will be included in the __CONNECT__ packet sent during connection initiation (see [refmem mqtt_client connect_property] and [refmem mqtt_client connect_properties]). +We will connect to the __HIVEMQ__'s public Broker at `broker.hivemq.com`, which listens for MQTT connections on the default TCP/IP port 1883. +Additionally, we will set the Client Identifier to `async_mqtt5_tester` using the [refmem mqtt_client credentials] function. +This is not strictly mandatory, as some Brokers allow anonymous connections. + +After configuring the `mqtt_client`, we call the [refmem mqtt_client async_run] function. +This starts the process of establishing a connection with the Broker. + +[configure_tcp_client] + It is important to note that these configurations apply to every Broker listed in [refmem mqtt_client brokers]. To modify any configuration parameters, you must first stop the __Client__ using [refmem mqtt_client cancel] or [refmem mqtt_client async_disconnect]. Afterwards, you can re-apply the configurations and restart the __Client__ with [refmem mqtt_client async_run]. -[endsect] [/customisation] +[endsect] [/configuration] -[section:establishing_a_connection Establishing a connection] +[section:establishing_a_connection Establishing a Connection] The __Client__ initiates a connection with the first Broker from the list of Brokers assigned using [refmem mqtt_client brokers]. A single attempt at connecting involves several steps: @@ -87,4 +92,41 @@ and `jitter` is a randomly chosen value between `-500ms` to `500ms`, intended to [endsect] [/establishing_a_connection] -[endsect] [/configuring_the_client] +[section:using_the_client Using the Client] + +After calling [refmem mqtt_client async_run], you can now use the Client according to your application needs. +In this case, we will publish a "Hello World!" message to `async-mqtt5/test` topic with Quality of Service 0 (at most once) using the [refmem mqtt_client async_publish] function. + +[publish_hello_world] + +You can find the full program listing for this chapter at the link below: + +* [link async_mqtt5.hello_world_over_tcp hello_world_over_tcp.cpp] + +Additional "Hello World!" examples for different underlying transport protocols can be found here: + +* [link async_mqtt5.hello_world_over_tls hello_world_over_tls.cpp] +* [link async_mqtt5.hello_world_over_websocket_tcp hello_world_over_websocket_tcp.cpp] +* [link async_mqtt5.hello_world_over_websocket_tls hello_world_over_websocket_tls.cpp] + +[endsect] [/using_the_client] + +[section:debugging Debugging the Client] + +If you encounter configuration or connection issues, you can use our logging mechanism to debug problems. +The __Client__ introduces a __LoggerType__ as its third template parameter, which specifies the type used for logging events within the __Client__. + +The __Self__ library provides a built-in [ghreflink include/async_mqtt5/logger.hpp logger] implementation that outputs operation results to stderr. +This logger outputs detailed information about each step in the connection process, including DNS resolution, TCP connection, TLS handshake, WebSocket handshake, and MQTT handshake. +To enable this functionality, construct the __Client__ with an instance of this logger class: + +[!c++] + // Since we are not establishing a secure connection, set the TlsContext template parameter to std::monostate. + async_mqtt5::mqtt_client client( + ioc, {} /* tls_context */, async_mqtt5::logger(async_mqtt5::log_level::debug) + ); + + +[endsect] [/debugging] + +[endsect] [/getting_started] diff --git a/doc/qbk/03_auto_reconnect.qbk b/doc/qbk/03_auto_reconnect.qbk index c66ea9f..c114f49 100644 --- a/doc/qbk/03_auto_reconnect.qbk +++ b/doc/qbk/03_auto_reconnect.qbk @@ -4,7 +4,7 @@ (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:auto_reconnect Built-in auto-reconnect and retry mechanism] +[section:auto_reconnect Built-in Auto-Reconnect and Retry Mechanism] [nochunk] The auto-reconnect and retry mechanism is a key feature of the __Self__ library. @@ -54,19 +54,19 @@ and [refmem mqtt_client async_disconnect]). [endsect] [/sentry] -[section:cons Considerations and limitations] +[section:cons Considerations and Limitations] The integrated auto-reconnect and retry mechanism greatly improves the user experience by simplifying complex processes and ensuring continuous connections. However, it is important to be mindful of certain limitations and considerations associated with this feature. -[heading Delayed handler invocation] +[heading Delayed Handler Invocation] During extended periods of __Client__ downtime, the completion handlers for asynchronous functions, such as those used in [refmem mqtt_client async_publish], may face considerable delays before invocation. This can result in users being left in the dark regarding the status of their requests due to the absence of prompt feedback on the initiated actions. -[heading Concealing configuration-related issues] +[heading Concealing Configuration-Related Issues] The __Client__ will always try to reconnect to the Broker(s) regardless of the reason why the connection was previously closed. This is desirable behaviour when the connection gets dropped due to underlying stream transport issues, @@ -93,10 +93,10 @@ By design, one of the main functional requirements of the __Client__ was to hand If the decision for reconnection were left to the user, then the user would need to handle all those error states manually, which would dramatically increase the complexity of the user's code, not to mention how difficult it would be to cover all possible error states. -The proposed approach for detecting configuration errors in the __Client__ is to use some simple logging facility during development. -Log lines should be injected directly into the __Client__ code (typically in the connect_op.hpp file), and logs would uncover misconfigurations (if any). +The proposed approach for detecting configuration errors in the __Client__ is to use our logging mechanism as described +in [link async_mqtt5.getting_started.debugging Debugging the Client] -[heading Increased resource consumption] +[heading Increased Resource Consumption] The __Client__ is designed to automatically buffer requests that are initiated while it is offline. During extended downtime or when a high volume of requests accumulates, this can lead to an increase in memory usage. diff --git a/doc/qbk/04_maintaining_a_stable_connection.qbk b/doc/qbk/04_maintaining_a_stable_connection.qbk index b82ddb8..aa81fad 100644 --- a/doc/qbk/04_maintaining_a_stable_connection.qbk +++ b/doc/qbk/04_maintaining_a_stable_connection.qbk @@ -4,7 +4,7 @@ (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:connection_maintenance Maintaining a stable connection] +[section:connection_maintenance Maintaining a Stable Connection] [nochunk] This chapter delves into the strategies used by the __Client__ to sustain a stable connection with the Broker. @@ -33,14 +33,14 @@ Use [refmem mqtt_client keep_alive] function during the __Client__ configuration Otherwise, the __Client__ defaults to a `Keep Alive` period of `60 seconds`. [note - The MQTT does not use the TCP's built-in keep-alive mechanism as it is inflexible and limited in that it can be configured solely at the operating system level. + The MQTT protocol does not use the TCP's built-in keep-alive mechanism as it is inflexible and limited in that it can be configured solely at the operating system level. The default time a connection must be idle before sending the first keep-alive packet is typically set to 2 hours, exceeding the tolerances of most MQTT applications. ] [endsect] [/keep_alive] -[section:half_open_connections Detecting and handling half-open connections] +[section:half_open_connections Detecting and Handling Half-open Connections] Ensuring the integrity and stability of network connections is a complex task, given the number of potential disruptions such as software anomalies, diff --git a/doc/qbk/05_optimising_communication.qbk b/doc/qbk/05_optimising_communication.qbk index 3d942d7..e79b596 100644 --- a/doc/qbk/05_optimising_communication.qbk +++ b/doc/qbk/05_optimising_communication.qbk @@ -4,7 +4,7 @@ (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:optimising_communication Optimising communication] +[section:optimising_communication Optimising Communication] [nochunk] This chapter provides a detailed breakdown of how __Client__ optimises its communications with the Broker @@ -12,7 +12,7 @@ with multiflight mode for simultaneous message handling and strategies for effic These techniques are key to getting the most out of MQTT in scenarios demanding fast and dependable message delivery, all while meeting the protocol's quality of service requirements and network efficiency standards. -[section:multiflight The multiflight mode] +[section:multiflight The Multiflight Mode] The __Self__ library introduces a multiflight feature. This allows the initiation of multiple asynchronous requests simultaneously, without waiting for the completion of the previous requests. @@ -40,7 +40,7 @@ Source: [link async_mqtt5.multiflight_client multiflight_client.cpp] [endsect] [/multiflight] -[section:packet_queuing Efficient bandwidth usage with packet queuing] +[section:packet_queuing Efficient Bandwidth Usage With Packet Queuing] The __Client__ employs a strategic queuing mechanism crucial in optimising network usage and performance for the user's requests. This mechanism bundles multiple MQTT packets for transmission within a single TCP packet whenever feasible @@ -62,7 +62,7 @@ if possible [footnote The Broker's `Receive Maximum` is equal to or greater than [endsect] [/packet_queuing] -[section:packet_ordering Packet ordering] +[section:packet_ordering Packet Ordering] The __Client__ uses a packet ordering mechanism to manage the queued packets pending dispatch to the Broker. The most important ordering rules are: diff --git a/doc/qbk/06_disconnecting_the_client.qbk b/doc/qbk/06_disconnecting_the_client.qbk index dc41768..6440705 100644 --- a/doc/qbk/06_disconnecting_the_client.qbk +++ b/doc/qbk/06_disconnecting_the_client.qbk @@ -90,14 +90,13 @@ In this case, the proper way to disconnect would be to call [refmem mqtt_client ); ``` -[section:reusing_the_client Restarting the Client after disconnection] +[section:reusing_the_client Restarting the Client After Disconnection] Once the __Client__ has been successfully stopped, reactivating it is straightforward and requires invoking [refmem mqtt_client async_run]. This method can be called right after initiating [refmem mqtt_client async_disconnect], without waiting for it to complete. The __Client__ is configurable again in the interval between stopping and restarting. -See `Customising your MQTT connection` in [link async_mqtt5.configuring_the_client Configuring the Client] -for more information. +See [link async_mqtt5.getting_started.configuration Configuring Your MQTT Connection] for more information. ``` int main() { diff --git a/doc/qbk/07_asio_compliance.qbk b/doc/qbk/07_asio_compliance.qbk index f7844e8..9c0e63c 100644 --- a/doc/qbk/07_asio_compliance.qbk +++ b/doc/qbk/07_asio_compliance.qbk @@ -4,7 +4,7 @@ (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:asio_compliance Compliance with Boost.Asio] +[section:asio_compliance Compliance With Boost.Asio] Every asynchronous operation in __Asio__ has associated characteristics that specify their behaviour. diff --git a/doc/qbk/11_multithreading.qbk b/doc/qbk/11_multithreading.qbk index 3ee1073..600bb79 100644 --- a/doc/qbk/11_multithreading.qbk +++ b/doc/qbk/11_multithreading.qbk @@ -4,13 +4,13 @@ (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:multithreading Using the mqtt_client in a multithreaded environment] +[section:multithreading Using the mqtt_client in a Multithreaded Environment] [nochunk] This chapter provides information about thread safety of the __Client__ and other __Asio__-compliant objects and provides examples of how to write thread-safe code in multithreaded environments. -[section:thread_safety Thread safety of ASIO-compliant objects] +[section:thread_safety Thread Safety of ASIO-Compliant Objects] A common misconception exists regarding the "thread safety" of ASIO-compliant asynchronous objects, specifically around the belief that initialising such an object with a __STRAND__ @@ -37,7 +37,7 @@ Instead, it encourages developers to implement their own concurrency management [endsect] [/thread_safety] -[section:executors_threads_strands Executors, threads, and strands] +[section:executors_threads_strands Executors, Threads, and Strands] Before delving into thread-safe programming, it is essential to understand the distinction between executors and threads. Executors are not threads but mechanisms for scheduling how and when work gets done. @@ -56,7 +56,7 @@ Refer to __ASIO_STRANDS__ for more details. [endsect] [/executors_threads_strands] -[section:thread_safe_code Writing thread-safe code] +[section:thread_safe_code Writing Thread-Safe Code] As mentioned previously, it is the user's responsibility to ensure that none of the __Client__'s member functions are called concurrently from separate threads. diff --git a/doc/qbk/15_examples.qbk b/doc/qbk/12_examples.qbk similarity index 100% rename from doc/qbk/15_examples.qbk rename to doc/qbk/12_examples.qbk diff --git a/doc/qbk/examples/Examples.qbk b/doc/qbk/examples/Examples.qbk index 8df6086..28bf0d1 100644 --- a/doc/qbk/examples/Examples.qbk +++ b/doc/qbk/examples/Examples.qbk @@ -8,25 +8,21 @@ [section:hello_world_over_tcp Hello World over TCP/IP] This example illustrates the process of setting up the Client to connect to the Broker via TCP/IP and publish a "Hello World!" message. -[import ../../../example/hello_world_over_tcp.cpp] [hello_world_over_tcp] [endsect] [/hello_world_over_tcp] [section:hello_world_over_tls Hello World over TLS/SSL] This example illustrates the process of setting up the Client to connect to the Broker via TLS/SSL and publish a "Hello World!" message. -[import ../../../example/hello_world_over_tls.cpp] [hello_world_over_tls] [endsect] [/hello_world_over_tls] [section:hello_world_over_websocket_tcp Hello World over Websocket/TCP] This example illustrates the process of setting up the Client to connect to the Broker via Websocket/TCP and publish a "Hello World!" message. -[import ../../../example/hello_world_over_websocket_tcp.cpp] [hello_world_over_websocket_tcp] [endsect] [/hello_world_over_websocket_tcp] [section:hello_world_over_websocket_tls Hello World over Websocket/TLS] This example illustrates the process of setting up the Client to connect to the Broker via Websocket/TLS and publish a "Hello World!" message. -[import ../../../example/hello_world_over_websocket_tls.cpp] [hello_world_over_websocket_tls] [endsect] [/hello_world_over_websocket_tls] @@ -34,7 +30,6 @@ This example illustrates the process of setting up the Client to connect to the This example shows how to use __Client__ as a publisher that publishes sensor readings every `5` seconds. The __Client__ uses TCP to connect to the Broker and modified __USE_AWAITABLE__ as the completion token. -[import ../../../example/publisher.cpp] [publisher] [endsect] @@ -43,14 +38,12 @@ This example shows how to use __Client__ as a receiver. The __Client__ subscribes and indefinitely receives Application Messages from the Broker. The __Client__ uses TCP to connect to the Broker and modified __USE_AWAITABLE__ as the completion token. -[import ../../../example/receiver.cpp] [receiver] [endsect] [section:multiflight_client The multiflight Client] This example shows how to use __Client__ to simultaneously dispatch multiple requests. -[import ../../../example/multiflight_client.cpp] [multiflight_client] [endsect] @@ -59,7 +52,6 @@ This example demonstrates how to use the __Client__ with its support for per-ope using parallel group. Specifically, in this example, the __Client__ will subscribe to a Topic and try to receive a message from the Topic within `5 seconds`. -[import ../../../example/timeout_with_parallel_group.cpp] [timeout_with_parallel_group] [endsect] @@ -69,21 +61,18 @@ using awaitable operators. Specifically, in this example, a call to [refmem mqtt_client async_publish] and [refmem mqtt_client async_disconnect] must complete within `5 seconds`. Otherwise, they will be cancelled. -[import ../../../example/timeout_with_awaitable_operators.cpp] [timeout_with_awaitable_operators] [endsect] [section:hello_world_in_multithreaded_env Hello World in a multithreaded environment using callbacks] This example demonstrates how to publish a "Hello World" message in a multithreaded environment using callbacks (`post`/`dispatch`). -[import ../../../example/hello_world_in_multithreaded_env.cpp] [hello_world_in_multithreaded_env] [endsect] [section:hello_world_in_coro_multithreaded_env Hello World in a multithreaded environment using coroutines] This example demonstrates how to publish a "Hello World" message in a multithreaded environment using coroutines (`co_spawn`). -[import ../../../example/hello_world_in_coro_multithreaded_env.cpp] [hello_world_in_coro_multithreaded_env] [endsect] diff --git a/doc/qbk/reference/concepts/LoggerType.qbk b/doc/qbk/reference/concepts/LoggerType.qbk new file mode 100644 index 0000000..c7fc9e6 --- /dev/null +++ b/doc/qbk/reference/concepts/LoggerType.qbk @@ -0,0 +1,87 @@ +[/ + Copyright (c) 2023-2024 Ivica Siladic, Bruno Iljazovic, Korina Simicevic + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +[section:LoggerType LoggerType concept] + +`LoggerType` represents an object type that will be used by the __Client__ to log events. + +A type satisfies the `LoggerType` concept if it defines [*any number (including zero)] of the following functions: + +[table:log_functions + [[Function signature] [Arguments] [Description]] + [ + [`void at_resolve(error_code ec, std::string_view host, std::string_view port, const asio::ip::tcp::resolver::results_type& eps);`] + [ + [*`ec`] is the `error_code` returned by the resolve operation. + + [*`host`] is the hostname used in the resolve. + + [*`port`] is the port used in the resolve. + + [*`eps`] is a list of endpoints returned by the resolve operation. + ] + [Invoked when the resolve operation is complete.] + ] + [ + [`void at_tcp_connect(error_code ec, asio::ip::tcp::endpoint ep);`] + [ + [*`ec`] is the `error_code` returned by the TCP connect operation. + + [*`ep`] is a TCP endpoint used to establish the TCP connection. + ] + [Invoked when the TCP connect operation is complete.] + ] + [ + [`void at_tls_handshake(error_code ec, asio::ip::tcp::endpoint ep);`] + [ + [*`ec`] is the `error_code` returned by the the TLS handshake operation. + + [*`ep`] is a TCP endpoint used to establish the TLS handshake. + ] + [Invoked when the TLS handshake operation is complete.] + ] + [ + [`void at_ws_handshake(error_code ec, asio::ip::tcp::endpoint ep);`] + [ + [*`ec`] is the `error_code` returned by the the WebSocket handshake operation. + + [*`ep`] is a TCP endpoint used to establish the WebSocket handshake. + ] + [Invoked when the WebSocket handshake operation is complete.] + ] + [ + [`void at_connack(reason_code rc, bool session_present, const connack_props& ca_props);`] + [ + [*`rc`] is the `reason_code` received in the __CONNACK__ packet indicating the result of the MQTT handshake. + + [*`session_present`] A flag indicating whether the Broker already has a session associated with this connection. + + [*`ca_props`] __CONNACK_PROPS__ received in the __CONNACK__ packet. + ] + [Invoked when the __CONNACK__ packet is received, marking the completion of the MQTT handshake. ] + ] + [ + [`void at_disconnect(reason_code rc, const disconnect_props& dc_props);`] + [ + [*`rc`] is the `reason_code` received in the __DISCONNECT__ packet specifying the reason behind the disconnection. + + [*`dc_props`] __DISCONNECT_PROPS__ received in the __DISCONNECT__ packet. + ] + [Invoked when the __DISCONNECT__ packet is received, indicating that the Broker wants to close this connection. ] + ] +] + +For example, a type `T` that defines `at_connack` and `at_disconnect` functions with their respective arguments is considered a valid `LoggerType`. +This allows you to create your own `LoggerType` classes with functions of interest. + +All defined functions are invoked directly within the __Client__ using its default executor. +If the __Client__ is initialized with an explicit or implicit strand, none of the functions will be invoked concurrently. + +[warning Defined functions should not block and stop the __Client__ from doing work. ] + +A class that satifies this concept is [ghreflink include/async_mqtt5/logger.hpp logger]. + +[endsect] diff --git a/doc/qbk/reference/quickref.xml b/doc/qbk/reference/quickref.xml index d52a007..8cb7f6e 100644 --- a/doc/qbk/reference/quickref.xml +++ b/doc/qbk/reference/quickref.xml @@ -20,7 +20,6 @@ subscribe_options subscribe_topic will - logger Concepts @@ -42,7 +41,6 @@ disconnect_rc_e qos_e retain_e - log_level Functions @@ -75,6 +73,12 @@ Reason codes Error handling + Logging + + LoggerType + logger + log_level + diff --git a/doc/reference.xsl b/doc/reference.xsl index f9500c0..5b75f11 100644 --- a/doc/reference.xsl +++ b/doc/reference.xsl @@ -31,6 +31,7 @@ [include concepts/StreamType.qbk] [include concepts/TlsContext.qbk] [include concepts/is_authenticator.qbk] +[include concepts/LoggerType.qbk] [include reason_codes/Reason_codes.qbk] [include properties/will_props.qbk] [include properties/connect_props.qbk] @@ -1470,18 +1471,24 @@ StreamType TlsContext is_authenticator + LoggerType - - - ____ + + + + ____ - + + + + + @@ -1524,7 +1531,8 @@ or contains(type, 'ExecutionContext') or contains(type, 'TlsContext') or contains(type, 'StreamType') - or contains(type, 'is_authenticator')"> + or contains(type, 'is_authenticator') + or contains(type, 'LoggerType')"> diff --git a/example/hello_world_over_tcp.cpp b/example/hello_world_over_tcp.cpp index c11d0ad..891a643 100644 --- a/example/hello_world_over_tcp.cpp +++ b/example/hello_world_over_tcp.cpp @@ -15,23 +15,36 @@ #include int main() { + //[init_tcp_client + // Initialize the execution context required to run I/O operations. boost::asio::io_context ioc; // Construct the Client with ``__TCP_SOCKET__`` as the underlying stream. - async_mqtt5::mqtt_client client(ioc); + //async_mqtt5::mqtt_client client(ioc); + async_mqtt5::mqtt_client client( + ioc, {} /* tls_context */, async_mqtt5::logger(async_mqtt5::log_level::debug) + ); + //] + //[configure_tcp_client // 1883 is the default TCP MQTT port. client.brokers("broker.hivemq.com", 1883) + .credentials("async_mqtt5_tester") .async_run(boost::asio::detached); + //] + //[publish_hello_world client.async_publish( "async-mqtt5/test", "Hello world!", async_mqtt5::retain_e::yes, async_mqtt5::publish_props {}, [&client](async_mqtt5::error_code ec) { std::cout << ec.message() << std::endl; + + // Disconnnect the Client. client.async_disconnect(boost::asio::detached); } ); + //] ioc.run(); } diff --git a/include/async_mqtt5/logger.hpp b/include/async_mqtt5/logger.hpp index 8040761..b390a14 100644 --- a/include/async_mqtt5/logger.hpp +++ b/include/async_mqtt5/logger.hpp @@ -130,7 +130,7 @@ public: write_prefix(); std::clog - << "tls handshake: " + << "TLS handshake: " << ep.address().to_string() << ":" << ep.port() << " - " << ec.message() << std::endl; @@ -148,7 +148,7 @@ public: write_prefix(); std::clog - << "ws handshake: " + << "WebSocket handshake: " << ep.address().to_string() << ":" << ep.port() << " - " << ec.message() << std::endl; diff --git a/include/async_mqtt5/mqtt_client.hpp b/include/async_mqtt5/mqtt_client.hpp index 67be565..8f6a36a 100644 --- a/include/async_mqtt5/mqtt_client.hpp +++ b/include/async_mqtt5/mqtt_client.hpp @@ -41,6 +41,7 @@ namespace asio = boost::asio; * the stream of bytes between the Client and the Broker. The transport must be * ordered and lossless. * \tparam \__TlsContext\__ Type of the context object used in TLS/SSL connections. + * \tparam \__LoggerType\__ Type of object used to log events within the Client. * * \par Thread safety * ['Distinct objects]: safe. \n @@ -85,7 +86,7 @@ public: * * \param ex An executor that will be associated with the Client. * \param tls_context A context object used in TLS/SSL connection. - * \param logger An object used to log events within the Client. + * \param logger An object satisfying the \__LoggerType\__ concept used to log events within the Client. */ explicit mqtt_client( const executor_type& ex, @@ -102,7 +103,7 @@ public: * \tparam \__ExecutionContext\__ Type of a concrete execution context. * \param context Execution context whose executor will be associated with the Client. * \param tls_context A context object used in TLS/SSL connection. - * \param logger An object used to log events within the Client. + * \param logger An object satisfying the \__LoggerType\__ concept used to log events within the Client. * * \par Precondition * \code @@ -442,7 +443,7 @@ public: * \param token Completion token that will be used to produce a * completion handler. The handler will be invoked when the operation completes. * On immediate completion, invocation of the handler will be performed in a manner - * equivalent to using \__POST\__. + * equivalent to using \__ASYNC_IMMEDIATE\__. * * \par Handler signature * The handler signature for this operation depends on the \ref qos_e specified:\n @@ -535,7 +536,7 @@ public: * \param token Completion token that will be used to produce a * completion handler. The handler will be invoked when the operation completes. * On immediate completion, invocation of the handler will be performed in a manner - * equivalent to using \__POST\__. + * equivalent to using \__ASYNC_IMMEDIATE\__. * * \par Handler signature * The handler signature for this operation: @@ -608,7 +609,7 @@ public: * \param token Completion token that will be used to produce a * completion handler. The handler will be invoked when the operation completes. * On immediate completion, invocation of the handler will be performed in a manner - * equivalent to using \__POST\__. + * equivalent to using \__ASYNC_IMMEDIATE\__. * * \par Handler signature * The handler signature for this operation: @@ -677,7 +678,7 @@ public: * \param token Completion token that will be used to produce a * completion handler. The handler will be invoked when the operation completes. * On immediate completion, invocation of the handler will be performed in a manner - * equivalent to using \__POST\__. + * equivalent to using \__ASYNC_IMMEDIATE\__. * * \par Handler signature * The handler signature for this operation: @@ -745,7 +746,7 @@ public: * \param token Completion token that will be used to produce a * completion handler. The handler will be invoked when the operation completes. * On immediate completion, invocation of the handler will be performed in a manner - * equivalent to using \__POST\__. + * equivalent to using \__ASYNC_IMMEDIATE\__. * * \par Handler signature * The handler signature for this operation: @@ -871,8 +872,6 @@ public: * \param props An instance of \__DISCONNECT_PROPS\__. * \param token Completion token that will be used to produce a * completion handler. The handler will be invoked when the operation completes. - * On immediate completion, invocation of the handler will be performed in a manner - * equivalent to using \__POST\__. * * \par Handler signature * The handler signature for this operation: @@ -935,8 +934,6 @@ public: * * \param token Completion token that will be used to produce a * completion handler. The handler will be invoked when the operation completes. - * On immediate completion, invocation of the handler will be performed in a manner - * equivalent to using \__POST\__. * * \par Handler signature * The handler signature for this operation: diff --git a/include/async_mqtt5/types.hpp b/include/async_mqtt5/types.hpp index c114596..f77039f 100644 --- a/include/async_mqtt5/types.hpp +++ b/include/async_mqtt5/types.hpp @@ -25,7 +25,14 @@ using error_code = boost::system::error_code; * such as the hostname, port, and path. */ struct authority_path { - std::string host, port, path; + /** The hostname of the authority as a domain name or an IP address. */ + std::string host; + + /** The port number used for communication. */ + std::string port; + + /** Specifies the endpoint path relevant to WebSocket connections. */ + std::string path; }; /** diff --git a/test/unit/logger.cpp b/test/unit/logger.cpp index 8f88d05..14cedbd 100644 --- a/test/unit/logger.cpp +++ b/test/unit/logger.cpp @@ -115,8 +115,8 @@ BOOST_AUTO_TEST_CASE(successful_connect_debug) { BOOST_TEST_MESSAGE(log); BOOST_TEST_WARN(contains(log, "resolve")); BOOST_TEST_WARN(contains(log, "connect")); - BOOST_TEST_WARN(contains(log, "tls handshake")); - BOOST_TEST_WARN(contains(log, "ws handshake")); + BOOST_TEST_WARN(contains(log, "TLS handshake")); + BOOST_TEST_WARN(contains(log, "WebSocket handshake")); BOOST_TEST_WARN(contains(log, "connack")); }