From 791abb6dedddf594220ef8a7a71802829c5ffa53 Mon Sep 17 00:00:00 2001 From: Takatoshi Kondo Date: Sat, 4 May 2024 15:49:49 +0900 Subject: [PATCH] Updated the version to 5.1.0. --- CHANGELOG.adoc | 4 + CMakeLists.txt | 4 +- README.md | 6 +- ...sasync__mqtt_1_1basic__client-members.html | 139 ++ .../classasync__mqtt_1_1basic__client.html | 1311 +++++++++++++++++ doc/api/classasync__mqtt_1_1basic__client.js | 33 + doc/api/client_8hpp.html | 127 ++ doc/api/client_8hpp.js | 5 + doc/api/client_8hpp_source.html | 830 +++++++++++ doc/api/inherit_graph_45.map | 3 + doc/api/inherit_graph_45.md5 | 1 + doc/api/inherit_graph_45.png | Bin 0 -> 3808 bytes doc/api/inherit_graph_46.map | 3 + doc/api/inherit_graph_46.md5 | 1 + doc/api/inherit_graph_46.png | Bin 0 -> 3420 bytes doc/api/search/files_4.js | 6 + doc/api/search/typedefs_7.js | 5 + ...1_1basic__client_1_1pubres__t-members.html | 113 ++ ...c__mqtt_1_1basic__client_1_1pubres__t.html | 138 ++ ...ync__mqtt_1_1basic__client_1_1pubres__t.js | 6 + doc/tutorial/client.html | 654 ++++++++ doc/tutorial/non_packet_based.html | 14 +- 22 files changed, 3395 insertions(+), 8 deletions(-) create mode 100644 doc/api/classasync__mqtt_1_1basic__client-members.html create mode 100644 doc/api/classasync__mqtt_1_1basic__client.html create mode 100644 doc/api/classasync__mqtt_1_1basic__client.js create mode 100644 doc/api/client_8hpp.html create mode 100644 doc/api/client_8hpp.js create mode 100644 doc/api/client_8hpp_source.html create mode 100644 doc/api/inherit_graph_45.map create mode 100644 doc/api/inherit_graph_45.md5 create mode 100644 doc/api/inherit_graph_45.png create mode 100644 doc/api/inherit_graph_46.map create mode 100644 doc/api/inherit_graph_46.md5 create mode 100644 doc/api/inherit_graph_46.png create mode 100644 doc/api/search/files_4.js create mode 100644 doc/api/search/typedefs_7.js create mode 100644 doc/api/structasync__mqtt_1_1basic__client_1_1pubres__t-members.html create mode 100644 doc/api/structasync__mqtt_1_1basic__client_1_1pubres__t.html create mode 100644 doc/api/structasync__mqtt_1_1basic__client_1_1pubres__t.js create mode 100644 doc/tutorial/client.html diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 728eed08d..17ba694f3 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -2,6 +2,10 @@ = History +== 5.1.0 +* Added tests. #180 +* Added high level MQTT client APIs support. #178 + == 5.0.0 === breaking changes diff --git a/CMakeLists.txt b/CMakeLists.txt index 2be02e163..f658f034d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ # http://www.boost.org/LICENSE_1_0.txt) cmake_minimum_required (VERSION 3.13.0) -project(async_mqtt_iface VERSION 5.0.0) +project(async_mqtt_iface VERSION 5.1.0) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -115,7 +115,7 @@ if(DOXYGEN_FOUND) COMMAND ${CMAKE_COMMAND} -E echo "FILE_PATTERNS = *.hpp" >> ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile COMMAND ${CMAKE_COMMAND} -E echo "OUTPUT_DIRECTORY = doc" >> ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile COMMAND ${CMAKE_COMMAND} -E echo "PROJECT_NAME = async_mqtt" >> ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile - COMMAND ${CMAKE_COMMAND} -E echo "PROJECT_NUMBER = 5.0.0" >> ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + COMMAND ${CMAKE_COMMAND} -E echo "PROJECT_NUMBER = 5.1.0" >> ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile COMMAND ${CMAKE_COMMAND} -E echo "RECURSIVE = YES" >> ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile COMMAND ${CMAKE_COMMAND} -E echo "PREDEFINED = _DOXYGEN_ ASYNC_MQTT_USE_TLS ASYNC_MQTT_USE_WS" >> ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile COMMAND ${CMAKE_COMMAND} -E echo "INPUT = ${CMAKE_CURRENT_SOURCE_DIR}/include/async_mqtt" >> ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile diff --git a/README.md b/README.md index 98864ab0f..47ac3fb9a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Asynchronous MQTT communication library. -Version 5.0.0 [![Actions Status](https://github.com/redboltz/async_mqtt/workflows/CI/badge.svg)](https://github.com/redboltz/async_mqtt/actions)[![codecov](https://codecov.io/gh/redboltz/async_mqtt/branch/main/graph/badge.svg)](https://codecov.io/gh/redboltz/async_mqtt) +Version 5.1.0 [![Actions Status](https://github.com/redboltz/async_mqtt/workflows/CI/badge.svg)](https://github.com/redboltz/async_mqtt/actions)[![codecov](https://codecov.io/gh/redboltz/async_mqtt/branch/main/graph/badge.svg)](https://codecov.io/gh/redboltz/async_mqtt) This is Boost.Asio oriented asynchronous MQTT communication library. You can use async_mqtt to develop not only your MQTT client application but also your server (e.g. broker). Based on https://github.com/redboltz/mqtt_cpp experience, there are many improvements. See overview. @@ -42,6 +42,10 @@ Document is https://github.com/redboltz/async_mqtt/blob/doc/README.adoc I recommend using [Stackless Coroutine (`boost::asio::coroutine`)](https://www.boost.org/doc/html/boost_asio/overview/composition/coroutine.html) because it can avoid deep nested callbacks and higher performance than [`boost::asio::use_future`](https://www.boost.org/doc/html/boost_asio/overview/composition/futures.html). C++20 Coroutine is also a good choice. It requires C++20 support. It is more elegant than Stackless Coroutine but a little bit slower than Stackless coroutine. +## High level MQTT client APIs support (since 5.1.0) + +See [document](https://redboltz.github.io/async_mqtt/doc/latest/tutorial/client.html) and [example](example/cl_cpp20coro_mqtt.cpp). + ## Features - Not only client but also server is supported. diff --git a/doc/api/classasync__mqtt_1_1basic__client-members.html b/doc/api/classasync__mqtt_1_1basic__client-members.html new file mode 100644 index 000000000..85e3bcc8e --- /dev/null +++ b/doc/api/classasync__mqtt_1_1basic__client-members.html @@ -0,0 +1,139 @@ + + + + + + + +async_mqtt: Member List + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
async_mqtt 5.0.0 +
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
async_mqtt::basic_client< Version, Strand, NextLayer > Member List
+
+
+ +

This is the complete list of members for async_mqtt::basic_client< Version, Strand, NextLayer >, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
acquire_unique_packet_id(CompletionToken &&token)async_mqtt::basic_client< Version, Strand, NextLayer >inline
acquire_unique_packet_id()async_mqtt::basic_client< Version, Strand, NextLayer >inline
acquire_unique_packet_id_wait_until(CompletionToken &&token)async_mqtt::basic_client< Version, Strand, NextLayer >inline
basic_client(Args &&... args)async_mqtt::basic_client< Version, Strand, NextLayer >inline
client typedefasync_mqtt::basic_client< Version, Strand, NextLayer >related
client_st typedefasync_mqtt::basic_client< Version, Strand, NextLayer >related
close(CompletionToken &&token)async_mqtt::basic_client< Version, Strand, NextLayer >inline
disconnect(disconnect_packet packet, CompletionToken &&token)async_mqtt::basic_client< Version, Strand, NextLayer >inline
get_executor() constasync_mqtt::basic_client< Version, Strand, NextLayer >inline
in_strand() constasync_mqtt::basic_client< Version, Strand, NextLayer >inline
lowest_layer() constasync_mqtt::basic_client< Version, Strand, NextLayer >inline
lowest_layer()async_mqtt::basic_client< Version, Strand, NextLayer >inline
next_layer() constasync_mqtt::basic_client< Version, Strand, NextLayer >inline
next_layer()async_mqtt::basic_client< Version, Strand, NextLayer >inline
publish(publish_packet packet, CompletionToken &&token)async_mqtt::basic_client< Version, Strand, NextLayer >inline
recv(CompletionToken &&token)async_mqtt::basic_client< Version, Strand, NextLayer >inline
register_packet_id(packet_id_t pid, CompletionToken &&token)async_mqtt::basic_client< Version, Strand, NextLayer >inline
register_packet_id(packet_id_t pid)async_mqtt::basic_client< Version, Strand, NextLayer >inline
release_packet_id(packet_id_t pid, CompletionToken &&token)async_mqtt::basic_client< Version, Strand, NextLayer >inline
release_packet_id(packet_id_t pid)async_mqtt::basic_client< Version, Strand, NextLayer >inline
set_auto_map_topic_alias_send(bool val)async_mqtt::basic_client< Version, Strand, NextLayer >inline
set_auto_replace_topic_alias_send(bool val)async_mqtt::basic_client< Version, Strand, NextLayer >inline
set_bulk_write(bool val)async_mqtt::basic_client< Version, Strand, NextLayer >inline
set_pingresp_recv_timeout_ms(std::size_t ms)async_mqtt::basic_client< Version, Strand, NextLayer >inline
start(connect_packet packet, CompletionToken &&token)async_mqtt::basic_client< Version, Strand, NextLayer >inline
strand() constasync_mqtt::basic_client< Version, Strand, NextLayer >inline
strand()async_mqtt::basic_client< Version, Strand, NextLayer >inline
subscribe(subscribe_packet packet, CompletionToken &&token)async_mqtt::basic_client< Version, Strand, NextLayer >inline
unsubscribe(unsubscribe_packet packet, CompletionToken &&token)async_mqtt::basic_client< Version, Strand, NextLayer >inline
+
+ + + + diff --git a/doc/api/classasync__mqtt_1_1basic__client.html b/doc/api/classasync__mqtt_1_1basic__client.html new file mode 100644 index 000000000..6adeb74f6 --- /dev/null +++ b/doc/api/classasync__mqtt_1_1basic__client.html @@ -0,0 +1,1311 @@ + + + + + + + +async_mqtt: async_mqtt::basic_client< Version, Strand, NextLayer > Class Template Reference + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
async_mqtt 5.0.0 +
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+ +
async_mqtt::basic_client< Version, Strand, NextLayer > Class Template Reference
+
+
+ +

