Skip to content

Commit

Permalink
Refined separate compilation.
Browse files Browse the repository at this point in the history
  • Loading branch information
redboltz committed Jan 17, 2025
1 parent 3315188 commit 7850f44
Show file tree
Hide file tree
Showing 22 changed files with 762 additions and 103 deletions.
2 changes: 2 additions & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ if("cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
ep_cpp20coro_mqtt_client.cpp
)
if(ASYNC_MQTT_BUILD_EXAMPLE_SEPARATE)
add_subdirectory(separate_client_manual)
add_subdirectory(separate_endpoint_manual)
if(ASYNC_MQTT_BUILD_LIB)
add_subdirectory(separate_client)
add_subdirectory(separate_endpoint)
Expand Down
31 changes: 31 additions & 0 deletions example/separate_client_manual/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
project(separate_client_manual)

add_executable(
separate_client_manual
src.cpp
main.cpp
)

# Without this setting added, azure pipelines completely fails to find the boost libraries. No idea why.
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
endif()

target_compile_definitions(separate_client_manual PRIVATE ASYNC_MQTT_SEPARATE_COMPILATION)

if(ASYNC_MQTT_USE_LOG)
target_compile_definitions(
separate_client_manual
PRIVATE
$<IF:$<BOOL:${ASYNC_MQTT_USE_STATIC_BOOST}>,,BOOST_LOG_DYN_LINK>
)
target_link_libraries(
separate_client_manual PRIVATE async_mqtt_iface Boost::log Boost::log_setup
)
endif()

target_compile_definitions(
separate_client_manual
PRIVATE
$<IF:$<BOOL:${ASYNC_MQTT_USE_STATIC_BOOST}>,,BOOST_PROGRAM_OPTIONS_DYN_LINK>
)
216 changes: 216 additions & 0 deletions example/separate_client_manual/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
// Copyright Takatoshi Kondo 2023
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include <iostream>
#include <string>

#include <boost/asio.hpp>

#include <async_mqtt/all.hpp>

namespace as = boost::asio;
namespace am = async_mqtt;

using client_t = am::client<am::protocol_version::v5, am::protocol::mqtt>;

