Commit 87fe34d7e16ec2c27cb86c4da3fa821c4907d635
1 parent
584030be
feat: implement last-will support
Showing
5 changed files
with
49 additions
and
35 deletions
example/pubsub/main.cpp
| @@ -19,6 +19,7 @@ int main() | @@ -19,6 +19,7 @@ int main() | ||
| 19 | client.setPublishQueue(TrueMQTT::Client::PublishQueueType::FIFO, 10); | 19 | client.setPublishQueue(TrueMQTT::Client::PublishQueueType::FIFO, 10); |
| 20 | client.setErrorCallback([](TrueMQTT::Client::Error error, std::string message) | 20 | client.setErrorCallback([](TrueMQTT::Client::Error error, std::string message) |
| 21 | { std::cout << "Error " << error << ": " << message << std::endl; }); | 21 | { std::cout << "Error " << error << ": " << message << std::endl; }); |
| 22 | + client.setLastWill("test/lastwill", "example pubsub finished", true); | ||
| 22 | 23 | ||
| 23 | client.connect(); | 24 | client.connect(); |
| 24 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); | 25 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
include/TrueMQTT.h
| @@ -146,12 +146,12 @@ namespace TrueMQTT | @@ -146,12 +146,12 @@ namespace TrueMQTT | ||
| 146 | * @brief Set the last will message on the connection. | 146 | * @brief Set the last will message on the connection. |
| 147 | * | 147 | * |
| 148 | * @param topic The topic to publish the last will message to. | 148 | * @param topic The topic to publish the last will message to. |
| 149 | - * @param payload The payload of the last will message. | 149 | + * @param message The message of the last will message. |
| 150 | * @param retain Whether to retain the last will message. | 150 | * @param retain Whether to retain the last will message. |
| 151 | * | 151 | * |
| 152 | * @note Cannot be called after \ref connect. | 152 | * @note Cannot be called after \ref connect. |
| 153 | */ | 153 | */ |
| 154 | - void setLastWill(const std::string &topic, const std::string &payload, bool retain) const; | 154 | + void setLastWill(const std::string &topic, const std::string &message, bool retain) const; |
| 155 | 155 | ||
| 156 | /** | 156 | /** |
| 157 | * @brief Set the error callback, called when any error occurs. | 157 | * @brief Set the error callback, called when any error occurs. |
| @@ -198,14 +198,14 @@ namespace TrueMQTT | @@ -198,14 +198,14 @@ namespace TrueMQTT | ||
| 198 | void disconnect() const; | 198 | void disconnect() const; |
| 199 | 199 | ||
| 200 | /** | 200 | /** |
| 201 | - * @brief Publish a payload on a topic. | 201 | + * @brief Publish a message on a topic. |
| 202 | * | 202 | * |
| 203 | * After \ref connect is called, this function will either publish the message | 203 | * After \ref connect is called, this function will either publish the message |
| 204 | * immediately (if connected) or queue it for later (if still connecting). | 204 | * immediately (if connected) or queue it for later (if still connecting). |
| 205 | * In the latter case, it will be published as soon as the connection is established. | 205 | * In the latter case, it will be published as soon as the connection is established. |
| 206 | * | 206 | * |
| 207 | - * @param topic The topic to publish the payload on. | ||
| 208 | - * @param payload The payload to publish. | 207 | + * @param topic The topic to publish the message on. |
| 208 | + * @param message The message to publish. | ||
| 209 | * @param retain Whether to retain the message on the broker. | 209 | * @param retain Whether to retain the message on the broker. |
| 210 | * | 210 | * |
| 211 | * @note All messages are always published under QoS 0, and this library supports no | 211 | * @note All messages are always published under QoS 0, and this library supports no |
| @@ -218,7 +218,7 @@ namespace TrueMQTT | @@ -218,7 +218,7 @@ namespace TrueMQTT | ||
| 218 | * moment the connection to the broker is established, and there are messages in the | 218 | * moment the connection to the broker is established, and there are messages in the |
| 219 | * publish queue and/or subscriptions. | 219 | * publish queue and/or subscriptions. |
| 220 | */ | 220 | */ |
| 221 | - void publish(const std::string &topic, const std::string &payload, bool retain) const; | 221 | + void publish(const std::string &topic, const std::string &message, bool retain) const; |
| 222 | 222 | ||
| 223 | /** | 223 | /** |
| 224 | * @brief Subscribe to a topic, and call the callback function when a message arrives. | 224 | * @brief Subscribe to a topic, and call the callback function when a message arrives. |
src/Client.cpp
| @@ -64,7 +64,7 @@ void TrueMQTT::Client::setLogger(Client::LogLevel log_level, const std::function | @@ -64,7 +64,7 @@ void TrueMQTT::Client::setLogger(Client::LogLevel log_level, const std::function | ||
| 64 | LOG_DEBUG(m_impl, "Log level now on " + std::to_string(m_impl->m_log_level)); | 64 | LOG_DEBUG(m_impl, "Log level now on " + std::to_string(m_impl->m_log_level)); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | -void TrueMQTT::Client::setLastWill(const std::string &topic, const std::string &payload, bool retain) const | 67 | +void TrueMQTT::Client::setLastWill(const std::string &topic, const std::string &message, bool retain) const |
| 68 | { | 68 | { |
| 69 | if (m_impl->m_state != Client::Impl::State::DISCONNECTED) | 69 | if (m_impl->m_state != Client::Impl::State::DISCONNECTED) |
| 70 | { | 70 | { |
| @@ -72,10 +72,10 @@ void TrueMQTT::Client::setLastWill(const std::string &topic, const std::string & | @@ -72,10 +72,10 @@ void TrueMQTT::Client::setLastWill(const std::string &topic, const std::string & | ||
| 72 | return; | 72 | return; |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | - LOG_TRACE(m_impl, "Setting last will to topic " + topic + " with payload " + payload + " and retain " + std::to_string(retain)); | 75 | + LOG_TRACE(m_impl, "Setting last will to topic " + topic + " with message " + message + " and retain " + std::to_string(retain)); |
| 76 | 76 | ||
| 77 | m_impl->m_last_will_topic = topic; | 77 | m_impl->m_last_will_topic = topic; |
| 78 | - m_impl->m_last_will_payload = payload; | 78 | + m_impl->m_last_will_message = message; |
| 79 | m_impl->m_last_will_retain = retain; | 79 | m_impl->m_last_will_retain = retain; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| @@ -131,11 +131,11 @@ void TrueMQTT::Client::disconnect() const | @@ -131,11 +131,11 @@ void TrueMQTT::Client::disconnect() const | ||
| 131 | m_impl->disconnect(); | 131 | m_impl->disconnect(); |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | -void TrueMQTT::Client::publish(const std::string &topic, const std::string &payload, bool retain) const | 134 | +void TrueMQTT::Client::publish(const std::string &topic, const std::string &message, bool retain) const |
| 135 | { | 135 | { |
| 136 | std::scoped_lock lock(m_impl->m_state_mutex); | 136 | std::scoped_lock lock(m_impl->m_state_mutex); |
| 137 | 137 | ||
| 138 | - LOG_DEBUG(m_impl, "Publishing message on topic '" + topic + "': " + payload + " (" + (retain ? "retained" : "not retained") + ")"); | 138 | + LOG_DEBUG(m_impl, "Publishing message on topic '" + topic + "': " + message + " (" + (retain ? "retained" : "not retained") + ")"); |
| 139 | 139 | ||
| 140 | switch (m_impl->m_state) | 140 | switch (m_impl->m_state) |
| 141 | { | 141 | { |
| @@ -143,10 +143,10 @@ void TrueMQTT::Client::publish(const std::string &topic, const std::string &payl | @@ -143,10 +143,10 @@ void TrueMQTT::Client::publish(const std::string &topic, const std::string &payl | ||
| 143 | LOG_ERROR(m_impl, "Cannot publish when disconnected"); | 143 | LOG_ERROR(m_impl, "Cannot publish when disconnected"); |
| 144 | return; | 144 | return; |
| 145 | case Client::Impl::State::CONNECTING: | 145 | case Client::Impl::State::CONNECTING: |
| 146 | - m_impl->toPublishQueue(topic, payload, retain); | 146 | + m_impl->toPublishQueue(topic, message, retain); |
| 147 | return; | 147 | return; |
| 148 | case Client::Impl::State::CONNECTED: | 148 | case Client::Impl::State::CONNECTED: |
| 149 | - m_impl->sendPublish(topic, payload, retain); | 149 | + m_impl->sendPublish(topic, message, retain); |
| 150 | return; | 150 | return; |
| 151 | } | 151 | } |
| 152 | } | 152 | } |
| @@ -266,9 +266,9 @@ void TrueMQTT::Client::Impl::connectionStateChange(bool connected) | @@ -266,9 +266,9 @@ void TrueMQTT::Client::Impl::connectionStateChange(bool connected) | ||
| 266 | sendSubscribe(subscription); | 266 | sendSubscribe(subscription); |
| 267 | } | 267 | } |
| 268 | // Flush the publish queue. | 268 | // Flush the publish queue. |
| 269 | - for (const auto &[topic, payload, retain] : m_publish_queue) | 269 | + for (const auto &[topic, message, retain] : m_publish_queue) |
| 270 | { | 270 | { |
| 271 | - sendPublish(topic, payload, retain); | 271 | + sendPublish(topic, message, retain); |
| 272 | } | 272 | } |
| 273 | m_publish_queue.clear(); | 273 | m_publish_queue.clear(); |
| 274 | } | 274 | } |
| @@ -279,7 +279,7 @@ void TrueMQTT::Client::Impl::connectionStateChange(bool connected) | @@ -279,7 +279,7 @@ void TrueMQTT::Client::Impl::connectionStateChange(bool connected) | ||
| 279 | } | 279 | } |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | -void TrueMQTT::Client::Impl::toPublishQueue(const std::string &topic, const std::string &payload, bool retain) | 282 | +void TrueMQTT::Client::Impl::toPublishQueue(const std::string &topic, const std::string &message, bool retain) |
| 283 | { | 283 | { |
| 284 | if (m_state != Client::Impl::State::CONNECTING) | 284 | if (m_state != Client::Impl::State::CONNECTING) |
| 285 | { | 285 | { |
| @@ -309,7 +309,7 @@ void TrueMQTT::Client::Impl::toPublishQueue(const std::string &topic, const std: | @@ -309,7 +309,7 @@ void TrueMQTT::Client::Impl::toPublishQueue(const std::string &topic, const std: | ||
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | LOG_TRACE(this, "Adding message to publish queue"); | 311 | LOG_TRACE(this, "Adding message to publish queue"); |
| 312 | - m_publish_queue.emplace_back(topic, payload, retain); | 312 | + m_publish_queue.emplace_back(topic, message, retain); |
| 313 | } | 313 | } |
| 314 | 314 | ||
| 315 | void TrueMQTT::Client::Impl::findSubscriptionMatch(std::vector<std::function<void(std::string, std::string)>> &matching_callbacks, const std::map<std::string, Client::Impl::SubscriptionPart> &subscriptions, std::deque<std::string> &parts) | 315 | void TrueMQTT::Client::Impl::findSubscriptionMatch(std::vector<std::function<void(std::string, std::string)>> &matching_callbacks, const std::map<std::string, Client::Impl::SubscriptionPart> &subscriptions, std::deque<std::string> &parts) |
| @@ -357,9 +357,9 @@ void TrueMQTT::Client::Impl::findSubscriptionMatch(std::vector<std::function<voi | @@ -357,9 +357,9 @@ void TrueMQTT::Client::Impl::findSubscriptionMatch(std::vector<std::function<voi | ||
| 357 | } | 357 | } |
| 358 | } | 358 | } |
| 359 | 359 | ||
| 360 | -void TrueMQTT::Client::Impl::messageReceived(std::string topic, std::string payload) | 360 | +void TrueMQTT::Client::Impl::messageReceived(std::string topic, std::string message) |
| 361 | { | 361 | { |
| 362 | - LOG_TRACE(this, "Message received on topic '" + topic + "': " + payload); | 362 | + LOG_TRACE(this, "Message received on topic '" + topic + "': " + message); |
| 363 | 363 | ||
| 364 | // Split the topic on the / in parts. | 364 | // Split the topic on the / in parts. |
| 365 | std::string part; | 365 | std::string part; |
| @@ -378,14 +378,14 @@ void TrueMQTT::Client::Impl::messageReceived(std::string topic, std::string payl | @@ -378,14 +378,14 @@ void TrueMQTT::Client::Impl::messageReceived(std::string topic, std::string payl | ||
| 378 | 378 | ||
| 379 | if (matching_callbacks.size() == 1) | 379 | if (matching_callbacks.size() == 1) |
| 380 | { | 380 | { |
| 381 | - // For a single callback there is no need to copy the topic/payload. | ||
| 382 | - matching_callbacks[0](std::move(topic), std::move(payload)); | 381 | + // For a single callback there is no need to copy the topic/message. |
| 382 | + matching_callbacks[0](std::move(topic), std::move(message)); | ||
| 383 | } | 383 | } |
| 384 | else | 384 | else |
| 385 | { | 385 | { |
| 386 | for (const auto &callback : matching_callbacks) | 386 | for (const auto &callback : matching_callbacks) |
| 387 | { | 387 | { |
| 388 | - callback(topic, payload); | 388 | + callback(topic, message); |
| 389 | } | 389 | } |
| 390 | } | 390 | } |
| 391 | } | 391 | } |
src/ClientImpl.h
| @@ -47,12 +47,12 @@ public: | @@ -47,12 +47,12 @@ public: | ||
| 47 | 47 | ||
| 48 | void connect(); ///< Connect to the broker. | 48 | void connect(); ///< Connect to the broker. |
| 49 | void disconnect(); ///< Disconnect from the broker. | 49 | void disconnect(); ///< Disconnect from the broker. |
| 50 | - void sendPublish(const std::string &topic, const std::string &payload, bool retain); ///< Send a publish message to the broker. | 50 | + void sendPublish(const std::string &topic, const std::string &message, bool retain); ///< Send a publish message to the broker. |
| 51 | void sendSubscribe(const std::string &topic); ///< Send a subscribe message to the broker. | 51 | void sendSubscribe(const std::string &topic); ///< Send a subscribe message to the broker. |
| 52 | void sendUnsubscribe(const std::string &topic); ///< Send an unsubscribe message to the broker. | 52 | void sendUnsubscribe(const std::string &topic); ///< Send an unsubscribe message to the broker. |
| 53 | void connectionStateChange(bool connected); ///< Called when a connection goes from CONNECTING state to CONNECTED state or visa versa. | 53 | void connectionStateChange(bool connected); ///< Called when a connection goes from CONNECTING state to CONNECTED state or visa versa. |
| 54 | - void toPublishQueue(const std::string &topic, const std::string &payload, bool retain); ///< Add a publish message to the publish queue. | ||
| 55 | - void messageReceived(std::string topic, std::string payload); ///< Called when a message is received from the broker. | 54 | + void toPublishQueue(const std::string &topic, const std::string &message, bool retain); ///< Add a publish message to the publish queue. |
| 55 | + void messageReceived(std::string topic, std::string message); ///< Called when a message is received from the broker. | ||
| 56 | 56 | ||
| 57 | void findSubscriptionMatch(std::vector<std::function<void(std::string, std::string)>> &callbacks, const std::map<std::string, SubscriptionPart> &subscriptions, std::deque<std::string> &parts); ///< Recursive function to find any matching subscription based on parts. | 57 | void findSubscriptionMatch(std::vector<std::function<void(std::string, std::string)>> &callbacks, const std::map<std::string, SubscriptionPart> &subscriptions, std::deque<std::string> &parts); ///< Recursive function to find any matching subscription based on parts. |
| 58 | 58 | ||
| @@ -71,7 +71,7 @@ public: | @@ -71,7 +71,7 @@ public: | ||
| 71 | std::function<void(Client::LogLevel, std::string)> m_logger = [](Client::LogLevel, std::string) { /* empty */ }; ///< Logger callback. | 71 | std::function<void(Client::LogLevel, std::string)> m_logger = [](Client::LogLevel, std::string) { /* empty */ }; ///< Logger callback. |
| 72 | 72 | ||
| 73 | std::string m_last_will_topic = ""; ///< Topic to publish the last will message to. | 73 | std::string m_last_will_topic = ""; ///< Topic to publish the last will message to. |
| 74 | - std::string m_last_will_payload = ""; ///< Payload of the last will message. | 74 | + std::string m_last_will_message = ""; ///< Message to publish on the last will topic. |
| 75 | bool m_last_will_retain = false; ///< Whether to retain the last will message. | 75 | bool m_last_will_retain = false; ///< Whether to retain the last will message. |
| 76 | 76 | ||
| 77 | std::function<void(Error, std::string)> m_error_callback = [](Error, std::string) { /* empty */ }; ///< Error callback. | 77 | std::function<void(Error, std::string)> m_error_callback = [](Error, std::string) { /* empty */ }; ///< Error callback. |
src/Packet.cpp
| @@ -265,12 +265,12 @@ bool TrueMQTT::Client::Impl::Connection::recvLoop() | @@ -265,12 +265,12 @@ bool TrueMQTT::Client::Impl::Connection::recvLoop() | ||
| 265 | return false; | 265 | return false; |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | - std::string payload; | ||
| 269 | - packet.read_remaining(payload); | 268 | + std::string message; |
| 269 | + packet.read_remaining(message); | ||
| 270 | 270 | ||
| 271 | - LOG_DEBUG(&m_impl, "Received PUBLISH with topic " + topic + ": " + payload); | 271 | + LOG_DEBUG(&m_impl, "Received PUBLISH with topic " + topic + ": " + message); |
| 272 | 272 | ||
| 273 | - m_impl.messageReceived(std::move(topic), std::move(payload)); | 273 | + m_impl.messageReceived(std::move(topic), std::move(message)); |
| 274 | break; | 274 | break; |
| 275 | } | 275 | } |
| 276 | case Packet::PacketType::SUBACK: | 276 | case Packet::PacketType::SUBACK: |
| @@ -366,7 +366,16 @@ void TrueMQTT::Client::Impl::Connection::sendConnect() | @@ -366,7 +366,16 @@ void TrueMQTT::Client::Impl::Connection::sendConnect() | ||
| 366 | 366 | ||
| 367 | uint8_t flags = 0; | 367 | uint8_t flags = 0; |
| 368 | flags |= 1 << 1; // Clean session | 368 | flags |= 1 << 1; // Clean session |
| 369 | - // TODO -- Support for last-will | 369 | + if (!m_impl.m_last_will_topic.empty()) |
| 370 | + { | ||
| 371 | + flags |= 1 << 2; // Last will | ||
| 372 | + flags |= 0 << 3; // Last will QoS | ||
| 373 | + | ||
| 374 | + if (m_impl.m_last_will_retain) | ||
| 375 | + { | ||
| 376 | + flags |= 1 << 5; // Last will retain | ||
| 377 | + } | ||
| 378 | + } | ||
| 370 | 379 | ||
| 371 | Packet packet(Packet::PacketType::CONNECT, 0); | 380 | Packet packet(Packet::PacketType::CONNECT, 0); |
| 372 | 381 | ||
| @@ -377,14 +386,18 @@ void TrueMQTT::Client::Impl::Connection::sendConnect() | @@ -377,14 +386,18 @@ void TrueMQTT::Client::Impl::Connection::sendConnect() | ||
| 377 | packet.write_uint16(30); // Keep-alive | 386 | packet.write_uint16(30); // Keep-alive |
| 378 | 387 | ||
| 379 | packet.write_string(client_id); // Client ID | 388 | packet.write_string(client_id); // Client ID |
| 380 | - // TODO -- Last will topic & message | 389 | + if (!m_impl.m_last_will_topic.empty()) |
| 390 | + { | ||
| 391 | + packet.write_string(m_impl.m_last_will_topic); | ||
| 392 | + packet.write_string(m_impl.m_last_will_message); | ||
| 393 | + } | ||
| 381 | 394 | ||
| 382 | send(packet); | 395 | send(packet); |
| 383 | } | 396 | } |
| 384 | 397 | ||
| 385 | -void TrueMQTT::Client::Impl::sendPublish(const std::string &topic, const std::string &payload, bool retain) | 398 | +void TrueMQTT::Client::Impl::sendPublish(const std::string &topic, const std::string &message, bool retain) |
| 386 | { | 399 | { |
| 387 | - LOG_TRACE(this, "Sending PUBLISH packet to topic '" + topic + "': " + payload + " (" + (retain ? "retained" : "not retained") + ")"); | 400 | + LOG_TRACE(this, "Sending PUBLISH packet to topic '" + topic + "': " + message + " (" + (retain ? "retained" : "not retained") + ")"); |
| 388 | 401 | ||
| 389 | uint8_t flags = 0; | 402 | uint8_t flags = 0; |
| 390 | flags |= (retain ? 1 : 0) << 0; // Retain | 403 | flags |= (retain ? 1 : 0) << 0; // Retain |
| @@ -394,7 +407,7 @@ void TrueMQTT::Client::Impl::sendPublish(const std::string &topic, const std::st | @@ -394,7 +407,7 @@ void TrueMQTT::Client::Impl::sendPublish(const std::string &topic, const std::st | ||
| 394 | Packet packet(Packet::PacketType::PUBLISH, flags); | 407 | Packet packet(Packet::PacketType::PUBLISH, flags); |
| 395 | 408 | ||
| 396 | packet.write_string(topic); | 409 | packet.write_string(topic); |
| 397 | - packet.write(payload.c_str(), payload.size()); | 410 | + packet.write(message.c_str(), message.size()); |
| 398 | 411 | ||
| 399 | m_connection->send(packet); | 412 | m_connection->send(packet); |
| 400 | } | 413 | } |