MQTT client for casual usecases. + More...

+ +

#include <client.hpp>

+ + + + + +

+Classes

struct  pubres_t
 publish completion handler parameter class More...
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

template<typename... Args>
 basic_client (Args &&... args)
 constructor
 
template<typename CompletionToken >
auto start (connect_packet packet, CompletionToken &&token)
 send CONNECT packet and start packet receive loop
 
template<typename CompletionToken >
auto subscribe (subscribe_packet packet, CompletionToken &&token)
 send SUBSCRIBE packet
 
template<typename CompletionToken >
auto unsubscribe (unsubscribe_packet packet, CompletionToken &&token)
 send UNSUBSCRIBE packet
 
template<typename CompletionToken >
auto publish (publish_packet packet, CompletionToken &&token)
 send PUBLISH packet
 
template<typename CompletionToken >
auto disconnect (disconnect_packet packet, CompletionToken &&token)
 send DISCONNECT packet
 
template<typename CompletionToken >
auto close (CompletionToken &&token)
 close the underlying connection
 
template<typename CompletionToken >
auto recv (CompletionToken &&token)
 receive PUBLISH or DISCONNECT packet users CANNOT call recv() before the previous recv()'s CompletionToken is invoked
 
as::any_io_executor get_executor () const
 executor getter
 
strand_type conststrand () const
 strand getter
 
strand_type & strand ()
 strand getter
 
bool in_strand () const
 strand checker
 
auto constnext_layer () const
 next_layer getter
 
autonext_layer ()
 next_layer getter
 
auto constlowest_layer () const
 lowest_layer getter
 
autolowest_layer ()
 lowest_layer getter
 
void set_auto_map_topic_alias_send (bool val)
 auto map (allocate) topic alias on send PUBLISH packet. If all topic aliases are used, then overwrite by LRU algorithm.
+ This function should be called before send() call.
 
void set_auto_replace_topic_alias_send (bool val)
 auto replace topic with corresponding topic alias on send PUBLISH packet. Registering topic alias need to do manually.
+ This function should be called before send() call.
 
void set_pingresp_recv_timeout_ms (std::size_t ms)
 Set timeout for receiving PINGRESP packet after PINGREQ packet is sent. If the timer is fired, then the underlying layer is closed from the client side. If the protocol_version is v5, then send DISCONNECT packet with the reason code disconnect_reason_code::keep_alive_timeout automatically before underlying layer is closed.
+ This function should be called before send() call.
 
void set_bulk_write (bool val)
 Set bulk write mode. If true, then concatenate multiple packets' const buffer sequence when send() is called before the previous send() is not completed. Otherwise, send packet one by one.
+ This function should be called before send() call.
 
template<typename CompletionToken >
auto acquire_unique_packet_id (CompletionToken &&token)
 acuire unique packet_id.
 
template<typename CompletionToken >
auto acquire_unique_packet_id_wait_until (CompletionToken &&token)
 acuire unique packet_id. If packet_id is fully acquired, then wait until released.
 
template<typename CompletionToken >
auto register_packet_id (packet_id_t pid, CompletionToken &&token)
 acuire unique packet_id. If packet_id is fully acquired, then wait until released.
 
template<typename CompletionToken >
auto release_packet_id (packet_id_t pid, CompletionToken &&token)
 register packet_id.
 
optional< packet_id_t > acquire_unique_packet_id ()
 acuire unique packet_id.
 
bool register_packet_id (packet_id_t pid)
 register packet_id.
 
void release_packet_id (packet_id_t pid)
 release packet_id.
 
+ + + + + + + + + + +

+Related Symbols

(Note that these are not member symbols.)

+
template<protocol_version Version, typename NextLayer >
using client = basic_client<Version, as::strand, NextLayer>
 Type alias of basic_client (Strand=boost::asio::strand). This is for typical usecase.
 
template<protocol_version Version, typename NextLayer >
using client_st = basic_client<Version, null_strand, NextLayer>
 Type alias of basic_client (Strand=null_strand). This is for typical usecase.
 
+

Detailed Description

+
template<protocol_version Version, template< typename > typename Strand, typename NextLayer>
+class async_mqtt::basic_client< Version, Strand, NextLayer >

MQTT client for casual usecases.

+
Template Parameters
+ + + + +
VersionMQTT protocol version.
Strandstrand class template type. By default boost::asio::strand<T> should be used. You can replace it with null_strand if you run the endpoint on single thread environment.
NextLayerJust next layer for basic_endpoint. mqtt, mqtts, ws, and wss are predefined.
+
+
+

Constructor & Destructor Documentation

+ +

◆ basic_client()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+
+template<typename... Args>
+ + + + + +
+ + + + + + + +
async_mqtt::basic_client< Version, Strand, NextLayer >::basic_client (Args &&... args)
+
+inline
+
+ +

constructor

+
Template Parameters
+ + +
ArgsTypes for the next layer
+
+
+
Parameters
+ + +
argsargs for the next layer. There are predefined next layer types:
+ protocol::mqtt, protocol::mqtts, protocol::ws, and protocol::wss.
+
+
+ +
+
+

Member Function Documentation

+ +

◆ acquire_unique_packet_id() [1/2]

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
optional< packet_id_t > async_mqtt::basic_client< Version, Strand, NextLayer >::acquire_unique_packet_id ()
+
+inline
+
+ +

acuire unique packet_id.

+
Returns
optional<packet_id_t> if acquired return acquired packet id, otherwise nullopt
+
Note
This function is SYNC function that must only be called in the strand.
+ +
+
+ +

◆ acquire_unique_packet_id() [2/2]

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + + +
+ + + + + + + +
auto async_mqtt::basic_client< Version, Strand, NextLayer >::acquire_unique_packet_id (CompletionToken && token)
+
+inline
+
+ +

acuire unique packet_id.

+
Parameters
+ + +
tokenthe param is optional<packet_id_t>
+
+
+
Returns
deduced by token
+ +
+
+ +

◆ acquire_unique_packet_id_wait_until()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + + +
+ + + + + + + +
auto async_mqtt::basic_client< Version, Strand, NextLayer >::acquire_unique_packet_id_wait_until (CompletionToken && token)
+
+inline
+
+ +

acuire unique packet_id. If packet_id is fully acquired, then wait until released.

+
Parameters
+ + +
tokenthe param is packet_id_t
+
+
+
Returns
deduced by token
+ +
+
+ +

◆ close()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + + +
+ + + + + + + +
auto async_mqtt::basic_client< Version, Strand, NextLayer >::close (CompletionToken && token)
+
+inline
+
+ +

close the underlying connection

+
Parameters
+ + +
tokenthe param is void
+
+
+
Returns
deduced by token
+ +
+
+ +

◆ disconnect()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + + +
+ + + + + + + + + + + +
auto async_mqtt::basic_client< Version, Strand, NextLayer >::disconnect (disconnect_packet packet,
CompletionToken && token )
+
+inline
+
+ +

send DISCONNECT packet

+
Parameters
+ + + +
packetDISCONNECT packet
tokenthe params is error_code
+
+
+
Returns
deduced by token
+ +
+
+ +

◆ get_executor()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
as::any_io_executor async_mqtt::basic_client< Version, Strand, NextLayer >::get_executor () const
+
+inline
+
+ +

executor getter

+
Returns
strand as an executor
+ +
+
+ +

◆ in_strand()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
bool async_mqtt::basic_client< Version, Strand, NextLayer >::in_strand () const
+
+inline
+
+ +

strand checker

+
Returns
true if the current context running in the strand, otherwise false
+ +
+
+ +

◆ lowest_layer() [1/2]

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
auto & async_mqtt::basic_client< Version, Strand, NextLayer >::lowest_layer ()
+
+inline
+
+ +

lowest_layer getter

+
Returns
reference of the lowest_layer
+ +
+
+ +

◆ lowest_layer() [2/2]

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
auto const & async_mqtt::basic_client< Version, Strand, NextLayer >::lowest_layer () const
+
+inline
+
+ +

lowest_layer getter

+
Returns
const reference of the lowest_layer
+ +
+
+ +

◆ next_layer() [1/2]

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
auto & async_mqtt::basic_client< Version, Strand, NextLayer >::next_layer ()
+
+inline
+
+ +

next_layer getter

+
Returns
reference of the next_layer
+ +
+
+ +

◆ next_layer() [2/2]

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
auto const & async_mqtt::basic_client< Version, Strand, NextLayer >::next_layer () const
+
+inline
+
+ +

next_layer getter

+
Returns
const reference of the next_layer
+ +
+
+ +

◆ publish()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + + +
+ + + + + + + + + + + +
auto async_mqtt::basic_client< Version, Strand, NextLayer >::publish (publish_packet packet,
CompletionToken && token )
+
+inline
+
+ +

send PUBLISH packet

+
Parameters
+ + + +
packetPUBLISH packet
tokenthe params are error_code, pubres_t When sending QoS0 packet, all members of pubres_t is nullopt. When sending QoS1 packet, only pubres_t::puback_opt is set. When sending QoS1 packet, only pubres_t::pubrec_opt pubres_t::pubcomp are set.
+
+
+
Returns
deduced by token
+ +
+
+ +