as::awaitable<void>
proc(
client_t& amcl,
std::string_view host,
std::string_view port) {

auto exe = co_await as::this_coro::executor;

std::cout << "start" << std::endl;

try {
// all underlying layer handshaking
// (Resolve hostname, TCP handshake)
co_await amcl.async_underlying_handshake(host, port, as::use_awaitable);

std::cout << "mqtt undlerlying handshaked" << std::endl;

// prepare will message if you need.
am::will will{
"WillTopic1",
"WillMessage1",
am::qos::at_most_once,
{ // properties
am::property::user_property{"key1", "val1"},
am::property::content_type{"text"},
}
};

// MQTT connect and receive loop start
auto connack_opt = co_await amcl.async_start(
am::v5::connect_packet{
true, // clean_start
0x1234, // keep_alive
"", // Client Identifier, empty means generated by the broker
will, // you can pass std::nullopt if you don't want to set the will message
"UserName1",
"Password1"
},
as::use_awaitable
);
if (connack_opt) {
std::cout << *connack_opt << std::endl;
}

// subscribe
// MQTT send subscribe and wait suback
std::vector<am::topic_subopts> sub_entry{
{"topic1", am::qos::at_most_once},
{"topic2", am::qos::at_least_once},
{"topic3", am::qos::exactly_once},
};
auto suback_opt = co_await amcl.async_subscribe(
am::v5::subscribe_packet{
*amcl.acquire_unique_packet_id(), // sync version only works thread safe context
am::force_move(sub_entry)
},
as::use_awaitable
);
if (suback_opt) {
std::cout << *suback_opt << std::endl;
}
auto print_pubres =
[](client_t::pubres_type const& pubres) {
if (pubres.puback_opt) {
std::cout << *pubres.puback_opt << std::endl;
}
if (pubres.pubrec_opt) {
std::cout << *pubres.pubrec_opt << std::endl;
}
if (pubres.pubcomp_opt) {
std::cout << *pubres.pubcomp_opt << std::endl;
}
};

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

// MQTT publish QoS1 and wait response (puback receive)
auto pid_pub1 = co_await amcl.async_acquire_unique_packet_id(as::use_awaitable); // async version
auto pubres1 = co_await amcl.async_publish(
// you can pass v5::publish_packet constructor's args directly
pid_pub1,
"topic2",
"payload2",
am::qos::at_least_once,
as::use_awaitable
);
print_pubres(pubres1);

// recv (coroutine)
for (int i = 0; i != 2; ++i) {
auto pv_opt = co_await amcl.async_recv(as::use_awaitable);
BOOST_ASSERT(pv_opt);
pv_opt->visit(
am::overload{
[&](client_t::publish_packet& p) {
std::cout << p << std::endl;
std::cout << "topic : " << p.topic() << std::endl;
std::cout << "payload : " << p.payload() << std::endl;
},
[&](client_t::disconnect_packet& p) {
std::cout << p << std::endl;
},
[](auto&) {
}
}
);
}
// recv (callback) before sending
amcl.async_recv(
[] (am::error_code ec, std::optional<am::packet_variant> pv_opt) {
std::cout << ec.message() << std::endl;
BOOST_ASSERT(pv_opt);
pv_opt->visit(
am::overload{
[&](client_t::publish_packet& p) {
std::cout << p << std::endl;
std::cout << "topic : " << p.topic() << std::endl;
std::cout << "payload : " << p.payload() << std::endl;
},
[&](client_t::disconnect_packet& p) {
std::cout << p << std::endl;
},
[](auto&) {
}
}
);
}
);

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

// MQTT send unsubscribe and wait unsuback
std::vector<am::topic_sharename> unsub_entry{
"topic1",
"topic2",
"topic3",
};

auto unsuback_opt = co_await amcl.async_unsubscribe(
am::v5::unsubscribe_packet{
*amcl.acquire_unique_packet_id(), // sync version only works thread safe context
am::force_move(unsub_entry)
},
as::use_awaitable
);
if (unsuback_opt) {
std::cout << *unsuback_opt << std::endl;
}

// disconnect
co_await amcl.async_disconnect(
am::v5::disconnect_packet{
am::disconnect_reason_code::disconnect_with_will_message
},
as::use_awaitable
);
std::cout << "finished" << std::endl;
}
catch (boost::system::system_error const& se) {
std::cout << se.code().message() << std::endl;
}
}

int main(int argc, char* argv[]) {
am::setup_log(
am::severity_level::warning,
true // log colored
);
if (argc != 3) {
std::cout << "Usage: " << argv[0] << " host port" << std::endl;
return -1;
}
as::io_context ioc;
auto amcl = client_t{ioc.get_executor()};
as::co_spawn(amcl.get_executor(), proc(amcl, argv[1], argv[2]), as::detached);
ioc.run();
}
13 changes: 13 additions & 0 deletions example/separate_client_manual/src.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright Takatoshi Kondo 2023
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// example: overriding custom instantiate configuration
#define ASYNC_MQTT_PP_ROLE (async_mqtt::role::client)
#define ASYNC_MQTT_PP_SIZE (2)
#define ASYNC_MQTT_PP_PROTOCOL (async_mqtt::protocol::mqtt)

#include <async_mqtt/predefined_layer/mqtt.hpp>
#include <async_mqtt/separate/src_client.hpp>
31 changes: 31 additions & 0 deletions example/separate_endpoint_manual/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
project(separate_endpoint_manual)

add_executable(
separate_endpoint_manual
src.cpp
main.cpp
)

# Without this setting added, azure pipelines completely fails to find the boost libraries. No idea why.
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
endif()

target_compile_definitions(separate_endpoint_manual PRIVATE ASYNC_MQTT_SEPARATE_COMPILATION)

if(ASYNC_MQTT_USE_LOG)
target_compile_definitions(
separate_endpoint_manual
PRIVATE
$<IF:$<BOOL:${ASYNC_MQTT_USE_STATIC_BOOST}>,,BOOST_LOG_DYN_LINK>
)
target_link_libraries(
separate_endpoint_manual PRIVATE async_mqtt_iface Boost::log Boost::log_setup
)
endif()

target_compile_definitions(
separate_endpoint_manual
PRIVATE
$<IF:$<BOOL:${ASYNC_MQTT_USE_STATIC_BOOST}>,,BOOST_PROGRAM_OPTIONS_DYN_LINK>
)
Loading

0 comments on commit 7850f44

Please # to comment.