mirror of
https://github.com/boostorg/mqtt5.git
synced 2025-08-02 05:54:39 +02:00
[mqtt-client] receive channel discards oldest message
Reviewers: ivica Reviewed By: ivica Subscribers: korina Differential Revision: https://repo.mireo.local/D26538
This commit is contained in:
@@ -25,10 +25,6 @@ may complete with, along with the reasons for their occurrence.
|
|||||||
to establish a connection with the Broker. The cause of this error may be attributed to the connection
|
to establish a connection with the Broker. The cause of this error may be attributed to the connection
|
||||||
related parameters used during the initialization of the [reflink2 mqtt_client `mqtt_client`].
|
related parameters used during the initialization of the [reflink2 mqtt_client `mqtt_client`].
|
||||||
]]
|
]]
|
||||||
[[`boost::asio::experimental::error::channel_cancelled`] [
|
|
||||||
This error occurs in scenarios identical to those causing `boost::asio::error::operation_aborted`
|
|
||||||
error code but it is exclusive to completion handlers associated with [refmem mqtt_client async_receive] calls.
|
|
||||||
]]
|
|
||||||
[[`async_mqtt5::client::error::pid_overrun`] [
|
[[`async_mqtt5::client::error::pid_overrun`] [
|
||||||
This error code signifies that the Client was unable to allocate a Packet Identifier for
|
This error code signifies that the Client was unable to allocate a Packet Identifier for
|
||||||
the current operation due to the exhaustion of the available identifiers.
|
the current operation due to the exhaustion of the available identifiers.
|
||||||
|
84
include/async_mqtt5/detail/channel_traits.hpp
Normal file
84
include/async_mqtt5/detail/channel_traits.hpp
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#ifndef ASYNC_MQTT5_CHANNEL_TRAITS_HPP
|
||||||
|
#define ASYNC_MQTT5_CHANNEL_TRAITS_HPP
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
#include <boost/asio/error.hpp>
|
||||||
|
|
||||||
|
namespace async_mqtt5::detail {
|
||||||
|
|
||||||
|
namespace asio = boost::asio;
|
||||||
|
using error_code = boost::system::error_code;
|
||||||
|
|
||||||
|
template <typename Element>
|
||||||
|
class bounded_deque {
|
||||||
|
std::deque<Element> _buffer;
|
||||||
|
static constexpr size_t MAX_SIZE = 65535;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bounded_deque() = default;
|
||||||
|
bounded_deque(size_t n) : _buffer(n) {}
|
||||||
|
|
||||||
|
size_t size() const { return _buffer.size(); }
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
void push_back(E&& e) {
|
||||||
|
if (_buffer.size() == MAX_SIZE)
|
||||||
|
_buffer.pop_front();
|
||||||
|
_buffer.push_back(std::forward<E>(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_front() { _buffer.pop_front(); }
|
||||||
|
|
||||||
|
void clear() { _buffer.clear(); }
|
||||||
|
|
||||||
|
const auto& front() const noexcept { return _buffer.front(); }
|
||||||
|
|
||||||
|
auto& front() noexcept { return _buffer.front(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Signatures>
|
||||||
|
struct channel_traits {
|
||||||
|
template <typename... NewSignatures>
|
||||||
|
struct rebind {
|
||||||
|
using other = channel_traits<NewSignatures...>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename R, typename... Args>
|
||||||
|
struct channel_traits<R(error_code, Args...)> {
|
||||||
|
static_assert(sizeof...(Args) > 0);
|
||||||
|
template <typename... NewSignatures>
|
||||||
|
struct rebind {
|
||||||
|
using other = channel_traits<NewSignatures...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Element>
|
||||||
|
struct container {
|
||||||
|
using type = bounded_deque<Element>;
|
||||||
|
};
|
||||||
|
|
||||||
|
using receive_cancelled_signature = R(error_code, Args...);
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
static void invoke_receive_cancelled(F f) {
|
||||||
|
std::forward<F>(f)(
|
||||||
|
asio::error::operation_aborted,
|
||||||
|
typename std::decay_t<Args>()...
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
using receive_closed_signature = R(error_code, Args...);
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
static void invoke_receive_closed(F f) {
|
||||||
|
std::forward<F>(f)(
|
||||||
|
asio::error::operation_aborted,
|
||||||
|
typename std::decay_t<Args>()...
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace async_mqtt5::detail
|
||||||
|
|
||||||
|
#endif // !ASYNC_MQTT5_CHANNEL_TRAITS_HPP
|
@@ -1,9 +1,10 @@
|
|||||||
#ifndef ASYNC_MQTT5_CLIENT_SERVICE_HPP
|
#ifndef ASYNC_MQTT5_CLIENT_SERVICE_HPP
|
||||||
#define ASYNC_MQTT5_CLIENT_SERVICE_HPP
|
#define ASYNC_MQTT5_CLIENT_SERVICE_HPP
|
||||||
|
|
||||||
#include <boost/asio/experimental/concurrent_channel.hpp>
|
#include <boost/asio/experimental/basic_concurrent_channel.hpp>
|
||||||
|
|
||||||
#include <async_mqtt5/detail/internal_types.hpp>
|
#include <async_mqtt5/detail/internal_types.hpp>
|
||||||
|
#include <async_mqtt5/detail/channel_traits.hpp>
|
||||||
|
|
||||||
#include <async_mqtt5/impl/assemble_op.hpp>
|
#include <async_mqtt5/impl/assemble_op.hpp>
|
||||||
#include <async_mqtt5/impl/async_sender.hpp>
|
#include <async_mqtt5/impl/async_sender.hpp>
|
||||||
@@ -117,7 +118,9 @@ public:
|
|||||||
using executor_type = typename stream_type::executor_type;
|
using executor_type = typename stream_type::executor_type;
|
||||||
private:
|
private:
|
||||||
using tls_context_type = TlsContext;
|
using tls_context_type = TlsContext;
|
||||||
using receive_channel = asio::experimental::concurrent_channel<
|
using receive_channel = asio::experimental::basic_concurrent_channel<
|
||||||
|
asio::any_io_executor,
|
||||||
|
channel_traits<>,
|
||||||
void (error_code, std::string, std::string, publish_props)
|
void (error_code, std::string, std::string, publish_props)
|
||||||
>;
|
>;
|
||||||
|
|
||||||
@@ -162,7 +165,7 @@ public:
|
|||||||
_stream(ex, _stream_context),
|
_stream(ex, _stream_context),
|
||||||
_async_sender(*this),
|
_async_sender(*this),
|
||||||
_active_span(_read_buff.cend(), _read_buff.cend()),
|
_active_span(_read_buff.cend(), _read_buff.cend()),
|
||||||
_rec_channel(ex, 128)
|
_rec_channel(ex, std::numeric_limits<size_t>::max())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
executor_type get_executor() const noexcept {
|
executor_type get_executor() const noexcept {
|
||||||
@@ -208,6 +211,11 @@ public:
|
|||||||
return _stream_context.connack_prop(p);
|
return _stream_context.connack_prop(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
_stream.open();
|
||||||
|
_rec_channel.reset();
|
||||||
|
}
|
||||||
|
|
||||||
void open_stream() {
|
void open_stream() {
|
||||||
_stream.open();
|
_stream.open();
|
||||||
}
|
}
|
||||||
@@ -224,12 +232,7 @@ public:
|
|||||||
_cancel_ping.emit(asio::cancellation_type::terminal);
|
_cancel_ping.emit(asio::cancellation_type::terminal);
|
||||||
_cancel_sentry.emit(asio::cancellation_type::terminal);
|
_cancel_sentry.emit(asio::cancellation_type::terminal);
|
||||||
|
|
||||||
// cancelling the receive channel invokes all pending handlers with
|
_rec_channel.close();
|
||||||
// ec = asio::experimental::error::channel_cancelled
|
|
||||||
// adding another ec to the list of the possible client ecs
|
|
||||||
|
|
||||||
// TODO: close() the channel instead, and open() it on the next run()
|
|
||||||
_rec_channel.cancel();
|
|
||||||
_replies.cancel_unanswered();
|
_replies.cancel_unanswered();
|
||||||
_async_sender.cancel();
|
_async_sender.cancel();
|
||||||
_stream.close();
|
_stream.close();
|
||||||
|
@@ -195,8 +195,6 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void complete() {
|
void complete() {
|
||||||
// TODO: if rv == false then the channel buffer is full and
|
|
||||||
// there is no listener; we may need to log this
|
|
||||||
/* auto rv = */_svc_ptr->channel_store(std::move(_message));
|
/* auto rv = */_svc_ptr->channel_store(std::move(_message));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -143,7 +143,7 @@ public:
|
|||||||
* \brief Start the Client.
|
* \brief Start the Client.
|
||||||
*/
|
*/
|
||||||
void run() {
|
void run() {
|
||||||
_svc_ptr->open_stream();
|
_svc_ptr->run();
|
||||||
detail::ping_op { _svc_ptr }
|
detail::ping_op { _svc_ptr }
|
||||||
.perform(read_timeout - std::chrono::seconds(1));
|
.perform(read_timeout - std::chrono::seconds(1));
|
||||||
detail::read_message_op { _svc_ptr }.perform();
|
detail::read_message_op { _svc_ptr }.perform();
|
||||||
@@ -637,7 +637,7 @@ public:
|
|||||||
* \par Error codes
|
* \par Error codes
|
||||||
* The list of all possible error codes that this operation can finish with:\n
|
* The list of all possible error codes that this operation can finish with:\n
|
||||||
* - `boost::system::errc::errc_t::success`\n
|
* - `boost::system::errc::errc_t::success`\n
|
||||||
* - `boost::asio::experimental::error::channel_cancelled`
|
* - `boost::asio::error::operation_aborted`\n
|
||||||
*
|
*
|
||||||
* Refer to the section on \__ERROR_HANDLING\__ to find the underlying causes for each error code.
|
* Refer to the section on \__ERROR_HANDLING\__ to find the underlying causes for each error code.
|
||||||
*/
|
*/
|
||||||
|
@@ -38,7 +38,7 @@ void cancel_async_receive() {
|
|||||||
c.async_receive([&handlers_called](
|
c.async_receive([&handlers_called](
|
||||||
error_code ec, std::string, std::string, publish_props
|
error_code ec, std::string, std::string, publish_props
|
||||||
) {
|
) {
|
||||||
BOOST_CHECK_EQUAL(ec, asio::experimental::error::channel_cancelled);
|
BOOST_CHECK_EQUAL(ec, asio::error::operation_aborted);
|
||||||
handlers_called++;
|
handlers_called++;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user