◆ recv()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + + +
+ + + + + + + +
auto async_mqtt::basic_client< Version, Strand, NextLayer >::recv (CompletionToken && token)
+
+inline
+
+ +

receive PUBLISH or DISCONNECT packet users CANNOT call recv() before the previous recv()'s CompletionToken is invoked

+
Parameters
+ + +
tokenthe params are error_code, optional<publish_packet>, and optional<disconnect_packet>
+
+
+
Returns
deduced by token
+ +
+
+ +

◆ register_packet_id() [1/2]

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
bool async_mqtt::basic_client< Version, Strand, NextLayer >::register_packet_id (packet_id_t pid)
+
+inline
+
+ +

register packet_id.

+
Parameters
+ + +
packet_idpacket_id to register
+
+
+
Returns
If true, success, otherwise the packet_id has already been used.
+
Note
This function is SYNC function that must only be called in the strand.
+ +
+
+ +

◆ register_packet_id() [2/2]

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + + +
+ + + + + + + + + + + +
auto async_mqtt::basic_client< Version, Strand, NextLayer >::register_packet_id (packet_id_t pid,
CompletionToken && token )
+
+inline
+
+ +

acuire unique packet_id. If packet_id is fully acquired, then wait until released.

+
Parameters
+ + +
tokenthe param is packet_id_t
+
+
+
Returns
deduced by token
+ +
+
+ +

◆ release_packet_id() [1/2]

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
void async_mqtt::basic_client< Version, Strand, NextLayer >::release_packet_id (packet_id_t pid)
+
+inline
+
+ +

release packet_id.

+
Parameters
+ + +
packet_idpacket_id to release
+
+
+
Note
This function is SYNC function that must only be called in the strand.
+ +
+
+ +

◆ release_packet_id() [2/2]

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + + +
+ + + + + + + + + + + +
auto async_mqtt::basic_client< Version, Strand, NextLayer >::release_packet_id (packet_id_t pid,
CompletionToken && token )
+
+inline
+
+ +

register packet_id.

+
Parameters
+ + + +
packet_idpacket_id to register
tokenthe param is bool. If true, success, otherwise the packet_id has already been used.
+
+
+
Returns
deduced by token
+ +
+
+ +

◆ set_auto_map_topic_alias_send()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
void async_mqtt::basic_client< Version, Strand, NextLayer >::set_auto_map_topic_alias_send (bool val)
+
+inline
+
+ +

auto map (allocate) topic alias on send PUBLISH packet. If all topic aliases are used, then overwrite by LRU algorithm.
+ This function should be called before send() call.

+
Note
By default not automatically mapping.
+
Parameters
+ + +
valif true, enable auto mapping, otherwise disable.
+
+
+ +
+
+ +

◆ set_auto_replace_topic_alias_send()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
void async_mqtt::basic_client< Version, Strand, NextLayer >::set_auto_replace_topic_alias_send (bool val)
+
+inline
+
+ +

auto replace topic with corresponding topic alias on send PUBLISH packet. Registering topic alias need to do manually.
+ This function should be called before send() call.

+
Note
By default not automatically replacing.
+
Parameters
+ + +
valif true, enable auto replacing, otherwise disable.
+
+
+ +
+
+ +

◆ set_bulk_write()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
void async_mqtt::basic_client< Version, Strand, NextLayer >::set_bulk_write (bool val)
+
+inline
+
+ +

Set bulk write mode. If true, then concatenate multiple packets' const buffer sequence when send() is called before the previous send() is not completed. Otherwise, send packet one by one.
+ This function should be called before send() call.

+
Note
By default bulk write mode is false (disabled)
+
Parameters
+ + +
valif true, enable bulk write mode, otherwise disable it.
+
+
+ +
+
+ +

◆ set_pingresp_recv_timeout_ms()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
void async_mqtt::basic_client< Version, Strand, NextLayer >::set_pingresp_recv_timeout_ms (std::size_t ms)
+
+inline
+
+ +

Set timeout for receiving PINGRESP packet after PINGREQ packet is sent. If the timer is fired, then the underlying layer is closed from the client side. If the protocol_version is v5, then send DISCONNECT packet with the reason code disconnect_reason_code::keep_alive_timeout automatically before underlying layer is closed.
+ This function should be called before send() call.

+
Note
By default timeout is not set.
+
Parameters
+ + +
valif 0, timer is not set, otherwise set val milliseconds.
+
+
+ +
+
+ +

◆ start()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + + +
+ + + + + + + + + + + +
auto async_mqtt::basic_client< Version, Strand, NextLayer >::start (connect_packet packet,
CompletionToken && token )
+
+inline
+
+ +

send CONNECT packet and start packet receive loop

+
Parameters
+ + + +
packetCONNECT packet
tokenthe params are error_code, optional<connack_packet>
+
+
+
Returns
deduced by token
+ +
+
+ +

◆ strand() [1/2]

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
strand_type & async_mqtt::basic_client< Version, Strand, NextLayer >::strand ()
+
+inline
+
+ +

strand getter

+
Returns
reference of the strand
+ +
+
+ +

◆ strand() [2/2]

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + +
+ + + + + + + +
strand_type const & async_mqtt::basic_client< Version, Strand, NextLayer >::strand () const
+
+inline
+
+ +

strand getter

+
Returns
const reference of the strand
+ +
+
+ +

◆ subscribe()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + + +
+ + + + + + + + + + + +
auto async_mqtt::basic_client< Version, Strand, NextLayer >::subscribe (subscribe_packet packet,
CompletionToken && token )
+
+inline
+
+ +

send SUBSCRIBE packet

+
Parameters
+ + + +
packetSUBSCRIBE packet
tokenthe params are error_code, optional<suback_packet>
+
+
+
Returns
deduced by token
+ +
+
+ +

◆ unsubscribe()

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+ + + + + + +
+ + + + + + + + + + + +
auto async_mqtt::basic_client< Version, Strand, NextLayer >::unsubscribe (unsubscribe_packet packet,
CompletionToken && token )
+
+inline
+
+ +

send UNSUBSCRIBE packet

+
Parameters
+ + + +
packetUNSUBSCRIBE packet
tokenthe params are error_code, optional<unsuback_packet>
+
+
+
Returns
deduced by token
+ +
+
+

Friends And Related Symbol Documentation

+ +

◆ client

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+
+template<protocol_version Version, typename NextLayer >
+ + + + + +
+ + + + +
using client = basic_client<Version, as::strand, NextLayer>
+
+related
+
+ +

Type alias of basic_client (Strand=boost::asio::strand). This is for typical usecase.

+
Template Parameters
+ + +
NextLayerJust next layer for basic_endpoint. mqtt, mqtts, ws, and wss are predefined.
+
+
+ +
+
+ +

◆ client_st

+ +
+
+
+template<protocol_version Version, template< typename > typename Strand, typename NextLayer >
+
+template<protocol_version Version, typename NextLayer >
+ + + + + +
+ + + + +
using client_st = basic_client<Version, null_strand, NextLayer>
+
+related
+
+ +

Type alias of basic_client (Strand=null_strand). This is for typical usecase.

+
Template Parameters
+ + +
NextLayerJust next layer for basic_endpoint. mqtt, mqtts, ws, and wss are predefined.
+
+
+ +
+
+
The documentation for this class was generated from the following file:
    +
  • /home/kondo/work/async_mqtt/include/async_mqtt/client.hpp
  • +
