forked from boostorg/mqtt5
async_run
Reviewers: ivica Reviewed By: ivica Subscribers: korina Differential Revision: https://repo.mireo.local/D27342
This commit is contained in:
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);
|
||||
|
||||
@@ -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
|
||||
) {
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 <
|
||||
|
||||
Reference in new issue
Block a user