async_run

Reviewers: ivica

Reviewed By: ivica

Subscribers: korina

Differential Revision: https://repo.mireo.local/D27342
This commit is contained in:
Bruno Iljazovic committed 2024-01-16 13:18:21 +01:00
1 parent 2f6751d162
commit 4f87b27861
29 files changed
+398 -85

No files matched your search

@@ -181,6 +181,9 @@ public:
return resend();
}
if (ec == asio::error::no_recovery)
_svc.cancel();
// errors, if any, are propagated to ops
for (auto& op : write_queue)
op.complete(ec);
+44 -6
View File
@@ -184,7 +184,7 @@ public:
private:
using tls_context_type = TlsContext;
using receive_channel = asio::experimental::basic_concurrent_channel<
asio::any_io_executor,
executor_type,
channel_traits<>,
void (error_code, std::string, std::string, publish_props)
>;
@@ -204,6 +204,8 @@ private:
template <typename ClientService>
friend class re_auth_op;
executor_type _executor;
stream_context_type _stream_context;
stream_type _stream;
@@ -219,6 +221,8 @@ private:
asio::cancellation_signal _cancel_ping;
asio::cancellation_signal _cancel_sentry;
asio::any_completion_handler<void(error_code)> _run_handler;
public:
client_service(
@@ -226,6 +230,7 @@ public:
const std::string& /* cnf */,
tls_context_type tls_context = {}
) :
_executor(ex),
_stream_context(std::move(tls_context)),
_stream(ex, _stream_context),
_replies(ex),
@@ -235,7 +240,7 @@ public:
{}
executor_type get_executor() const noexcept {
return _stream.get_executor();
return _executor;
}
template <
@@ -302,7 +307,18 @@ public:
return _stream_context.connack_properties();
}
void run() {
template <typename Handler>
void run(Handler&& handler) {
_executor = asio::get_associated_executor(handler, _executor);
_run_handler = std::move(handler);
auto slot = asio::get_associated_cancellation_slot(_run_handler);
if (slot.is_connected()) {
using c_t = asio::cancellation_type_t;
slot.assign([&svc = *this](c_t c) {
if ((c & c_t::terminal) != c_t::none)
svc.cancel();
});
}
_stream.open();
_rec_channel.reset();
}
@@ -320,6 +336,8 @@ public:
}
void cancel() {
if (!_run_handler) return;
_cancel_ping.emit(asio::cancellation_type::terminal);
_cancel_sentry.emit(asio::cancellation_type::terminal);
@@ -327,6 +345,15 @@ public:
_replies.cancel_unanswered();
_async_sender.cancel();
_stream.close();
asio::get_associated_cancellation_slot(_run_handler).clear();
asio::post(
get_executor(),
asio::prepend(
std::move(_run_handler),
asio::error::operation_aborted
)
);
}
uint16_t allocate_pid() {
@@ -420,9 +447,20 @@ public:
template <typename CompletionToken>
decltype(auto) async_channel_receive(CompletionToken&& token) {
// sig = void (error_code, std::string, std::string, publish_props)
return _rec_channel.async_receive(
std::forward<CompletionToken>(token)
using Signature =
void(error_code, std::string, std::string, publish_props);
auto initiation = [] (auto handler, self_type& self) {
auto ex = asio::get_associated_executor(
handler, self.get_executor()
);
return self._rec_channel.async_receive(
asio::bind_executor(ex, std::move(handler))
);
};
return asio::async_initiate<CompletionToken, Signature> (
initiation, token, std::ref(*this)
);
}
@@ -259,7 +259,7 @@ inline std::string encode_subscribe(
inline std::string encode_suback(
uint16_t packet_id,
std::vector<uint8_t>& reason_codes,
const std::vector<uint8_t>& reason_codes,
const suback_props& props
) {
@@ -319,7 +319,7 @@ inline std::string encode_unsubscribe(
inline std::string encode_unsuback(
uint16_t packet_id,
std::vector<uint8_t>& reason_codes,
const std::vector<uint8_t>& reason_codes,
const unsuback_props& props
) {
+6 -4
View File
@@ -64,10 +64,10 @@ public:
"Malformed Packet received from the Server"
);
if (
ec == asio::error::operation_aborted ||
ec == asio::error::no_recovery
)
if (ec == asio::error::no_recovery)
return _svc_ptr->cancel();
if (ec == asio::error::operation_aborted)
return;
dispatch(control_code, first, last);
@@ -115,6 +115,8 @@ private:
re_auth_op { _svc_ptr }.perform(std::move(*rv));
}
break;
default:
assert(false);
}
perform();
+45 -18
View File
@@ -156,13 +156,42 @@ public:
/**
* \brief Start the Client.
*
* \param token Completion token that will be used to produce a
* completion handler. The handler will be invoked when the operation completes.
*
* \par Handler signature
* The handler signature for this operation:
* \code
* void (__ERROR_CODE__)
* \endcode
*
* \par Completion condition
* The asynchronous operation will complete with
* `boost::asio::error::operation_aborted` when client is cancelled by calling
* \ref mqtt_client::async_disconnect, \ref mqtt_client::cancel, destruction or
* if non-recoverable error happens during connection attempt (e.g. access denied).
*
* \par Error codes
* The list of all possible error codes that this operation can finish with:\n
* - `boost::asio::error::operation_aborted`\n
*/
void run() {
_svc_ptr->run();
detail::ping_op { _svc_ptr }
.perform(read_timeout - std::chrono::seconds(1));
detail::read_message_op { _svc_ptr }.perform();
detail::sentry_op { _svc_ptr }.perform();
template <typename CompletionToken>
decltype(auto) async_run(CompletionToken&& token) {
using Signature = void(error_code);
auto initiation = [] (auto handler, const clisvc_ptr& svc_ptr) {
svc_ptr->run(std::move(handler));
detail::ping_op { svc_ptr }
.perform(read_timeout - std::chrono::seconds(1));
detail::read_message_op { svc_ptr }.perform();
detail::sentry_op { svc_ptr }.perform();
};
return asio::async_initiate<CompletionToken, Signature>(
initiation, token, _svc_ptr
);
}
/**
@@ -172,12 +201,10 @@ public:
* with `boost::asio::error::operation_aborted`.
*
* \attention This function has terminal effects and will close the Client.
* The Client cannot be used before calling \ref mqtt_client::run again.
* The Client cannot be used before calling \ref mqtt_client::async_run again.
*/
void cancel() {
get_executor().execute([svc_ptr = _svc_ptr]() {
svc_ptr->cancel();
});
_svc_ptr->cancel();
}
/**
@@ -188,9 +215,9 @@ public:
* closed normally.
*
* \attention This function takes action when the client is in a non-operational state,
* meaning the \ref run function has not been invoked.
* meaning the \ref async_run function has not been invoked.
* Furthermore, you can use this function after the \ref cancel function has been called,
* before the \ref run function is invoked again.
* before the \ref async_run function is invoked again.
*/
mqtt_client& will(will will) {
_svc_ptr->will(std::move(will));
@@ -204,9 +231,9 @@ public:
* a User Name and Password.
*
* \attention This function takes action when the client is in a non-operational state,
* meaning the \ref run function has not been invoked.
* meaning the \ref async_run function has not been invoked.
* Furthermore, you can use this function after the \ref cancel function has been called,
* before the \ref run function is invoked again.
* before the \ref async_run function is invoked again.
*/
mqtt_client& credentials(
std::string client_id,
@@ -233,9 +260,9 @@ public:
* explicitly specified in the `hosts` list.
*
* \attention This function takes action when the client is in a non-operational state,
* meaning the \ref run function has not been invoked.
* meaning the \ref async_run function has not been invoked.
* Furthermore, you can use this function after the \ref cancel function has been called,
* before the \ref run function is invoked again.
* before the \ref async_run function is invoked again.
*
* \par Example
* Some valid `hosts` string:
@@ -260,9 +287,9 @@ public:
* and used for authentication. It needs to satisfy \__is_authenticator\__ concept.
*
* \attention This function takes action when the client is in a non-operational state,
* meaning the \ref run function has not been invoked.
* meaning the \ref async_run function has not been invoked.
* Furthermore, you can use this function after the \ref cancel function has been called,
* before the \ref run function is invoked again.
* before the \ref async_run function is invoked again.
*
*/
template <