+
+
+ + + + diff --git a/doc/api/classasync__mqtt_1_1basic__client.js b/doc/api/classasync__mqtt_1_1basic__client.js new file mode 100644 index 000000000..e9f48ed04 --- /dev/null +++ b/doc/api/classasync__mqtt_1_1basic__client.js @@ -0,0 +1,33 @@ +var classasync__mqtt_1_1basic__client = +[ + [ "pubres_t", "structasync__mqtt_1_1basic__client_1_1pubres__t.html", "structasync__mqtt_1_1basic__client_1_1pubres__t" ], + [ "basic_client", "classasync__mqtt_1_1basic__client.html#aae0fb6a264f5feac3172c935d63f8f2b", null ], + [ "acquire_unique_packet_id", "classasync__mqtt_1_1basic__client.html#acaea92142dca0924af36e5acef91d8bb", null ], + [ "acquire_unique_packet_id", "classasync__mqtt_1_1basic__client.html#aa5a37f75664bb4dd8b883e464f2016e5", null ], + [ "acquire_unique_packet_id_wait_until", "classasync__mqtt_1_1basic__client.html#afbc77b4e603db0c1141d3235c8fa8b35", null ], + [ "close", "classasync__mqtt_1_1basic__client.html#a4758d075939de30c77f3f4bdf0f7a4e1", null ], + [ "disconnect", "classasync__mqtt_1_1basic__client.html#a13400c20164b4e0d2ed4d295cd6413d0", null ], + [ "get_executor", "classasync__mqtt_1_1basic__client.html#a7b2a774d16a96243e46d7dd9f8efc5c0", null ], + [ "in_strand", "classasync__mqtt_1_1basic__client.html#a958a6f26550d04d612c90ac28687276d", null ], + [ "lowest_layer", "classasync__mqtt_1_1basic__client.html#a899373f16e994c427de1cc1f55e2900d", null ], + [ "lowest_layer", "classasync__mqtt_1_1basic__client.html#a0c4b8f45b124d877b1d5e37202432542", null ], + [ "next_layer", "classasync__mqtt_1_1basic__client.html#a327733ce5f15e48acbdd366cc9b51dae", null ], + [ "next_layer", "classasync__mqtt_1_1basic__client.html#a17f4c62b162f33c95f893e19cc7a045e", null ], + [ "publish", "classasync__mqtt_1_1basic__client.html#ab6bed9cb83ac66b7bcb8595941edae4c", null ], + [ "recv", "classasync__mqtt_1_1basic__client.html#aad1963132aa1d0c6458bd6f38d9b7e48", null ], + [ "register_packet_id", "classasync__mqtt_1_1basic__client.html#a59d9f08b64a0b06a6d94b666fd51a9fa", null ], + [ "register_packet_id", "classasync__mqtt_1_1basic__client.html#a7020cadea9c167746dd248cc66eea67e", null ], + [ "release_packet_id", "classasync__mqtt_1_1basic__client.html#a10dcc67eddbb1b31bed4d7831b70edbc", null ], + [ "release_packet_id", "classasync__mqtt_1_1basic__client.html#a9e9309f80f102d442e5355adf3c1cc86", null ], + [ "set_auto_map_topic_alias_send", "classasync__mqtt_1_1basic__client.html#ac04e97c4b491ccfe707158d889e0657b", null ], + [ "set_auto_replace_topic_alias_send", "classasync__mqtt_1_1basic__client.html#a516a226a27334ed324df25a2a530d489", null ], + [ "set_bulk_write", "classasync__mqtt_1_1basic__client.html#ad5ba02f153d9a4a592acc50f1367f799", null ], + [ "set_pingresp_recv_timeout_ms", "classasync__mqtt_1_1basic__client.html#ae6de76e91012ea196666ca450d025560", null ], + [ "start", "classasync__mqtt_1_1basic__client.html#a64c2b201c643fabc568865933b681f80", null ], + [ "strand", "classasync__mqtt_1_1basic__client.html#a58b9fbfa4909f0cf0c91459a454de69d", null ], + [ "strand", "classasync__mqtt_1_1basic__client.html#a444ec817894b27eb7793b388f54d4067", null ], + [ "subscribe", "classasync__mqtt_1_1basic__client.html#ae74159d835dca15f87b760b53acb4d51", null ], + [ "unsubscribe", "classasync__mqtt_1_1basic__client.html#a0ff1b5b724340a3df4c9ce9fab7a4b90", null ], + [ "client", "classasync__mqtt_1_1basic__client.html#a9dd11900baa797fded499766bde8b81e", null ], + [ "client_st", "classasync__mqtt_1_1basic__client.html#a0bb29717d22dda60a005f97c3a24b853", null ] +]; \ No newline at end of file diff --git a/doc/api/client_8hpp.html b/doc/api/client_8hpp.html new file mode 100644 index 000000000..0505d37d1 --- /dev/null +++ b/doc/api/client_8hpp.html @@ -0,0 +1,127 @@ + + + + + + + +async_mqtt: /home/kondo/work/async_mqtt/include/async_mqtt/client.hpp File Reference + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
async_mqtt 5.0.0 +
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+ +
client.hpp File Reference
+
+
+
#include <async_mqtt/endpoint.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/key.hpp>
+#include <boost/preprocessor/cat.hpp>
+
+

Go to the source code of this file.

+ + + + + + + + +

+Classes

class  async_mqtt::basic_client< Version, Strand, NextLayer >
 MQTT client for casual usecases. More...
 
struct  async_mqtt::basic_client< Version, Strand, NextLayer >::pubres_t
 publish completion handler parameter class More...
 
