mirror of
https://github.com/eclipse-paho/paho.mqtt.cpp.git
synced 2025-09-15 12:58:39 +08:00
Added individual callback registration.
Added chat sample. The 'topic' objects can subscribe. Fixed disconnect version for v5
This commit is contained in:
parent
ba3aceeb1a
commit
01d3381421
14
README.md
14
README.md
@ -37,7 +37,7 @@ _Catch2_ can be found here: [Catch2](https://github.com/catchorg/Catch2)
|
|||||||
|
|
||||||
### Unreleased Features in this Branch
|
### Unreleased Features in this Branch
|
||||||
|
|
||||||
- Started MQTT v5 support
|
- Started MQTT v5 support:
|
||||||
- **Properties**
|
- **Properties**
|
||||||
- New `property` class acts something like a std::variant to hold a property of any supported type.
|
- New `property` class acts something like a std::variant to hold a property of any supported type.
|
||||||
- New `properties` class is a collection type to hold all the properties for a single transmitted packet.
|
- New `properties` class is a collection type to hold all the properties for a single transmitted packet.
|
||||||
@ -45,12 +45,14 @@ _Catch2_ can be found here: [Catch2](https://github.com/catchorg/Catch2)
|
|||||||
- Properties can also be obtained from server responses to requests such as from a _connect_ call. These are available in the `token` objects when they complete.
|
- Properties can also be obtained from server responses to requests such as from a _connect_ call. These are available in the `token` objects when they complete.
|
||||||
- The client object tracks the desired MQTT version that the app requested and/or is currently connected at. Internally this is now required by the `response_options` the need to distinguish between pre-v5 and post-v5 callback functions.
|
- The client object tracks the desired MQTT version that the app requested and/or is currently connected at. Internally this is now required by the `response_options` the need to distinguish between pre-v5 and post-v5 callback functions.
|
||||||
- MQTT v5 reason codes for requests are available via `token` objects when they complete. They are also available in `exception` objects that are thrown by tokens.
|
- MQTT v5 reason codes for requests are available via `token` objects when they complete. They are also available in `exception` objects that are thrown by tokens.
|
||||||
- More descriptive error messages (PR #154), integrated into the `mqtt::exception` class. MQTT v5 reason codes are also included in the exceptions when an error occurs.
|
|
||||||
- The`message` and various options classes were updated for MQTT v5 to include properties and reson codes (where appropriate).
|
|
||||||
- Applications can (finally) get server responses from the various ack packets. These are available through the tokens after they complete, as `connect_response`, `subscribe_response`, and `unsubscribe_response`.
|
|
||||||
- Support for subscibe options, like no local subscriptions, etc.
|
- Support for subscibe options, like no local subscriptions, etc.
|
||||||
- Sample applications were added showing how to do basic Remote Procedure Calls (RPC's) with MQTT v5 using the *RESPONSE_TOPIC* and *CORRELATION_DATA* properties. These are *rpc_math_cli* and *rpc_math_srvr* in the _src/samples_ directory.
|
- Sample applications were added showing how to do basic Remote Procedure Calls (RPC's) with MQTT v5 using the *RESPONSE_TOPIC* and *CORRELATION_DATA* properties. These are *rpc_math_cli* and *rpc_math_srvr* in the _src/samples_ directory.
|
||||||
|
- A sample "chat" application was added, showing how to use subscribe options, such as "no local".
|
||||||
|
- More descriptive error messages (PR #154), integrated into the `mqtt::exception` class. MQTT v5 reason codes are also included in the exceptions when an error occurs.
|
||||||
|
- Applications can (finally) get server responses from the various ack packets. These are available through the tokens after they complete, as `connect_response`, `subscribe_response`, and `unsubscribe_response`.
|
||||||
|
- The `topic` objects can be used to subscribe.
|
||||||
|
- Applications can register individual callback functions instead of using a `callback` interface object. This allows easy use of lambda functions for callbacks.
|
||||||
|
- The connect options can take a LWT as a plain message, via `connect_options::set_will_message()`
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
@ -155,9 +155,15 @@ void async_client::on_connected(void* context, char* cause)
|
|||||||
if (context) {
|
if (context) {
|
||||||
async_client* cli = static_cast<async_client*>(context);
|
async_client* cli = static_cast<async_client*>(context);
|
||||||
callback* cb = cli->userCallback_;
|
callback* cb = cli->userCallback_;
|
||||||
|
auto& connHandler = cli->connHandler_;
|
||||||
|
|
||||||
|
string cause_str = cause ? string(cause) : string();
|
||||||
|
|
||||||
if (cb)
|
if (cb)
|
||||||
cb->connected(cause ? string(cause) : string());
|
cb->connected(cause_str);
|
||||||
|
|
||||||
|
if (connHandler)
|
||||||
|
connHandler(cause_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,9 +178,15 @@ void async_client::on_connection_lost(void *context, char *cause)
|
|||||||
async_client* cli = static_cast<async_client*>(context);
|
async_client* cli = static_cast<async_client*>(context);
|
||||||
callback* cb = cli->userCallback_;
|
callback* cb = cli->userCallback_;
|
||||||
consumer_queue_type& que = cli->que_;
|
consumer_queue_type& que = cli->que_;
|
||||||
|
auto& connLostHandler = cli->connLostHandler_;
|
||||||
|
|
||||||
|
string cause_str = cause ? string(cause) : string();
|
||||||
|
|
||||||
if (cb)
|
if (cb)
|
||||||
cb->connection_lost(cause ? string(cause) : string());
|
cb->connection_lost(cause_str);
|
||||||
|
|
||||||
|
if (connLostHandler)
|
||||||
|
connLostHandler(cause_str);
|
||||||
|
|
||||||
if (que)
|
if (que)
|
||||||
que->put(const_message_ptr{});
|
que->put(const_message_ptr{});
|
||||||
@ -191,13 +203,17 @@ int async_client::on_message_arrived(void* context, char* topicName, int topicLe
|
|||||||
async_client* cli = static_cast<async_client*>(context);
|
async_client* cli = static_cast<async_client*>(context);
|
||||||
callback* cb = cli->userCallback_;
|
callback* cb = cli->userCallback_;
|
||||||
consumer_queue_type& que = cli->que_;
|
consumer_queue_type& que = cli->que_;
|
||||||
|
message_handler& msgHandler = cli->msgHandler_;
|
||||||
|
|
||||||
if (cb || que) {
|
if (cb || que || msgHandler) {
|
||||||
size_t len = (topicLen == 0) ? strlen(topicName) : size_t(topicLen);
|
size_t len = (topicLen == 0) ? strlen(topicName) : size_t(topicLen);
|
||||||
|
|
||||||
string topic(topicName, topicName+len);
|
string topic(topicName, topicName+len);
|
||||||
auto m = message::create(std::move(topic), *msg);
|
auto m = message::create(std::move(topic), *msg);
|
||||||
|
|
||||||
|
if (msgHandler)
|
||||||
|
msgHandler(m);
|
||||||
|
|
||||||
if (cb)
|
if (cb)
|
||||||
cb->message_arrived(m);
|
cb->message_arrived(m);
|
||||||
|
|
||||||
@ -295,6 +311,32 @@ void async_client::remove_token(token* tok)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Callback management
|
||||||
|
|
||||||
|
void async_client::set_callback(callback& cb)
|
||||||
|
{
|
||||||
|
guard g(lock_);
|
||||||
|
userCallback_ = &cb;
|
||||||
|
|
||||||
|
int rc = MQTTAsync_setConnected(cli_, this, &async_client::on_connected);
|
||||||
|
|
||||||
|
if (rc == MQTTASYNC_SUCCESS) {
|
||||||
|
rc = MQTTAsync_setCallbacks(cli_, this,
|
||||||
|
&async_client::on_connection_lost,
|
||||||
|
&async_client::on_message_arrived,
|
||||||
|
nullptr /*&async_client::on_delivery_complete*/);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
MQTTAsync_setConnected(cli_, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (rc != MQTTASYNC_SUCCESS) {
|
||||||
|
userCallback_ = nullptr;
|
||||||
|
throw exception(rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void async_client::disable_callbacks()
|
void async_client::disable_callbacks()
|
||||||
{
|
{
|
||||||
// TODO: It would be nice to disable callbacks at the C library level,
|
// TODO: It would be nice to disable callbacks at the C library level,
|
||||||
@ -304,11 +346,32 @@ void async_client::disable_callbacks()
|
|||||||
int rc = MQTTAsync_setCallbacks(cli_, this, nullptr,
|
int rc = MQTTAsync_setCallbacks(cli_, this, nullptr,
|
||||||
[](void*,char*,int,MQTTAsync_message*) -> int {return to_int(true);},
|
[](void*,char*,int,MQTTAsync_message*) -> int {return to_int(true);},
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
if (rc != MQTTASYNC_SUCCESS)
|
if (rc != MQTTASYNC_SUCCESS)
|
||||||
throw exception(rc);
|
throw exception(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void async_client::set_connected_handler(connection_handler cb)
|
||||||
|
{
|
||||||
|
connHandler_ = cb;
|
||||||
|
check_ret(::MQTTAsync_setConnected(cli_, this,
|
||||||
|
&async_client::on_connected));
|
||||||
|
}
|
||||||
|
|
||||||
|
void async_client::set_connection_lost_handler(connection_handler cb)
|
||||||
|
{
|
||||||
|
connLostHandler_ = cb;
|
||||||
|
check_ret(::MQTTAsync_setConnectionLostCallback(cli_, this,
|
||||||
|
&async_client::on_connection_lost));
|
||||||
|
}
|
||||||
|
|
||||||
|
void async_client::set_message_callback(message_handler cb)
|
||||||
|
{
|
||||||
|
msgHandler_ = cb;
|
||||||
|
check_ret(::MQTTAsync_setMessageArrivedCallback(cli_, this,
|
||||||
|
&async_client::on_message_arrived));
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// Connect
|
// Connect
|
||||||
|
|
||||||
@ -403,24 +466,7 @@ token_ptr async_client::disconnect(disconnect_options opts)
|
|||||||
auto tok = token::create(token::Type::DISCONNECT, *this);
|
auto tok = token::create(token::Type::DISCONNECT, *this);
|
||||||
add_token(tok);
|
add_token(tok);
|
||||||
|
|
||||||
opts.set_token(tok);
|
opts.set_token(tok, mqttVersion_);
|
||||||
|
|
||||||
int rc = MQTTAsync_disconnect(cli_, &opts.opts_);
|
|
||||||
|
|
||||||
if (rc != MQTTASYNC_SUCCESS) {
|
|
||||||
remove_token(tok);
|
|
||||||
throw exception(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
token_ptr async_client::disconnect(int timeout)
|
|
||||||
{
|
|
||||||
auto tok = token::create(token::Type::DISCONNECT, *this);
|
|
||||||
add_token(tok);
|
|
||||||
|
|
||||||
disconnect_options opts(timeout, tok);
|
|
||||||
|
|
||||||
int rc = MQTTAsync_disconnect(cli_, &opts.opts_);
|
int rc = MQTTAsync_disconnect(cli_, &opts.opts_);
|
||||||
|
|
||||||
@ -437,7 +483,8 @@ token_ptr async_client::disconnect(int timeout, void* userContext, iaction_liste
|
|||||||
auto tok = token::create(token::Type::DISCONNECT, *this, userContext, cb);
|
auto tok = token::create(token::Type::DISCONNECT, *this, userContext, cb);
|
||||||
add_token(tok);
|
add_token(tok);
|
||||||
|
|
||||||
disconnect_options opts(timeout, tok);
|
disconnect_options opts(timeout);
|
||||||
|
opts.set_token(tok, mqttVersion_);
|
||||||
|
|
||||||
int rc = MQTTAsync_disconnect(cli_, &opts.opts_);
|
int rc = MQTTAsync_disconnect(cli_, &opts.opts_);
|
||||||
|
|
||||||
@ -551,30 +598,6 @@ delivery_token_ptr async_client::publish(const_message_ptr msg,
|
|||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void async_client::set_callback(callback& cb)
|
|
||||||
{
|
|
||||||
guard g(lock_);
|
|
||||||
userCallback_ = &cb;
|
|
||||||
|
|
||||||
int rc = MQTTAsync_setConnected(cli_, this, &async_client::on_connected);
|
|
||||||
|
|
||||||
if (rc == MQTTASYNC_SUCCESS) {
|
|
||||||
rc = MQTTAsync_setCallbacks(cli_, this,
|
|
||||||
&async_client::on_connection_lost,
|
|
||||||
&async_client::on_message_arrived,
|
|
||||||
nullptr /*&async_client::on_delivery_complete*/);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
MQTTAsync_setConnected(cli_, nullptr, nullptr);
|
|
||||||
|
|
||||||
if (rc != MQTTASYNC_SUCCESS) {
|
|
||||||
userCallback_ = nullptr;
|
|
||||||
throw exception(rc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// Subscribe
|
// Subscribe
|
||||||
|
|
||||||
|
|||||||
@ -14,13 +14,6 @@ disconnect_options::disconnect_options() : opts_(DFLT_C_STRUCT)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnect_options::disconnect_options(int timeout, const token_ptr& tok)
|
|
||||||
: disconnect_options()
|
|
||||||
{
|
|
||||||
set_timeout(timeout);
|
|
||||||
set_token(tok);
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnect_options::disconnect_options(const disconnect_options& opt)
|
disconnect_options::disconnect_options(const disconnect_options& opt)
|
||||||
: opts_(opt.opts_), tok_(opt.tok_)
|
: opts_(opt.opts_), tok_(opt.tok_)
|
||||||
{
|
{
|
||||||
@ -45,18 +38,26 @@ disconnect_options& disconnect_options::operator=(disconnect_options&& opt)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void disconnect_options::set_token(const token_ptr& tok)
|
void disconnect_options::set_token(const token_ptr& tok, int mqttVersion)
|
||||||
{
|
{
|
||||||
tok_ = tok;
|
tok_ = tok;
|
||||||
opts_.context = tok_.get();
|
opts_.context = tok_.get();
|
||||||
|
|
||||||
|
opts_.onSuccess = nullptr;
|
||||||
|
opts_.onFailure = nullptr;
|
||||||
|
|
||||||
|
opts_.onSuccess5 = nullptr;
|
||||||
|
opts_.onFailure5 = nullptr;
|
||||||
|
|
||||||
if (tok) {
|
if (tok) {
|
||||||
opts_.onSuccess = &token::on_success;
|
if (mqttVersion >= MQTTVERSION_5) {
|
||||||
opts_.onFailure = &token::on_failure;
|
opts_.onSuccess5 = &token::on_success5;
|
||||||
}
|
opts_.onFailure5 = &token::on_failure5;
|
||||||
else {
|
}
|
||||||
opts_.onSuccess = nullptr;
|
else {
|
||||||
opts_.onFailure = nullptr;
|
opts_.onSuccess = &token::on_success;
|
||||||
|
opts_.onFailure = &token::on_failure;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,6 +41,7 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <functional>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace mqtt {
|
namespace mqtt {
|
||||||
@ -79,6 +80,11 @@ public:
|
|||||||
/** Type for a thread-safe queue to consume messages synchronously */
|
/** Type for a thread-safe queue to consume messages synchronously */
|
||||||
using consumer_queue_type = std::unique_ptr<thread_queue<const_message_ptr>>;
|
using consumer_queue_type = std::unique_ptr<thread_queue<const_message_ptr>>;
|
||||||
|
|
||||||
|
/** Handler type for registering an individual message callback */
|
||||||
|
using message_handler = std::function<void(const_message_ptr)>;
|
||||||
|
/** Handler type for when a connecion is made or lost */
|
||||||
|
using connection_handler = std::function<void(const string& cause)>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Lock guard type for this class */
|
/** Lock guard type for this class */
|
||||||
using guard = std::unique_lock<std::mutex>;
|
using guard = std::unique_lock<std::mutex>;
|
||||||
@ -99,6 +105,12 @@ private:
|
|||||||
std::unique_ptr<MQTTClient_persistence> persist_;
|
std::unique_ptr<MQTTClient_persistence> persist_;
|
||||||
/** Callback supplied by the user (if any) */
|
/** Callback supplied by the user (if any) */
|
||||||
callback* userCallback_;
|
callback* userCallback_;
|
||||||
|
/** Connection handler */
|
||||||
|
connection_handler connHandler_;
|
||||||
|
/** Connection lost handler */
|
||||||
|
connection_handler connLostHandler_;
|
||||||
|
/** Message handler (if any) */
|
||||||
|
message_handler msgHandler_;
|
||||||
/** Copy of connect token (for re-connects) */
|
/** Copy of connect token (for re-connects) */
|
||||||
token_ptr connTok_;
|
token_ptr connTok_;
|
||||||
/** A list of tokens that are in play */
|
/** A list of tokens that are in play */
|
||||||
@ -128,6 +140,12 @@ private:
|
|||||||
async_client(const async_client&) =delete;
|
async_client(const async_client&) =delete;
|
||||||
async_client& operator=(const async_client&) =delete;
|
async_client& operator=(const async_client&) =delete;
|
||||||
|
|
||||||
|
/** Checks a function return code and throws on error. */
|
||||||
|
static void check_ret(int rc) {
|
||||||
|
if (rc != MQTTASYNC_SUCCESS)
|
||||||
|
throw exception(rc);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Create an async_client that can be used to communicate with an MQTT
|
* Create an async_client that can be used to communicate with an MQTT
|
||||||
@ -193,6 +211,37 @@ public:
|
|||||||
* Destructor
|
* Destructor
|
||||||
*/
|
*/
|
||||||
~async_client() override;
|
~async_client() override;
|
||||||
|
/**
|
||||||
|
* Sets a callback listener to use for events that happen
|
||||||
|
* asynchronously.
|
||||||
|
* @param cb callback receiver which will be invoked for certain
|
||||||
|
* asynchronous events
|
||||||
|
*/
|
||||||
|
void set_callback(callback& cb) override;
|
||||||
|
/**
|
||||||
|
* Stops callbacks.
|
||||||
|
* This is not normally called by the application. It should be used
|
||||||
|
* cautiously as it may cause the application to lose messages.
|
||||||
|
*/
|
||||||
|
void disable_callbacks() override;
|
||||||
|
/**
|
||||||
|
* Callback for when a connection is made.
|
||||||
|
* @param cb Callback functor for when the connection is made.
|
||||||
|
*/
|
||||||
|
void set_connected_handler(connection_handler cb) /*override*/;
|
||||||
|
/**
|
||||||
|
* Callback for when a connection is lost.
|
||||||
|
* @param cb Callback functor for when the connection is lost.
|
||||||
|
*/
|
||||||
|
void set_connection_lost_handler(connection_handler cb) /*override*/;
|
||||||
|
/**
|
||||||
|
* Sets the callback for when a message arrives from the broker.
|
||||||
|
* Note that the application can only have one message handler which can
|
||||||
|
* be installed individually using this method, or installled as a
|
||||||
|
* listener object.
|
||||||
|
* @param cb The callback functor to register with the library.
|
||||||
|
*/
|
||||||
|
void set_message_callback(message_handler cb) /*override*/;
|
||||||
/**
|
/**
|
||||||
* Connects to an MQTT server using the default options.
|
* Connects to an MQTT server using the default options.
|
||||||
* @return token used to track and wait for the connect to complete. The
|
* @return token used to track and wait for the connect to complete. The
|
||||||
@ -271,7 +320,9 @@ public:
|
|||||||
* set.
|
* set.
|
||||||
* @throw exception for problems encountered while disconnecting
|
* @throw exception for problems encountered while disconnecting
|
||||||
*/
|
*/
|
||||||
token_ptr disconnect(int timeout) override;
|
token_ptr disconnect(int timeout) override {
|
||||||
|
return disconnect(disconnect_options(timeout));
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Disconnects from the server.
|
* Disconnects from the server.
|
||||||
* @param timeout the amount of time in milliseconds to allow for
|
* @param timeout the amount of time in milliseconds to allow for
|
||||||
@ -453,19 +504,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
delivery_token_ptr publish(const_message_ptr msg,
|
delivery_token_ptr publish(const_message_ptr msg,
|
||||||
void* userContext, iaction_listener& cb) override;
|
void* userContext, iaction_listener& cb) override;
|
||||||
/**
|
|
||||||
* Sets a callback listener to use for events that happen
|
|
||||||
* asynchronously.
|
|
||||||
* @param cb callback receiver which will be invoked for certain
|
|
||||||
* asynchronous events
|
|
||||||
*/
|
|
||||||
void set_callback(callback& cb) override;
|
|
||||||
/**
|
|
||||||
* Stops callbacks.
|
|
||||||
* This is not normally called by the application. It should be used
|
|
||||||
* cautiously as it may cause the application to lose messages.
|
|
||||||
*/
|
|
||||||
void disable_callbacks() override;
|
|
||||||
/**
|
/**
|
||||||
* Subscribe to a topic, which may include wildcards.
|
* Subscribe to a topic, which may include wildcards.
|
||||||
* @param topicFilter the topic to subscribe to, which can include
|
* @param topicFilter the topic to subscribe to, which can include
|
||||||
|
|||||||
@ -321,6 +321,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
void set_will(const will_options& will);
|
void set_will(const will_options& will);
|
||||||
void set_will(will_options&& will);
|
void set_will(will_options&& will);
|
||||||
|
/**
|
||||||
|
* Sets the "Last Will and Testament" (LWT) as a message
|
||||||
|
* @param msg The LWT message
|
||||||
|
*/
|
||||||
|
void set_will_message(const message& msg) {
|
||||||
|
set_will(will_options(msg));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sets the "Last Will and Testament" (LWT) as a message
|
||||||
|
* @param msg Pointer to a LWT message
|
||||||
|
*/
|
||||||
|
void set_will_message(const_message_ptr msg) {
|
||||||
|
if (msg) set_will(will_options(*msg));
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Sets the callback context to a delivery token.
|
* Sets the callback context to a delivery token.
|
||||||
* @param tok The delivery token to be used as the callback context.
|
* @param tok The delivery token to be used as the callback context.
|
||||||
|
|||||||
@ -62,19 +62,18 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Creates disconnect options tied to the specific token.
|
* Creates disconnect options tied to the specific token.
|
||||||
* @param timeout The timeout (in milliseconds).
|
* @param timeout The timeout (in milliseconds).
|
||||||
* @param tok A token to be used as the context.
|
|
||||||
*/
|
*/
|
||||||
disconnect_options(int timeout, const token_ptr& tok);
|
disconnect_options(int timeout) : disconnect_options() {
|
||||||
|
set_timeout(timeout);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Creates disconnect options tied to the specific token.
|
* Creates disconnect options tied to the specific token.
|
||||||
* @param to The timeout.
|
* @param to The timeout.
|
||||||
* @param tok A token to be used as the context.
|
|
||||||
*/
|
*/
|
||||||
template <class Rep, class Period>
|
template <class Rep, class Period>
|
||||||
disconnect_options(const std::chrono::duration<Rep, Period>& to,
|
disconnect_options(const std::chrono::duration<Rep, Period>& to)
|
||||||
const token_ptr& tok) : disconnect_options() {
|
: disconnect_options() {
|
||||||
set_timeout(to);
|
set_timeout(to);
|
||||||
set_token(tok);
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Copy constructor.
|
* Copy constructor.
|
||||||
@ -123,8 +122,10 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Sets the callback context to a delivery token.
|
* Sets the callback context to a delivery token.
|
||||||
* @param tok The delivery token to be used as the callback context.
|
* @param tok The delivery token to be used as the callback context.
|
||||||
|
* @param mqttVersion The version of MQTT we're using for the
|
||||||
|
* connection.
|
||||||
*/
|
*/
|
||||||
void set_token(const token_ptr& tok);
|
void set_token(const token_ptr& tok, int mqttVersion);
|
||||||
/**
|
/**
|
||||||
* Gets the callback context to a delivery token.
|
* Gets the callback context to a delivery token.
|
||||||
* @return The delivery token to be used as the callback context.
|
* @return The delivery token to be used as the callback context.
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include "MQTTAsync.h"
|
#include "MQTTAsync.h"
|
||||||
#include "mqtt/delivery_token.h"
|
#include "mqtt/delivery_token.h"
|
||||||
|
#include "mqtt/subscribe_options.h"
|
||||||
#include "mqtt/message.h"
|
#include "mqtt/message.h"
|
||||||
#include "mqtt/types.h"
|
#include "mqtt/types.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -153,6 +154,11 @@ public:
|
|||||||
* complete.
|
* complete.
|
||||||
*/
|
*/
|
||||||
delivery_token_ptr publish(binary_ref payload, int qos, bool retained);
|
delivery_token_ptr publish(binary_ref payload, int qos, bool retained);
|
||||||
|
/**
|
||||||
|
* Subscribe to the topic.
|
||||||
|
* @return A token used to track the progress of the operation.
|
||||||
|
*/
|
||||||
|
token_ptr subscribe(const subscribe_options& opts=subscribe_options());
|
||||||
/**
|
/**
|
||||||
* Returns a string representation of this topic.
|
* Returns a string representation of this topic.
|
||||||
* @return The name of the topic
|
* @return The name of the topic
|
||||||
|
|||||||
@ -40,6 +40,7 @@ add_executable(data_publish data_publish.cpp)
|
|||||||
add_executable(rpc_math_cli rpc_math_cli.cpp)
|
add_executable(rpc_math_cli rpc_math_cli.cpp)
|
||||||
add_executable(rpc_math_srvr rpc_math_srvr.cpp)
|
add_executable(rpc_math_srvr rpc_math_srvr.cpp)
|
||||||
add_executable(pub_speed_test pub_speed_test.cpp)
|
add_executable(pub_speed_test pub_speed_test.cpp)
|
||||||
|
add_executable(mqttpp_chat mqttpp_chat.cpp)
|
||||||
|
|
||||||
## link binaries
|
## link binaries
|
||||||
target_link_libraries(async_publish ${PAHO_CPP_LIB})
|
target_link_libraries(async_publish ${PAHO_CPP_LIB})
|
||||||
@ -50,6 +51,7 @@ target_link_libraries(sync_consume ${PAHO_CPP_LIB})
|
|||||||
target_link_libraries(data_publish ${PAHO_CPP_LIB})
|
target_link_libraries(data_publish ${PAHO_CPP_LIB})
|
||||||
target_link_libraries(rpc_math_cli ${PAHO_CPP_LIB})
|
target_link_libraries(rpc_math_cli ${PAHO_CPP_LIB})
|
||||||
target_link_libraries(rpc_math_srvr ${PAHO_CPP_LIB})
|
target_link_libraries(rpc_math_srvr ${PAHO_CPP_LIB})
|
||||||
|
target_link_libraries(mqttpp_chat ${PAHO_CPP_LIB})
|
||||||
|
|
||||||
target_link_libraries(pub_speed_test ${PAHO_CPP_LIB}
|
target_link_libraries(pub_speed_test ${PAHO_CPP_LIB}
|
||||||
Threads::Threads)
|
Threads::Threads)
|
||||||
@ -63,6 +65,7 @@ set(INSTALL_TARGETS
|
|||||||
data_publish
|
data_publish
|
||||||
rpc_math_cli
|
rpc_math_cli
|
||||||
rpc_math_srvr
|
rpc_math_srvr
|
||||||
|
mqttpp_chat
|
||||||
pub_speed_test
|
pub_speed_test
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
153
src/samples/mqttpp_chat.cpp
Normal file
153
src/samples/mqttpp_chat.cpp
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
// mqttpp_chat.cpp
|
||||||
|
//
|
||||||
|
// This is a Paho MQTT C++ client, sample application.
|
||||||
|
//
|
||||||
|
// The "chat" application is practically the "Hello World" application for
|
||||||
|
// messaging systems. This allows a user to type in message to send to a
|
||||||
|
// "group" while seeing all the messages that the other members of the group
|
||||||
|
// send.
|
||||||
|
//
|
||||||
|
// This application is an MQTT publisher/subscriber using the C++
|
||||||
|
// asynchronous client interface, employing callbacks to receive messages
|
||||||
|
// and status updates.
|
||||||
|
//
|
||||||
|
// The sample demonstrates:
|
||||||
|
// - Connecting to an MQTT server/broker.
|
||||||
|
// - Publishing messages.
|
||||||
|
// - Subscribing to a topic
|
||||||
|
// - Receiving messages (callbacks) through a lambda function
|
||||||
|
//
|
||||||
|
// USAGE:
|
||||||
|
// mqttpp_chat <user> <group>
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2019 Frank Pagliughi <fpagliughi@mindspring.com>
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||||
|
*
|
||||||
|
* The Eclipse Public License is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
* and the Eclipse Distribution License is available at
|
||||||
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Frank Pagliughi - initial implementation and documentation
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cctype>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
#include "mqtt/async_client.h"
|
||||||
|
#include "mqtt/topic.h"
|
||||||
|
|
||||||
|
const std::string SERVER_ADDRESS("tcp://localhost:1883");
|
||||||
|
|
||||||
|
const int QOS = 1;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc != 3) {
|
||||||
|
std::cout << "USAGE: mqttpp_chat <user> <group>" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string chatUser { argv[1] },
|
||||||
|
chatGroup { argv[2] },
|
||||||
|
chatTopic { "chat/"+chatGroup };
|
||||||
|
|
||||||
|
// LWT message is broadcast to other users if out connection is lost
|
||||||
|
|
||||||
|
auto lwt = mqtt::make_message(chatTopic, "<<<"+chatUser+" was disconnected>>>", QOS, false);
|
||||||
|
|
||||||
|
// Set up the connect options
|
||||||
|
|
||||||
|
mqtt::connect_options connOpts;
|
||||||
|
connOpts.set_keep_alive_interval(20);
|
||||||
|
connOpts.set_mqtt_version(MQTTVERSION_5);
|
||||||
|
connOpts.set_clean_start(true);
|
||||||
|
connOpts.set_will_message(lwt);
|
||||||
|
|
||||||
|
mqtt::async_client cli(SERVER_ADDRESS, "");
|
||||||
|
|
||||||
|
// Set a callback for connection lost.
|
||||||
|
// This just exits the app.
|
||||||
|
|
||||||
|
cli.set_connection_lost_handler([](const std::string&) {
|
||||||
|
std::cout << "*** Connection Lost ***" << std::endl;
|
||||||
|
exit(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set the callback for incoming messages
|
||||||
|
|
||||||
|
cli.set_message_callback([](mqtt::const_message_ptr msg) {
|
||||||
|
std::cout << msg->get_payload_str() << std::endl;
|
||||||
|
});
|
||||||
|
|
||||||
|
// We publish and subscribe to one topic,
|
||||||
|
// so a 'topic' object is helpful.
|
||||||
|
|
||||||
|
mqtt::topic topic { cli, "chat/"+chatGroup, QOS };
|
||||||
|
|
||||||
|
// Start the connection.
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::cout << "Connecting to the chat server at '" << SERVER_ADDRESS
|
||||||
|
<< "'..." << std::flush;
|
||||||
|
auto tok = cli.connect(connOpts);
|
||||||
|
tok->wait();
|
||||||
|
|
||||||
|
// Subscribe to the topic using "no local" so that
|
||||||
|
// we don't get own messages sent back to us
|
||||||
|
|
||||||
|
std::cout << "Ok\nJoining the group..." << std::flush;
|
||||||
|
auto subOpts = mqtt::subscribe_options(mqtt::subscribe_options::SUBSCRIBE_NO_LOCAL);
|
||||||
|
topic.subscribe(subOpts)->wait();
|
||||||
|
std::cout << "Ok" << std::endl;
|
||||||
|
}
|
||||||
|
catch (const mqtt::exception& exc) {
|
||||||
|
std::cerr << "\nERROR: Unable to connect. "
|
||||||
|
<< exc.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let eveyone know that a new user joined the conversation.
|
||||||
|
|
||||||
|
topic.publish("<<" + chatUser + " joined the group>>");
|
||||||
|
|
||||||
|
// Read messages from the console and publish them.
|
||||||
|
// Quit when the use enters an empty line.
|
||||||
|
|
||||||
|
std::string usrMsg;
|
||||||
|
|
||||||
|
while (std::getline(std::cin, usrMsg) && !usrMsg.empty()) {
|
||||||
|
usrMsg = chatUser + ": " + usrMsg;
|
||||||
|
topic.publish(usrMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let eveyone know that the user left the conversation.
|
||||||
|
|
||||||
|
topic.publish("<<" + chatUser + " left the group>>")->wait();
|
||||||
|
|
||||||
|
// Disconnect
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::cout << "Disconnecting from the chat server..." << std::flush;
|
||||||
|
cli.disconnect()->wait();
|
||||||
|
std::cout << "OK" << std::endl;
|
||||||
|
}
|
||||||
|
catch (const mqtt::exception& exc) {
|
||||||
|
std::cerr << exc.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ void token::on_failure(MQTTAsync_failureData* rsp)
|
|||||||
//
|
//
|
||||||
void token::on_failure5(MQTTAsync_failureData5* rsp)
|
void token::on_failure5(MQTTAsync_failureData5* rsp)
|
||||||
{
|
{
|
||||||
::Log(TRACE_MIN, -1, "[cpp] on_failure");
|
::Log(TRACE_MIN, -1, "[cpp] on_failure5");
|
||||||
|
|
||||||
unique_lock g(lock_);
|
unique_lock g(lock_);
|
||||||
iaction_listener* listener = listener_;
|
iaction_listener* listener = listener_;
|
||||||
|
|||||||
@ -44,6 +44,11 @@ delivery_token_ptr topic::publish(binary_ref payload, int qos, bool retained)
|
|||||||
return cli_.publish(name_, std::move(payload), qos, retained);
|
return cli_.publish(name_, std::move(payload), qos, retained);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
token_ptr topic::subscribe(const subscribe_options& opts)
|
||||||
|
{
|
||||||
|
return cli_.subscribe(name_, qos_, opts);
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
// end namespace mqtt
|
// end namespace mqtt
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,7 +79,8 @@ public:
|
|||||||
const int TIMEOUT = 10;
|
const int TIMEOUT = 10;
|
||||||
|
|
||||||
auto tok = token::create(TOKEN_TYPE, cli);
|
auto tok = token::create(TOKEN_TYPE, cli);
|
||||||
mqtt::disconnect_options opts { TIMEOUT, tok };
|
mqtt::disconnect_options opts { TIMEOUT };
|
||||||
|
opts.set_token(tok, MQTTVERSION_DEFAULT);
|
||||||
|
|
||||||
const auto& c_struct = opts.opts_;
|
const auto& c_struct = opts.opts_;
|
||||||
|
|
||||||
@ -124,11 +125,11 @@ public:
|
|||||||
CPPUNIT_ASSERT(nullptr == c_struct.onSuccess);
|
CPPUNIT_ASSERT(nullptr == c_struct.onSuccess);
|
||||||
CPPUNIT_ASSERT(nullptr == c_struct.onFailure);
|
CPPUNIT_ASSERT(nullptr == c_struct.onFailure);
|
||||||
|
|
||||||
opts.set_token(mqtt::token_ptr());
|
opts.set_token(mqtt::token_ptr(), MQTTVERSION_DEFAULT);
|
||||||
CPPUNIT_ASSERT(nullptr == c_struct.onSuccess);
|
CPPUNIT_ASSERT(nullptr == c_struct.onSuccess);
|
||||||
CPPUNIT_ASSERT(nullptr == c_struct.onFailure);
|
CPPUNIT_ASSERT(nullptr == c_struct.onFailure);
|
||||||
|
|
||||||
opts.set_token(tok);
|
opts.set_token(tok, MQTTVERSION_DEFAULT);
|
||||||
CPPUNIT_ASSERT(nullptr != c_struct.onSuccess);
|
CPPUNIT_ASSERT(nullptr != c_struct.onSuccess);
|
||||||
CPPUNIT_ASSERT(nullptr != c_struct.onFailure);
|
CPPUNIT_ASSERT(nullptr != c_struct.onFailure);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user