+
+
+ + + + diff --git a/doc/api/client_8hpp.js b/doc/api/client_8hpp.js new file mode 100644 index 000000000..3edff8417 --- /dev/null +++ b/doc/api/client_8hpp.js @@ -0,0 +1,5 @@ +var client_8hpp = +[ + [ "async_mqtt::basic_client< Version, Strand, NextLayer >", "classasync__mqtt_1_1basic__client.html", "classasync__mqtt_1_1basic__client" ], + [ "async_mqtt::basic_client< Version, Strand, NextLayer >::pubres_t", "structasync__mqtt_1_1basic__client_1_1pubres__t.html", "structasync__mqtt_1_1basic__client_1_1pubres__t" ] +]; \ No newline at end of file diff --git a/doc/api/client_8hpp_source.html b/doc/api/client_8hpp_source.html new file mode 100644 index 000000000..e134951b2 --- /dev/null +++ b/doc/api/client_8hpp_source.html @@ -0,0 +1,830 @@ + + + + + + + +async_mqtt: /home/kondo/work/async_mqtt/include/async_mqtt/client.hpp Source File + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
async_mqtt 5.0.0 +
+
+
+ + + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
client.hpp
+
+
+Go to the documentation of this file.
1// Copyright Takatoshi Kondo 2024
+
2//
+
3// Distributed under the Boost Software License, Version 1.0.
+
4// (See accompanying file LICENSE_1_0.txt or copy at
+
5// http://www.boost.org/LICENSE_1_0.txt)
+
6
+
7#if !defined(ASYNC_MQTT_CLIENT_HPP)
+
8#define ASYNC_MQTT_CLIENT_HPP
+
9
+ +
11
+
12#include <boost/multi_index_container.hpp>
+
13#include <boost/multi_index/ordered_index.hpp>
+
14#include <boost/multi_index/key.hpp>
+
15#include <boost/preprocessor/cat.hpp>
+
16
+
18
+
19namespace async_mqtt {
+
20
+
21namespace detail {
+
22
+
23#define ASYNC_MQTT_PACKET_TYPE_GETTER(packet) \
+
24 template <protocol_version Ver> \
+
25 struct BOOST_PP_CAT(meta_,packet) { \
+
26 using type = v5::BOOST_PP_CAT(packet, _packet); \
+
27 }; \
+
28 template <> \
+
29 struct BOOST_PP_CAT(meta_,packet)<protocol_version::v3_1_1> { \
+
30 using type = v3_1_1::BOOST_PP_CAT(packet, _packet); \
+
31 };
+
32
+
33ASYNC_MQTT_PACKET_TYPE_GETTER(connect)
+
34ASYNC_MQTT_PACKET_TYPE_GETTER(connack)
+
35ASYNC_MQTT_PACKET_TYPE_GETTER(subscribe)
+
36ASYNC_MQTT_PACKET_TYPE_GETTER(suback)
+
37ASYNC_MQTT_PACKET_TYPE_GETTER(unsubscribe)
+
38ASYNC_MQTT_PACKET_TYPE_GETTER(unsuback)
+
39ASYNC_MQTT_PACKET_TYPE_GETTER(publish)
+
40ASYNC_MQTT_PACKET_TYPE_GETTER(puback)
+
41ASYNC_MQTT_PACKET_TYPE_GETTER(pubrec)
+
42ASYNC_MQTT_PACKET_TYPE_GETTER(pubrel)
+
43ASYNC_MQTT_PACKET_TYPE_GETTER(pubcomp)
+
44ASYNC_MQTT_PACKET_TYPE_GETTER(pingreq)
+
45ASYNC_MQTT_PACKET_TYPE_GETTER(pingresp)
+
46ASYNC_MQTT_PACKET_TYPE_GETTER(disconnect)
+
47
+
48#undef ASYNC_MQTT_PACKET_TYPE_GETTER
+
49
+
50#define ASYNC_MQTT_PACKET_TYPE(packet) \
+
51 using BOOST_PP_CAT(packet, _packet) = typename BOOST_PP_CAT(detail::meta_, packet<Version>::type);
+
52
+
53} // namespace detail
+
54
+
62template <protocol_version Version, template <typename> typename Strand, typename NextLayer>
+
+ + +
65 using ep_type_sp = std::shared_ptr<ep_type>;
+
66
+
67
+
68 ASYNC_MQTT_PACKET_TYPE(connect)
+
69 ASYNC_MQTT_PACKET_TYPE(connack)
+
70 ASYNC_MQTT_PACKET_TYPE(subscribe)
+
71 ASYNC_MQTT_PACKET_TYPE(suback)
+
72 ASYNC_MQTT_PACKET_TYPE(unsubscribe)
+
73 ASYNC_MQTT_PACKET_TYPE(unsuback)
+
74 ASYNC_MQTT_PACKET_TYPE(publish)
+
75 ASYNC_MQTT_PACKET_TYPE(puback)
+
76 ASYNC_MQTT_PACKET_TYPE(pubrec)
+
77 ASYNC_MQTT_PACKET_TYPE(pubrel)
+
78 ASYNC_MQTT_PACKET_TYPE(pubcomp)
+
79 ASYNC_MQTT_PACKET_TYPE(pingreq)
+
80 ASYNC_MQTT_PACKET_TYPE(pingresp)
+
81 ASYNC_MQTT_PACKET_TYPE(disconnect)
+
82
+
83#undef ASYNC_MQTT_PACKET_TYPE
+
84
+
85public:
+
86 using packet_id_t = typename ep_type::packet_id_t;
+
87 using strand_type = typename ep_type::strand_type;
+ +
96
+
104 template <typename... Args>
+
+ +
106 Args&&... args
+
107 ): ep_{ep_type::create(Version, std::forward<Args>(args)...)}
+
108 {
+
109 ep_->set_auto_pub_response(true);
+
110 ep_->set_auto_ping_response(true);
+
111 }
+
+
112
+
113
+
120 template <typename CompletionToken>
+
+
121 auto start(
+
122 connect_packet packet,
+ +
124 ) {
+
125 return as::async_initiate<
+ +
127 void(error_code const& ec, optional<connack_packet>)
+
128 >(
+
129 [this](
+ +
131 connect_packet&& packet
+
132 ) {
+
133 ep_->send(
+
134 force_move(packet),
+
135 [this, completion_handler = force_move(completion_handler)]
+
136 (auto const& se) mutable {
+
137 if (se) {
+
138 force_move(completion_handler)(se.code(), nullopt);
+
139 return;
+
140 }
+
141 auto tim = std::make_shared<as::steady_timer>(ep_->strand());
+
142 tim->expires_at(std::chrono::steady_clock::time_point::max());
+
143 pid_tim_pv_res_col_.emplace(tim);
+
144 recv_loop();
+
145 tim->async_wait(
+
146 [this, tim, completion_handler = force_move(completion_handler)]
+
147 (error_code const& /*ec*/) mutable {
+
148 auto& idx = pid_tim_pv_res_col_.template get<tag_tim>();
+
149 auto it =idx.find(tim);
+
150 if (it != idx.end()) {
+
151 auto pv = it->pv;
+
152 idx.erase(it);
+
153 if (auto *p = pv->template get_if<connack_packet>()) {
+
154 force_move(completion_handler)(error_code{}, *p);
+
155 }
+
156 else {
+
157 force_move(completion_handler)(
+
158 errc::make_error_code(sys::errc::protocol_error),
+
159 nullopt
+
160 );
+
161 }
+
162 }
+
163 }
+
164 );
+
165 }
+
166 );
+
167 },
+
168 token,
+
169 force_move(packet)
+
170 );
+
171 }
+
+
172
+
179 template <typename CompletionToken>
+
+ +
181 subscribe_packet packet,
+ +
183 ) {
+
184 return as::async_initiate<
+ +
186 void(error_code const& ec, optional<suback_packet>)
+
187 >(
+
188 [this](
+ +
190 subscribe_packet&& packet
+
191 ) {
+
192 auto pid = packet.packet_id();
+
193 ep_->send(
+
194 force_move(packet),
+
195 [this, pid, completion_handler = force_move(completion_handler)]
+
196 (auto const& se) mutable {
+
197 if (se) {
+
198 force_move(completion_handler)(se.code(), nullopt);
+
199 return;
+
200 }
+
201 auto tim = std::make_shared<as::steady_timer>(ep_->strand());
+
202 tim->expires_at(std::chrono::steady_clock::time_point::max());
+
203 pid_tim_pv_res_col_.emplace(pid, tim);
+
204 tim->async_wait(
+
205 [this, tim, completion_handler = force_move(completion_handler)]
+
206 (error_code const& /*ec*/) mutable {
+
207 auto& idx = pid_tim_pv_res_col_.template get<tag_tim>();
+
208 auto it = idx.find(tim);
+
209 if (it != idx.end()) {
+
210 auto pv = it->pv;
+
211 idx.erase(it);
+
212 if (auto *p = pv->template get_if<suback_packet>()) {
+
213 force_move(completion_handler)(error_code{}, *p);
+
214 }
+
215 else {
+
216 force_move(completion_handler)(
+
217 errc::make_error_code(sys::errc::protocol_error),
+
218 nullopt
+
219 );
+
220 }
+
221 }
+
222 }
+
223 );
+
224 }
+
225 );
+
226 },
+
227 token,
+
228 force_move(packet)
+
229 );
+
230 }
+
+
231
+
238 template <typename CompletionToken>
+
+ +
240 unsubscribe_packet packet,
+ +
242 ) {
+
243 return as::async_initiate<
+ +
245 void(error_code const& ec, optional<unsuback_packet>)
+
246 >(
+
247 [this](
+ +
249 unsubscribe_packet&& packet
+
250 ) {
+
251 auto pid = packet.packet_id();
+
252 ep_->send(
+
253 force_move(packet),
+
254 [this, pid, completion_handler = force_move(completion_handler)]
+
255 (auto const& se) mutable {
+
256 if (se) {
+
257 force_move(completion_handler)(se.code(), nullopt);
+
258 return;
+
259 }
+
260 auto tim = std::make_shared<as::steady_timer>(ep_->strand());
+
261 tim->expires_at(std::chrono::steady_clock::time_point::max());
+
262 pid_tim_pv_res_col_.emplace(pid, tim);
+
263 tim->async_wait(
+
264 [this, tim, completion_handler = force_move(completion_handler)]
+
265 (error_code const& /*ec*/) mutable {
+
266 auto& idx = pid_tim_pv_res_col_.template get<tag_tim>();
+
267 auto it = idx.find(tim);
+
268 if (it != idx.end()) {
+
269 auto pv = it->pv;
+
270 idx.erase(it);
+
271 if (auto *p = pv->template get_if<unsuback_packet>()) {
+
272 force_move(completion_handler)(error_code{}, *p);
+
273 }
+
274 else {
+
275 force_move(completion_handler)(
+
276 errc::make_error_code(sys::errc::protocol_error),
+
277 nullopt
+
278 );
+
279 }
+
280 }
+
281 }
+
282 );
+
283 }
+
284 );
+
285 },
+
286 token,
+
287 force_move(packet)
+
288 );
+
289 }
+
+
290
+
300 template <typename CompletionToken>
+
+ +
302 publish_packet packet,
+ +
304 ) {
+
305 return as::async_initiate<
+ +
307 void(error_code const& ec, pubres_t res)
+
308 >(
+
309 [this](
+ +
311 publish_packet&& packet
+
312 ) {
+
313 auto pid = packet.packet_id();
+
314 ep_->send(
+
315 force_move(packet),
+
316 [this, pid, completion_handler = force_move(completion_handler)]
+
317 (auto const& se) mutable {
+
318 if (se) {
+
319 force_move(completion_handler)(se.code(), pubres_t{});
+
320 return;
+
321 }
+
322 auto tim = std::make_shared<as::steady_timer>(ep_->strand());
+
323 tim->expires_at(std::chrono::steady_clock::time_point::max());
+
324 if (pid == 0) {
+
325 // QoS: at_most_once
+
326 force_move(completion_handler)(se.code(), pubres_t{});
+
327 return;
+
328 }
+
329 pid_tim_pv_res_col_.emplace(pid, tim);
+
330 tim->async_wait(
+
331 [this, tim, completion_handler = force_move(completion_handler)]
+
332 (error_code const& /*ec*/) mutable {
+
333 auto& idx = pid_tim_pv_res_col_.template get<tag_tim>();
+
334 auto it = idx.find(tim);
+
335 if (it != idx.end()) {
+
336 auto res = it->res;
+
337 idx.erase(it);
+
338 force_move(completion_handler)(error_code{}, res);
+
339 }
+
340 }
+
341 );
+
342 }
+
343 );
+
344 },
+
345 token,
+
346 force_move(packet)
+
347 );
+
348 }
+
+
349
+
356 template <typename CompletionToken>
+
+ +
358 disconnect_packet packet,
+ +
360 ) {
+
361 return as::async_initiate<
+ +
363 void(error_code const& ec)
+
364 >(
+
365 [this](
+ +
367 disconnect_packet&& packet
+
368 ) {
+
369 ep_->send(
+
370 force_move(packet),
+ +
372 (auto const& se) mutable {
+
373 force_move(completion_handler)(se.code());
+
374 }
+
375 );
+
376 },
+
377 token,
+
378 force_move(packet)
+
379 );
+
380 }
+
+
381
+
387 template<typename CompletionToken>
+
388 auto
+
+ +
390 return ep_->close(std::forward<CompletionToken>(token));
+
391 }
+
+
392
+
399 template <typename CompletionToken>
+
+
400 auto recv(
+ +
402 ) {
+
403 return as::async_initiate<
+ + +
406 >(
+
407 [this](
+ +
409 ) {
+
410 as::dispatch(
+
411 as::bind_executor(
+
412 ep_->strand(),
+
413 [this, completion_handler = force_move(completion_handler)]
+
414 () mutable {
+ +
416 [this, completion_handler = force_move(completion_handler)]
+
417 () mutable {
+
418 auto [ec, publish_opt, disconnect_opt] = recv_queue_.front();
+
419 recv_queue_.pop_front();
+
420 force_move(completion_handler)(
+
421 ec,
+
422 force_move(publish_opt),
+
423 force_move(disconnect_opt)
+
424 );
+
425 };
+
426 if (recv_queue_.empty()) {
+
427 auto tim = std::make_shared<as::steady_timer>(ep_->strand());
+
428 tim_notify_publish_recv_.expires_at(std::chrono::steady_clock::time_point::max());
+
429 tim_notify_publish_recv_.async_wait(
+ +
431 (error_code const& /*ec*/) mutable {
+ +
433 }
+
434 );
+
435 }
+
436 else {
+ +
438 }
+
439 }
+
440 )
+
441 );
+
442 },
+
443 token
+
444 );
+
445 }
+
+
446
+
+
451 as::any_io_executor get_executor() const {
+
452 return ep_->strand();
+
453 }
+
+
454
+
+
459 strand_type const& strand() const {
+
460 return ep_->strand();
+
461 }
+
+
462
+
+
467 strand_type& strand() {
+
468 return ep_->strand();
+
469 }
+
+
470
+
+
475 bool in_strand() const {
+
476 return ep_->in_strand();
+
477 }
+
+
478
+
+
483 auto const& next_layer() const {
+
484 return ep_->next_layer();
+
485 }
+
+
+
490 auto& next_layer() {
+
491 return ep_->next_layer();
+
492 }
+
+
493
+
+
498 auto const& lowest_layer() const {
+
499 return ep_->lowest_layer();
+
500 }
+
+
+
505 auto& lowest_layer() {
+
506 return ep_->lowest_layer();
+
507 }
+
+
508
+
+ +
517 ep_->set_auto_map_topic_alias_send(val);
+
518 }
+
+
519
+
+ +
528 ep_->set_auto_replace_topic_alias_send(val);
+
529 }
+
+
530
+
+ +
541 ep_->set_pingresp_recv_timeout_ms(ms);
+
542 }
+
+
543
+
+
553 void set_bulk_write(bool val) {
+
554 ep_->set_bulk_write(val);
+
555 }
+
+
556
+
562 template <typename CompletionToken>
+
+ +
564 return ep_->acquire_unique_packet_id(std::forward<CompletionToken>(token));
+
565 }
+
+
566
+
573 template <typename CompletionToken>
+
574 auto
+
+ + +
577 ) {
+
578 return ep_->acquire_unique_packet_id_wait_until(std::forward<CompletionToken>(token));
+
579 }
+
+
580
+
587 template <typename CompletionToken>
+
+
588 auto register_packet_id(packet_id_t pid, CompletionToken&& token) {
+
589 return ep_->register_packet_id(pid, std::forward<CompletionToken>(token));
+
590 }
+
+
591
+
598 template <typename CompletionToken>
+
+
599 auto release_packet_id(packet_id_t pid, CompletionToken&& token) {
+
600 return ep_->release_packet_id(pid, std::forward<CompletionToken>(token));
+
601 }
+
+
602
+
+ +
609 return ep_->acquire_unique_packet_id();
+
610 }
+
+
611
+
+
618 bool register_packet_id(packet_id_t pid) {
+
619 return ep_->register_packet_id(pid);
+
620 }
+
+
621
+
+
627 void release_packet_id(packet_id_t pid) {
+
628 ep_->release_packet_id(pid);
+
629 }
+
+
630
+
631private:
+
632
+
633 void recv_loop() {
+
634 ep_->recv(
+
635 [this]
+
636 (packet_variant pv) mutable {
+
637 pv.visit(
+
638 overload {
+
639 [&](connack_packet& p) {
+
640 auto& idx = pid_tim_pv_res_col_.template get<tag_pid>();
+
641 auto it = idx.find(0);
+
642 if (it != idx.end()) {
+
643 const_cast<optional<packet_variant>&>(it->pv).emplace(p);
+
644 it->tim->cancel();
+
645 recv_loop();
+
646 }
+
647 },
+
648 [&](suback_packet& p) {
+
649 auto& idx = pid_tim_pv_res_col_.template get<tag_pid>();
+
650 auto it = idx.find(p.packet_id());
+
651 if (it != idx.end()) {
+
652 const_cast<optional<packet_variant>&>(it->pv).emplace(p);
+
653 it->tim->cancel();
+
654 }
+
655 recv_loop();
+
656 },
+
657 [&](unsuback_packet& p) {
+
658 auto& idx = pid_tim_pv_res_col_.template get<tag_pid>();
+
659 auto it = idx.find(p.packet_id());
+
660 if (it != idx.end()) {
+
661 const_cast<optional<packet_variant>&>(it->pv).emplace(p);
+
662 it->tim->cancel();
+
663 }
+
664 recv_loop();
+
665 },
+
666 [&](publish_packet& p) {
+
667 recv_queue_.emplace_back(force_move(p));
+
668 tim_notify_publish_recv_.cancel();
+
669 recv_loop();
+
670 },
+
671 [&](puback_packet& p) {
+
672 auto& idx = pid_tim_pv_res_col_.template get<tag_pid>();
+
673 auto it = idx.find(p.packet_id());
+
674 if (it != idx.end()) {
+
675 const_cast<optional<puback_packet>&>(it->res.puback_opt).emplace(p);
+
676 it->tim->cancel();
+
677 }
+
678 recv_loop();
+
679 },
+
680 [&](pubrec_packet& p) {
+
681 auto& idx = pid_tim_pv_res_col_.template get<tag_pid>();
+
682 auto it = idx.find(p.packet_id());
+
683 if (it != idx.end()) {
+
684 const_cast<optional<pubrec_packet>&>(it->res.pubrec_opt).emplace(p);
+
685 if constexpr (Version == protocol_version::v5) {
+
686 if (is_error(p.code())) {
+
687 it->tim->cancel();
+
688 }
+
689 }
+
690 }
+
691 recv_loop();
+
692 },
+
693 [&](pubcomp_packet& p) {
+
694 auto& idx = pid_tim_pv_res_col_.template get<tag_pid>();
+
695 auto it = idx.find(p.packet_id());
+
696 if (it != idx.end()) {
+
697 const_cast<optional<pubcomp_packet>&>(it->res.pubcomp_opt).emplace(p);
+
698 it->tim->cancel();
+
699 }
+
700 recv_loop();
+
701 },
+
702 [&](disconnect_packet& p) {
+
703 recv_queue_.emplace_back(force_move(p));
+
704 tim_notify_publish_recv_.cancel();
+
705 recv_loop();
+
706 },
+
707 [&](system_error const& se) {
+
708 recv_queue_.emplace_back(se.code());
+
709 tim_notify_publish_recv_.cancel();
+
710 },
+
711 [&](auto const&) {
+
712 recv_loop();
+
713 }
+
714 }
+
715 );
+
716 }
+
717 );
+
718 }
+
719
+
720private:
+
721
+
722 struct pid_tim_pv_res {
+
723 pid_tim_pv_res(
+
724 packet_id_t pid,
+
725 std::shared_ptr<as::steady_timer> tim
+
726 ): pid{pid},
+
727 tim{force_move(tim)}
+
728 {
+
729 }
+
730 pid_tim_pv_res(
+
731 std::shared_ptr<as::steady_timer> tim
+
732 ): tim{force_move(tim)}
+
733 {
+
734 }
+
735 packet_id_t pid = 0;
+
736 std::shared_ptr<as::steady_timer> tim;
+
737 optional<packet_variant> pv;
+
738 pubres_t res;
+
739 };
+
740 struct tag_pid {};
+
741 struct tag_tim {};
+
742
+
743 using mi_pid_tim_pv_res = mi::multi_index_container<
+
744 pid_tim_pv_res,
+
745 mi::indexed_by<
+
746 mi::ordered_unique<
+
747 mi::tag<tag_pid>,
+
748 mi::key<&pid_tim_pv_res::pid>
+
749 >,
+
750 mi::ordered_unique<
+
751 mi::tag<tag_tim>,
+
752 mi::key<&pid_tim_pv_res::tim>
+
753 >
+
754 >
+
755 >;
+
756
+
757 struct recv_t {
+
758 recv_t(publish_packet packet)
+
759 :publish_opt{force_move(packet)}
+
760 {
+
761 }
+
762 recv_t(disconnect_packet packet)
+
763 :disconnect_opt{force_move(packet)}
+
764 {
+
765 }
+
766 recv_t(error_code ec)
+
767 :ec{ec}
+
768 {
+
769 }
+
770 error_code ec = error_code{};
+
771 optional<publish_packet> publish_opt;
+
772 optional<disconnect_packet> disconnect_opt;
+
773 };
+
774
+
775 ep_type_sp ep_;
+
776 mi_pid_tim_pv_res pid_tim_pv_res_col_;
+
777 std::deque<recv_t> recv_queue_;
+
778 as::steady_timer tim_notify_publish_recv_{ep_->strand()};
+
779};
+
+
780
+
781
+
788template <protocol_version Version, typename NextLayer>
+ +
790
+
797template <protocol_version Version, typename NextLayer>
+ +
799
+
800} // namespace async_mqtt
+
801
+
802#endif // ASYNC_MQTT_CLIENT_HPP
+
MQTT client for casual usecases.
Definition client.hpp:63
+
auto const & lowest_layer() const
lowest_layer getter
Definition client.hpp:498
+
auto unsubscribe(unsubscribe_packet packet, CompletionToken &&token)
send UNSUBSCRIBE packet
Definition client.hpp:239
+
void release_packet_id(packet_id_t pid)
release packet_id.
Definition client.hpp:627
+
auto disconnect(disconnect_packet packet, CompletionToken &&token)
send DISCONNECT packet
Definition client.hpp:357
+
auto const & next_layer() const
next_layer getter
Definition client.hpp:483
+
auto & next_layer()
next_layer getter
Definition client.hpp:490
+
strand_type const & strand() const
strand getter
Definition client.hpp:459
+
auto close(CompletionToken &&token)
close the underlying connection
Definition client.hpp:389
+
void set_auto_replace_topic_alias_send(bool val)
auto replace topic with corresponding topic alias on send PUBLISH packet. Registering topic alias nee...
Definition client.hpp:527
+
strand_type & strand()
strand getter
Definition client.hpp:467
+
bool register_packet_id(packet_id_t pid)
register packet_id.
Definition client.hpp:618
+
auto start(connect_packet packet, CompletionToken &&token)
send CONNECT packet and start packet receive loop
Definition client.hpp:121
+
auto register_packet_id(packet_id_t pid, CompletionToken &&token)
acuire unique packet_id. If packet_id is fully acquired, then wait until released.
Definition client.hpp:588
+
as::any_io_executor get_executor() const
executor getter
Definition client.hpp:451
+
auto & lowest_layer()
lowest_layer getter
Definition client.hpp:505
+
bool in_strand() const
strand checker
Definition client.hpp:475
+
auto release_packet_id(packet_id_t pid, CompletionToken &&token)
register packet_id.
Definition client.hpp:599
+
auto acquire_unique_packet_id(CompletionToken &&token)
acuire unique packet_id.
Definition client.hpp:563
+
auto recv(CompletionToken &&token)
receive PUBLISH or DISCONNECT packet users CANNOT call recv() before the previous recv()'s Completion...
Definition client.hpp:400
+
basic_client(Args &&... args)
constructor
Definition client.hpp:105
+
auto publish(publish_packet packet, CompletionToken &&token)
send PUBLISH packet
Definition client.hpp:301
+
void set_auto_map_topic_alias_send(bool val)
auto map (allocate) topic alias on send PUBLISH packet. If all topic aliases are used,...
Definition client.hpp:516
+
optional< packet_id_t > acquire_unique_packet_id()
acuire unique packet_id.
Definition client.hpp:608
+
void set_bulk_write(bool val)
Set bulk write mode. If true, then concatenate multiple packets' const buffer sequence when send() is...
Definition client.hpp:553
+
void set_pingresp_recv_timeout_ms(std::size_t ms)
Set timeout for receiving PINGRESP packet after PINGREQ packet is sent. If the timer is fired,...
Definition client.hpp:540
+
auto subscribe(subscribe_packet packet, CompletionToken &&token)
send SUBSCRIBE packet
Definition client.hpp:180
+
auto acquire_unique_packet_id_wait_until(CompletionToken &&token)
acuire unique packet_id. If packet_id is fully acquired, then wait until released.
Definition client.hpp:575
+
Definition packet_variant.hpp:49
+ +
publish completion handler parameter class
Definition client.hpp:91
+
optional< puback_packet > puback_opt
puback_packet as the response when you send QoS1 publish
Definition client.hpp:92
+
optional< pubrec_packet > pubrec_opt
pubrec_packet as the response when you send QoS2 publish
Definition client.hpp:93
+
optional< pubcomp_packet > pubcomp_opt
pubcomp_packet as the response when you send QoS2 publish
Definition client.hpp:94
+
+
+ + + + diff --git a/doc/api/inherit_graph_45.map b/doc/api/inherit_graph_45.map new file mode 100644 index 000000000..a5f8ec3c8 --- /dev/null +++ b/doc/api/inherit_graph_45.map @@ -0,0 +1,3 @@ + + + diff --git a/doc/api/inherit_graph_45.md5 b/doc/api/inherit_graph_45.md5 new file mode 100644 index 000000000..474e97c63 --- /dev/null +++ b/doc/api/inherit_graph_45.md5 @@ -0,0 +1 @@ +bd3f50aeea5e91b81573f32915224e27 \ No newline at end of file diff --git a/doc/api/inherit_graph_45.png b/doc/api/inherit_graph_45.png new file mode 100644 index 0000000000000000000000000000000000000000..8d03db7800ee5a85068ba7efce0b4b7a4b068281 GIT binary patch literal 3808 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 oK`SQKaFn@+_kX9t2e50rIOj@4_ + + diff --git a/doc/api/inherit_graph_46.md5 b/doc/api/inherit_graph_46.md5 new file mode 100644 index 000000000..34f5ddc4c --- /dev/null +++ b/doc/api/inherit_graph_46.md5 @@ -0,0 +1 @@ +515435d6d598f904ff2c740b99417297 \ No newline at end of file diff --git a/doc/api/inherit_graph_46.png b/doc/api/inherit_graph_46.png new file mode 100644 index 0000000000000000000000000000000000000000..c13499ceb049a6ed3deccce4bcaef9edb4ad4853 GIT binary patch literal 3420 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 literal 0 HcmV?d00001 diff --git a/doc/api/search/files_4.js b/doc/api/search/files_4.js new file mode 100644 index 000000000..84e05eead --- /dev/null +++ b/doc/api/search/files_4.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['store_5fpacket_5fvariant_2ehpp_0',['store_packet_variant.hpp',['../store__packet__variant_8hpp.html',1,'']]], + ['suback_5freturn_5fcode_2ehpp_1',['suback_return_code.hpp',['../suback__return__code_8hpp.html',1,'']]], + ['subopts_2ehpp_2',['subopts.hpp',['../subopts_8hpp.html',1,'']]] +]; diff --git a/doc/api/search/typedefs_7.js b/doc/api/search/typedefs_7.js new file mode 100644 index 000000000..69f6e7748 --- /dev/null +++ b/doc/api/search/typedefs_7.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['ws_0',['ws',['../predefined__underlying__layer_8hpp.html#aa5faa493592170b84fe10807b67f2a7a',1,'async_mqtt::protocol']]], + ['wss_1',['wss',['../predefined__underlying__layer_8hpp.html#a3f43ad7309eefaa8f5e4dde369e19212',1,'async_mqtt::protocol']]] +]; diff --git a/doc/api/structasync__mqtt_1_1basic__client_1_1pubres__t-members.html b/doc/api/structasync__mqtt_1_1basic__client_1_1pubres__t-members.html new file mode 100644 index 000000000..bc12be658 --- /dev/null +++ b/doc/api/structasync__mqtt_1_1basic__client_1_1pubres__t-members.html @@ -0,0 +1,113 @@ + + + + + + + +async_mqtt: Member List + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
async_mqtt 5.0.0 +
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
async_mqtt::basic_client< Version, Strand, NextLayer >::pubres_t Member List
+
+ +
+ + + + diff --git a/doc/api/structasync__mqtt_1_1basic__client_1_1pubres__t.html b/doc/api/structasync__mqtt_1_1basic__client_1_1pubres__t.html new file mode 100644 index 000000000..0ece5ae92 --- /dev/null +++ b/doc/api/structasync__mqtt_1_1basic__client_1_1pubres__t.html @@ -0,0 +1,138 @@ + + + + + + + +async_mqtt: async_mqtt::basic_client< Version, Strand, NextLayer >::pubres_t Struct Reference + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+
async_mqtt 5.0.0 +
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+ +
async_mqtt::basic_client< Version, Strand, NextLayer >::pubres_t Struct Reference
+
+
+ +

publish completion handler parameter class + More...

+ +

#include <client.hpp>

+ + + + + + + + + + + +

+Public Attributes

+optional< puback_packet > puback_opt
 puback_packet as the response when you send QoS1 publish
 
+optional< pubrec_packet > pubrec_opt
 pubrec_packet as the response when you send QoS2 publish
 
+optional< pubcomp_packet > pubcomp_opt
 pubcomp_packet as the response when you send QoS2 publish
 
+

Detailed Description

+
template<protocol_version Version, template< typename > typename Strand, typename NextLayer>
+struct async_mqtt::basic_client< Version, Strand, NextLayer >::pubres_t

publish completion handler parameter class

+

The documentation for this struct was generated from the following file:
    +
  • /home/kondo/work/async_mqtt/include/async_mqtt/client.hpp
  • +
+
+
+ + + + diff --git a/doc/api/structasync__mqtt_1_1basic__client_1_1pubres__t.js b/doc/api/structasync__mqtt_1_1basic__client_1_1pubres__t.js new file mode 100644 index 000000000..eff2503fc --- /dev/null +++ b/doc/api/structasync__mqtt_1_1basic__client_1_1pubres__t.js @@ -0,0 +1,6 @@ +var structasync__mqtt_1_1basic__client_1_1pubres__t = +[ + [ "puback_opt", "structasync__mqtt_1_1basic__client_1_1pubres__t.html#a2bd405a21ad6a03ede0e6088bb0ffba9", null ], + [ "pubcomp_opt", "structasync__mqtt_1_1basic__client_1_1pubres__t.html#ac2c7b366fadb0e4a2f3286f4dbae314f", null ], + [ "pubrec_opt", "structasync__mqtt_1_1basic__client_1_1pubres__t.html#a6f31d3efe86904177e1f8baedae50a56", null ] +]; \ No newline at end of file diff --git a/doc/tutorial/client.html b/doc/tutorial/client.html new file mode 100644 index 000000000..8b841984e --- /dev/null +++ b/doc/tutorial/client.html @@ -0,0 +1,654 @@ + + + + + + + +Client + + + + + +
+
+

Create client

+
+
+

First, choose MQTT protocol version (v3.1.1 or v5), and then choose underlying layer.

+
+
+
+layer structure +
+
+
+
+
+

mqtt

+
+
+
+
    as::io_context ioc;
+
+    // To get IP address from hostname
+    as::ip::tcp::socket resolve_sock{ioc};
+    as::ip::tcp::resolver res{resolve_sock.get_executor()};
+
+    am::client<am::protocol_version::v3_1_1, am::protocol::mqtt> amcl{
+        ioc.get_executor() // args for underlying layer (mqtt)
+        // mqtt is as::basic_stream_socket<as::ip::tcp, as::io_context::executor_type>
+    );
+
+
+
+
+
+

mqtts

+
+
+
+
    as::io_context ioc;
+
+    // To get IP address from hostname
+    as::ip::tcp::socket resolve_sock{ioc};
+    as::ip::tcp::resolver res{resolve_sock.get_executor()};
+
+    am::tls::context ctx{am::tls::context::tlsv12};
+    ctx.set_verify_mode(am::tls::verify_none);
+    // If you want to check server certificate, set cacert as follows.
+    // ctx.load_verify_file(cacert);
+
+    am::client<am::protocol_version::v5, am::protocol::mqtts> amcl{
+        ioc.get_executor(),  // args for underlying layer (as::ssl::stream<mqtt>)
+        ctx
+    );
+
+
+
+ + + + + +
+
Note
+
+tls is namespace alias of boost::asio::ssl by default. +
+
+
+
+
+

ws

+
+
+
+
    as::io_context ioc;
+
+    // To get IP address from hostname
+    as::ip::tcp::socket resolve_sock{ioc};
+    as::ip::tcp::resolver res{resolve_sock.get_executor()};
+
+    am::client<am::protocol_version::v3_1_1, am::protocol::ws> amcl{
+    auto amep = am::endpoint<am::role::client, am::protocol::ws>::create(
+        ioc.get_executor()  // args for underlying layer (bs::websocket::stream<mqtt>)
+    );
+
+
+
+
+
+

wss

+
+
+
+
    as::io_context ioc;
+
+    // To get IP address from hostname
+    as::ip::tcp::socket resolve_sock{ioc};
+    as::ip::tcp::resolver res{resolve_sock.get_executor()};
+
+    am::tls::context ctx{am::tls::context::tlsv12};
+    ctx.set_verify_mode(am::tls::verify_none);
+    // If you want to check server certificate, set cacert as follows.
+    // ctx.load_verify_file(cacert);
+
+    am::client<am::protocol_version::v3_1_1, am::protocol::wss> amcl{
+        ioc.get_executor(),  // args for underlying layer ( bs::websocket::stream<mqtts>)
+        ctx                  // mqtts is as::ssl::stream<mqtt>
+    );
+
+
+
+
+
+

Layer access

+
+ +++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Layer accessmqttmqttswswss

next_layer()

TCP stream

TLS stream

WS stream

WS stream

next_layer().next_layer()

-

TCP stream

TCP stream

TLS stream

next_layer().next_layer().next_layer()

-

-

-

TCP stream

lowest_layer()

TCP stream

TCP stream

TCP stream

TCP stream

+
+
+
+

Handshaking underlying layer

+
+
+

You can use underlying handshaking functions as follows:

+
+
+
+
// Underlying TCP connect
+co_await as::async_connect(
+    amcl.next_layer(),
+    eps,
+    as::use_awaitable
+);
+std::cout << "TCP connected" << std::endl;
+
+
+
+

Similarly, handshake TLS, WebSocket layers if needed.

+
+
+
+
+

Send MQTT CONNECT packet and start receive loop

+
+
+

After underlying layers' handshaking is completed, then start MQTT layer connection.

+
+
+

start() funtion

+
+
+
// MQTT connect and receive loop start
+auto connack_opt = co_await amcl.start(
+    am::v5::connect_packet{
+        true,   // clean_session
+        0x1234, // keep_alive
+        am::allocate_buffer("cid1"),
+        am::nullopt, // will
+        am::nullopt, // username set like allocate_buffer("user1"),
+        am::nullopt  // password set like allocate_buffer("pass1")
+    },
+    as::use_awaitable
+);
+if (connack_opt) {
+    std::cout << *connack_opt << std::endl;
+}
+
+
+
+

CompletionToken parameters are error_code and connack_packet (optional). connack_packet has a value only if error_code is success. When you use CompletionToken such as as::use_awaitable, as::use_future, as::deferred, the first error_code is converted to exception. If you want to have the error_code as the return value, you can do as follows:

+
+
+
+
// MQTT connect and receive loop start
+auto [ec, connack_opt] = co_await amcl.start(
+    am::v5::connect_packet{
+        true,   // clean_session
+        0x1234, // keep_alive
+        am::allocate_buffer("cid1"),
+        am::nullopt, // will
+        am::nullopt, // username set like allocate_buffer("user1"),
+        am::nullopt  // password set like allocate_buffer("pass1")
+    },
+    as::as_tuple(as::use_awaitable)
+);
+std::cout << ec.message() << std::endl;
+if (connack_opt) {
+    std::cout << *connack_opt << std::endl;
+}
+
+
+
+
+
+
+

Send SUBSCRIBE/UNSUBSCRIBE and wait SUBACK/UNSUBACK

+
+
+

subscribe() funtion

+
+
+
// subscribe
+// MQTT send subscribe and wait suback
+std::vector<am::topic_subopts> sub_entry{
+    {am::allocate_buffer("topic1"), am::qos::at_most_once},
+    {am::allocate_buffer("topic2"), am::qos::at_least_once},
+    {am::allocate_buffer("topic3"), am::qos::exactly_once},
+};
+auto suback_opt = co_await amcl.subscribe(
+    am::v5::subscribe_packet{
+        *amcl.acquire_unique_packet_id(), // sync version only in strand
+        am::force_move(sub_entry) // sub_entry variable is required to avoid g++ bug
+    },
+    as::use_awaitable
+);
+if (suback_opt) {
+    std::cout << *suback_opt << std::endl;
+}
+
+
+
+

CompletionToken parameters are error_code and suback_packet (optional). suback_packet has a value only if error_code is success.

+
+
+
+

unsubscribe() funtion

+
+
+
// MQTT send unsubscribe and wait unsuback
+std::vector<am::topic_sharename> unsub_entry{
+    {am::allocate_buffer("topic1")},
+    {am::allocate_buffer("topic2")},
+    {am::allocate_buffer("topic3")},
+};
+
+auto unsuback_opt = co_await amcl.unsubscribe(
+    am::v5::unsubscribe_packet{
+        *amcl.acquire_unique_packet_id(), // sync version only in strand
+        am::force_move(unsub_entry) // unsub_entry variable is required to avoid g++ bug
+    },
+    as::use_awaitable
+);
+if (unsuback_opt) {
+    std::cout << *unsuback_opt << std::endl;
+}
+
+
+
+

CompletionToken parameters are error_code and unsuback_packet (optional). unsuback_packet has a value only if error_code is success.

+
+
+
+
+
+

Send PUBLISH packet and wait response

+
+
+

publish() funtion

+
+

Here is a code example that sending QoS0 PUBLISH packet.

+
+
+
+
// MQTT publish QoS0 and wait response (socket write complete)
+auto pubres0 = co_await amcl.publish(
+    am::v5::publish_packet{
+        am::allocate_buffer("topic1"),
+        am::allocate_buffer("payload1"),
+        am::qos::at_most_once
+    },
+    as::use_awaitable
+);
+
+
+
+

CompletionToken parameters are error_code and pubres_t. +When you send QoS0 PUBLISH packet, no response packet is expected, so the CompletionToken is invoked when underlying layer’s async_write operation is finished. +All the members of pubres_t are nullopt.

+
+
+

Here is a code example that sending QoS1 PUBLISH packet.

+
+
+
+
// MQTT publish QoS1 and wait response (puback receive)
+auto pid_pub1_opt = co_await amcl.acquire_unique_packet_id(as::use_awaitable); // async version
+auto pubres1 = co_await amcl.publish(
+    am::v5::publish_packet{
+        *pid_pub1_opt,
+        am::allocate_buffer("topic2"),
+        am::allocate_buffer("payload2"),
+        am::qos::at_least_once
+    },
+    as::use_awaitable
+);
+
+
+
+

In order to create QoS1 PUBLISH packet, you need to acquire packet identifier. The example code above uses acquire_unique_packet_id(). This is asynchnorous version. You can call it form anywhere you want. If all packet id is acquired, the CompletionToken parameter is nullopt. For convenience, sync version acquire_unique_packet_id() exists. When you use callback function approach, it could help keep the code simple. Sync version must be called in the client’s strand. For example, anywhare in the callback function that is registered to client member functions as a CompletionToken(CompletionHandler).

+
+
+

After publish() is completer, puback_opt of pubres_t is set. You can get puback packet.

+
+
+

Here is a code example that sending QoS1 PUBLISH packet.

+
+
+
+
// MQTT publish QoS2 and wait response (pubrec, pubcomp receive)
+auto pid_pub2 = co_await amcl.acquire_unique_packet_id_wait_until(as::use_awaitable); // async version
+auto pubres2 = co_await amcl.publish(
+    am::v5::publish_packet{
+        pid_pub2,
+        am::allocate_buffer("topic3"),
+        am::allocate_buffer("payload3"),
+        am::qos::exactly_once
+    },
+    as::use_awaitable
+);
+
+
+
+

In order to create QoS2 PUBLISH packet, you need to acquire packet identifier. In this example, acquire_unique_packet_id_wait_until() is used. The CompletionToken parameter is packet identifier that not optional. If all packet identifiers are used, the function waits at least one of the packet identifier becomes usable again, and then invokes CompletionToken. It can help keeping user code simple.

+
+
+

After publish() is completer, pubrec_opt and pubcomp_opt of pubres_t are set. You can get pubrec and pubcomp packet.

+
+
+
+
+
+

Receive PUBLISH packet from the broker

+
+
+

recv() funtion

+
+
+
auto [publish_opt, disconnect_opt] = co_await amcl.recv(as::use_awaitable);
+if (publish_opt) {
+    std::cout << *publish_opt << std::endl;
+}
+else if (disconnect_opt) {
+    std::cout << *disconnect_opt << std::endl;
+}
+
+
+
+

After you called start() function, the received PUBLISH packets are stored in the clinet. You can get it using recv() function. If the no packets are stored, recv() waits until PUBLISH packet would be received.

+
+
+

CompletionToken parameters are error_code and publish_packet (optional), and disconnect_packet(optional). publish_packet or disconnect_packet has a value only if error_code is success.

+
+
+
+
+
+

Send DISCONNECT packet

+
+
+

disconnect() funtion

+
+
+
co_await amcl.disconnect(
+    am::v5::disconnect_packet{},
+    as::use_awaitable
+);
+
+
+
+

CompletionToken parameters is error_code. +Sending DISCONNECT packet to the broker starts a glaceful disconnect sequence. The broker sends MQTT will message if needed and then disconnect the network connection from the broker side. And then, the client detects the disconnection, finally close the client side socket.

+
+
+
+
+
+

Close

+
+
+

close() funtion

+
+
+
co_await amcl.close(as::use_awaitable);
+
+
+
+

CompletionToken parameters is nothing. +If you want to close the socket forcibly, you can call close() function. For example, no packets are received from the broker unexpectedly, but the client side doesn’t detect disconnection.

+
+
+
+
+
+

Whole code

+
+ +
+
+
+

Supported Functionality

+
+
+

client supports the following functionalities:

+
+ + +
+
+
+ + + \ No newline at end of file diff --git a/doc/tutorial/non_packet_based.html b/doc/tutorial/non_packet_based.html index 9ef9e63d3..b3807daa7 100644 --- a/doc/tutorial/non_packet_based.html +++ b/doc/tutorial/non_packet_based.html @@ -81,25 +81,29 @@

Non packet based APIs

-

set_auto_pub_response

+

set_auto_pub_response()

If set true, then PUBACK, PUBREC, PUBREL, and PUBCOMP will be sent automatically when the corresponding packet is received.

-

set_auto_ping_response

+

set_auto_ping_response()

If set true, then PINGRESP will be sent automatically when PINGREQ is received.

-

set_auto_map_topic_alias_send

+

set_auto_map_topic_alias_send()

If set true, TopicAlias is automatically acquired and applied on sending PUBLISH packets. The limit is decidec by received TopicAliasMaximum property. If it is 0, no TopicAlias is used. If TopicAlias is fully used, then overwrite the oldest TopicAlias (LRU algorithm).

-

set_auto_replace_topic_alias_send

+

set_auto_replace_topic_alias_send()

It is similar to set_auto_map_topic_alias but not automatically acquired. So you need to register topicalias by yourself. If set true, then TopicAlias is automatically applied if TopicAlias is already registered.

-

set_ping_resp_recv_timeout_ms

+

set_ping_resp_recv_timeout_ms()

Set timer after sending PINGREQ packet. The timer would be cancelled when PINGRESP packet is received. If timer is fired then the connection is disconnected automatically.

+ +

set_bulk_write()

+

Set bulk write mode. If true, then concatenate multiple packets' const buffer sequence when send() is called before the previous send() is not completed. Otherwise, send packet one by one.

+