message.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. /////////////////////////////////////////////////////////////////////////////
  2. /// @file message.h
  3. /// Declaration of MQTT message class
  4. /// @date May 1, 2013
  5. /// @author Frank Pagliughi
  6. /////////////////////////////////////////////////////////////////////////////
  7. /*******************************************************************************
  8. * Copyright (c) 2013-2024 Frank Pagliughi <fpagliughi@mindspring.com>
  9. *
  10. * All rights reserved. This program and the accompanying materials
  11. * are made available under the terms of the Eclipse Public License v2.0
  12. * and Eclipse Distribution License v1.0 which accompany this distribution.
  13. *
  14. * The Eclipse Public License is available at
  15. * http://www.eclipse.org/legal/epl-v20.html
  16. * and the Eclipse Distribution License is available at
  17. * http://www.eclipse.org/org/documents/edl-v10.php.
  18. *
  19. * Contributors:
  20. * Frank Pagliughi - initial implementation and documentation
  21. * Frank Pagliughi - MQTT v5 support (properties)
  22. *******************************************************************************/
  23. #ifndef __mqtt_message_h
  24. #define __mqtt_message_h
  25. #include <memory>
  26. #include "MQTTAsync.h"
  27. #include "mqtt/buffer_ref.h"
  28. #include "mqtt/exception.h"
  29. #include "mqtt/platform.h"
  30. #include "mqtt/properties.h"
  31. namespace mqtt {
  32. /////////////////////////////////////////////////////////////////////////////
  33. /**
  34. * An MQTT message holds everything required for an MQTT PUBLISH message.
  35. * This holds the binary message payload, topic string, and all the
  36. * additional meta-data for an MQTT message.
  37. *
  38. * The topic and payload buffers are kept as references to const data, so
  39. * they can be reassigned as needed, but the buffers can not be updated
  40. * in-place. Normally they would be created externally then copied or moved
  41. * into the message. The library to transport the messages never touches the
  42. * payloads or topics.
  43. *
  44. * This also means that message objects are fairly cheap to copy, since they
  45. * don't copy the payloads. They simply copy the reference to the buffers.
  46. * It is safe to pass these buffer references across threads since all
  47. * references promise not to update the contents of the buffer.
  48. */
  49. class message
  50. {
  51. public:
  52. /** The default QoS for a message */
  53. static constexpr int DFLT_QOS = 0;
  54. /** The default retained flag */
  55. static constexpr bool DFLT_RETAINED = false;
  56. private:
  57. /** Initializer for the C struct (from the C library) */
  58. static constexpr MQTTAsync_message DFLT_C_STRUCT MQTTAsync_message_initializer;
  59. /** A const string to use for references */
  60. PAHO_MQTTPP_EXPORT static const string EMPTY_STR;
  61. /** A const binary to use for references */
  62. PAHO_MQTTPP_EXPORT static const binary EMPTY_BIN;
  63. /** The underlying C message struct */
  64. MQTTAsync_message msg_{DFLT_C_STRUCT};
  65. /** The topic that the message was (or should be) sent on. */
  66. string_ref topic_;
  67. /** The message payload - an arbitrary binary blob. */
  68. binary_ref payload_;
  69. /** The properties for the message */
  70. properties props_;
  71. /** The client has special access. */
  72. friend class async_client;
  73. /**
  74. * Set the dup flag in the underlying message
  75. * @param dup Whether to set the dup flag.
  76. */
  77. void set_duplicate(bool dup) { msg_.dup = to_int(dup); }
  78. public:
  79. /** Smart/shared pointer to this class. */
  80. using ptr_t = std::shared_ptr<message>;
  81. /** Smart/shared pointer to this class. */
  82. using const_ptr_t = std::shared_ptr<const message>;
  83. /**
  84. * Constructs a message with an empty payload, and all other values set
  85. * to defaults.
  86. */
  87. message() {}
  88. /**
  89. * Constructs a message with the specified array as a payload, and all
  90. * other values set to defaults.
  91. * @param topic The message topic
  92. * @param payload the bytes to use as the message payload
  93. * @param len the number of bytes in the payload
  94. * @param qos The quality of service for the message.
  95. * @param retained Whether the message should be retained by the broker.
  96. * @param props The MQTT v5 properties for the message.
  97. */
  98. message(
  99. string_ref topic, const void* payload, size_t len, int qos, bool retained,
  100. const properties& props = properties()
  101. );
  102. /**
  103. * Constructs a message with the specified array as a payload, and all
  104. * other values set to defaults.
  105. * @param topic The message topic
  106. * @param payload the bytes to use as the message payload
  107. * @param len the number of bytes in the payload
  108. */
  109. message(string_ref topic, const void* payload, size_t len)
  110. : message(std::move(topic), payload, len, DFLT_QOS, DFLT_RETAINED) {}
  111. /**
  112. * Constructs a message from a byte buffer.
  113. * Note that the payload accepts copy or move semantics.
  114. * @param topic The message topic
  115. * @param payload A byte buffer to use as the message payload.
  116. * @param qos The quality of service for the message.
  117. * @param retained Whether the message should be retained by the broker.
  118. * @param props The MQTT v5 properties for the message.
  119. */
  120. message(
  121. string_ref topic, binary_ref payload, int qos, bool retained,
  122. const properties& props = properties()
  123. );
  124. /**
  125. * Constructs a message from a byte buffer.
  126. * Note that the payload accepts copy or move semantics.
  127. * @param topic The message topic
  128. * @param payload A byte buffer to use as the message payload.
  129. */
  130. message(string_ref topic, binary_ref payload)
  131. : message(std::move(topic), std::move(payload), DFLT_QOS, DFLT_RETAINED) {}
  132. /**
  133. * Constructs a message as a copy of the message structure.
  134. * @param topic The message topic
  135. * @param cmsg A "C" MQTTAsync_message structure.
  136. */
  137. message(string_ref topic, const MQTTAsync_message& cmsg);
  138. /**
  139. * Constructs a message as a copy of the other message.
  140. * @param other The message to copy into this one.
  141. */
  142. message(const message& other);
  143. /**
  144. * Moves the other message to this one.
  145. * @param other The message to move into this one.
  146. */
  147. message(message&& other);
  148. /**
  149. * Destroys a message and frees all associated resources.
  150. */
  151. ~message() {}
  152. /**
  153. * Constructs a message with the specified values.
  154. * @param topic The message topic
  155. * @param payload the bytes to use as the message payload
  156. * @param len the number of bytes in the payload
  157. * @param qos The quality of service for the message.
  158. * @param retained Whether the message should be retained by the broker.
  159. * @param props The MQTT v5 properties for the message.
  160. */
  161. static ptr_t create(
  162. string_ref topic, const void* payload, size_t len, int qos, bool retained,
  163. const properties& props = properties()
  164. ) {
  165. return std::make_shared<message>(
  166. std::move(topic), payload, len, qos, retained, props
  167. );
  168. }
  169. /**
  170. * Constructs a message with the specified array as a payload, and all
  171. * other values set to defaults.
  172. * @param topic The message topic
  173. * @param payload the bytes to use as the message payload
  174. * @param len the number of bytes in the payload
  175. */
  176. static ptr_t create(string_ref topic, const void* payload, size_t len) {
  177. return std::make_shared<message>(
  178. std::move(topic), payload, len, DFLT_QOS, DFLT_RETAINED
  179. );
  180. }
  181. /**
  182. * Constructs a message from a byte buffer.
  183. * Note that the payload accepts copy or move semantics.
  184. * @param topic The message topic
  185. * @param payload A byte buffer to use as the message payload.
  186. * @param qos The quality of service for the message.
  187. * @param retained Whether the message should be retained by the broker.
  188. * @param props The MQTT v5 properties for the message.
  189. */
  190. static ptr_t create(
  191. string_ref topic, binary_ref payload, int qos, bool retained,
  192. const properties& props = properties()
  193. ) {
  194. return std::make_shared<message>(
  195. std::move(topic), std::move(payload), qos, retained, props
  196. );
  197. }
  198. /**
  199. * Constructs a message from a byte buffer.
  200. * Note that the payload accepts copy or move semantics.
  201. * @param topic The message topic
  202. * @param payload A byte buffer to use as the message payload.
  203. */
  204. static ptr_t create(string_ref topic, binary_ref payload) {
  205. return std::make_shared<message>(
  206. std::move(topic), std::move(payload), DFLT_QOS, DFLT_RETAINED
  207. );
  208. }
  209. /**
  210. * Constructs a message as a copy of the C message struct.
  211. * @param topic The message topic
  212. * @param msg A "C" MQTTAsync_message structure.
  213. */
  214. static ptr_t create(string_ref topic, const MQTTAsync_message& msg) {
  215. return std::make_shared<message>(std::move(topic), msg);
  216. }
  217. /**
  218. * Copies another message to this one.
  219. * @param rhs The other message.
  220. * @return A reference to this message.
  221. */
  222. message& operator=(const message& rhs);
  223. /**
  224. * Moves another message to this one.
  225. * @param rhs The other message.
  226. * @return A reference to this message.
  227. */
  228. message& operator=(message&& rhs);
  229. /**
  230. * Expose the underlying C struct for the unit tests.
  231. */
  232. #if defined(UNIT_TESTS)
  233. const MQTTAsync_message& c_struct() const { return msg_; }
  234. #endif
  235. /**
  236. * Sets the topic string.
  237. * @param topic The topic on which the message is published.
  238. */
  239. void set_topic(string_ref topic) {
  240. topic_ = topic ? std::move(topic) : string_ref(string());
  241. }
  242. /**
  243. * Gets the topic reference for the message.
  244. * @return The topic reference for the message.
  245. */
  246. const string_ref& get_topic_ref() const { return topic_; }
  247. /**
  248. * Gets the topic for the message.
  249. * @return The topic string for the message.
  250. */
  251. const string& get_topic() const { return topic_ ? topic_.str() : EMPTY_STR; }
  252. /**
  253. * Clears the payload, resetting it to be empty.
  254. */
  255. void clear_payload();
  256. /**
  257. * Gets the payload reference.
  258. */
  259. const binary_ref& get_payload_ref() const { return payload_; }
  260. /**
  261. * Gets the payload
  262. */
  263. const binary& get_payload() const { return payload_ ? payload_.str() : EMPTY_BIN; }
  264. /**
  265. * Gets the payload as a string
  266. */
  267. const string& get_payload_str() const { return payload_ ? payload_.str() : EMPTY_STR; }
  268. /**
  269. * Returns the quality of service for this message.
  270. * @return The quality of service for this message.
  271. */
  272. int get_qos() const { return msg_.qos; }
  273. /**
  274. * Returns whether or not this message might be a duplicate of one which
  275. * has already been received.
  276. * @return true this message might be a duplicate of one which
  277. * has already been received, false otherwise
  278. */
  279. bool is_duplicate() const { return to_bool(msg_.dup); }
  280. /**
  281. * Returns whether or not this message should be/was retained by the
  282. * server.
  283. * @return true if this message should be/was retained by the
  284. * server, false otherwise.
  285. */
  286. bool is_retained() const { return to_bool(msg_.retained); }
  287. /**
  288. * Sets the payload of this message to be the specified buffer.
  289. * Note that this accepts copy or move operations:
  290. * set_payload(buf);
  291. * set_payload(std::move(buf));
  292. * @param payload A buffer to use as the message payload.
  293. */
  294. void set_payload(binary_ref payload);
  295. /**
  296. * Sets the payload of this message to be the specified byte array.
  297. * @param payload the bytes to use as the message payload
  298. * @param n the number of bytes in the payload
  299. */
  300. void set_payload(const void* payload, size_t n) {
  301. set_payload(binary_ref(static_cast<const binary_ref::value_type*>(payload), n));
  302. }
  303. /**
  304. * Sets the quality of service for this message.
  305. * @param qos The integer Quality of Service for the message
  306. */
  307. void set_qos(int qos) {
  308. validate_qos(qos);
  309. msg_.qos = qos;
  310. }
  311. /**
  312. * Determines if the QOS value is a valid one.
  313. * @param qos The QOS value.
  314. * @throw std::invalid_argument If the qos value is invalid.
  315. */
  316. static void validate_qos(int qos) {
  317. if (qos < 0 || qos > 2)
  318. throw exception(MQTTASYNC_BAD_QOS, "Bad QoS");
  319. }
  320. /**
  321. * Whether or not the publish message should be retained by the broker.
  322. * @param retained @em true if the message should be retained by the
  323. * broker, @em false if not.
  324. */
  325. void set_retained(bool retained) { msg_.retained = to_int(retained); }
  326. /**
  327. * Gets the properties in the message.
  328. * @return A const reference to the properties in the message.
  329. */
  330. const properties& get_properties() const { return props_; }
  331. /**
  332. * Sets the properties in the message.
  333. * @param props The properties to place into the message.
  334. */
  335. void set_properties(const properties& props) {
  336. props_ = props;
  337. msg_.properties = props_.c_struct();
  338. }
  339. /**
  340. * Moves the properties into the message.
  341. * @param props The properties to move into the message.
  342. */
  343. void set_properties(properties&& props) {
  344. props_ = std::move(props);
  345. msg_.properties = props_.c_struct();
  346. }
  347. /**
  348. * Returns a string representation of this messages payload.
  349. * @return A string representation of this messages payload.
  350. */
  351. string to_string() const { return get_payload_str(); }
  352. };
  353. /** Smart/shared pointer to a message */
  354. using message_ptr = message::ptr_t;
  355. /** Smart/shared pointer to a const message */
  356. using const_message_ptr = message::const_ptr_t;
  357. /**
  358. * Constructs a message with the specified array as a payload, and all
  359. * other values set to defaults.
  360. * @param topic The message topic
  361. * @param payload the bytes to use as the message payload
  362. * @param len the number of bytes in the payload
  363. * @param qos The quality of service for the message.
  364. * @param retained Whether the message should be retained by the broker.
  365. * @param props The MQTT v5 properties for the message.
  366. */
  367. inline message_ptr make_message(
  368. string_ref topic, const void* payload, size_t len, int qos, bool retained,
  369. const properties& props = properties()
  370. ) {
  371. return mqtt::message::create(std::move(topic), payload, len, qos, retained, props);
  372. }
  373. /**
  374. * Constructs a message with the specified array as a payload, and all
  375. * other values set to defaults.
  376. * @param topic The message topic
  377. * @param payload the bytes to use as the message payload
  378. * @param len the number of bytes in the payload
  379. */
  380. inline message_ptr make_message(string_ref topic, const void* payload, size_t len) {
  381. return mqtt::message::create(std::move(topic), payload, len);
  382. }
  383. /**
  384. * Constructs a message with the specified values.
  385. * @param topic The message topic
  386. * @param payload A buffer to use as the message payload.
  387. * @param qos The quality of service for the message.
  388. * @param retained Whether the message should be retained by the broker.
  389. */
  390. inline message_ptr make_message(
  391. string_ref topic, binary_ref payload, int qos, bool retained,
  392. const properties& props = properties()
  393. ) {
  394. return mqtt::message::create(std::move(topic), std::move(payload), qos, retained, props);
  395. }
  396. /**
  397. * Constructs a message with the specified buffer as a payload, and
  398. * all other values set to defaults.
  399. * @param topic The message topic
  400. * @param payload A string to use as the message payload.
  401. */
  402. inline message_ptr make_message(string_ref topic, binary_ref payload) {
  403. return mqtt::message::create(std::move(topic), std::move(payload));
  404. }
  405. /////////////////////////////////////////////////////////////////////////////
  406. /**
  407. * Class to build messages.
  408. */
  409. class message_ptr_builder
  410. {
  411. /** The underlying message */
  412. message_ptr msg_;
  413. public:
  414. /** This class */
  415. using self = message_ptr_builder;
  416. /**
  417. * Default constructor.
  418. */
  419. message_ptr_builder() : msg_{std::make_shared<message>()} {}
  420. /**
  421. * Sets the topic string.
  422. * @param topic The topic on which the message is published.
  423. */
  424. auto topic(string_ref topic) -> self& {
  425. msg_->set_topic(topic);
  426. return *this;
  427. }
  428. /**
  429. * Sets the payload of this message to be the specified buffer.
  430. * Note that this accepts copy or move operations:
  431. * set_payload(buf);
  432. * set_payload(std::move(buf));
  433. * @param payload A buffer to use as the message payload.
  434. */
  435. auto payload(binary_ref payload) -> self& {
  436. msg_->set_payload(payload);
  437. return *this;
  438. }
  439. /**
  440. * Sets the payload of this message to be the specified byte array.
  441. * @param payload the bytes to use as the message payload
  442. * @param n the number of bytes in the payload
  443. */
  444. auto payload(const void* payload, size_t n) -> self& {
  445. msg_->set_payload(payload, n);
  446. return *this;
  447. }
  448. /**
  449. * Sets the quality of service for this message.
  450. * @param qos The integer Quality of Service for the message
  451. */
  452. auto qos(int qos) -> self& {
  453. msg_->set_qos(qos);
  454. return *this;
  455. }
  456. /**
  457. * Whether or not the publish message should be retained by the broker.
  458. * @param on @em true if the message should be retained by the broker, @em
  459. * false if not.
  460. */
  461. auto retained(bool on) -> self& {
  462. msg_->set_retained(on);
  463. return *this;
  464. }
  465. /**
  466. * Sets the properties for the disconnect message.
  467. * @param props The properties for the disconnect message.
  468. */
  469. auto properties(mqtt::properties&& props) -> self& {
  470. msg_->set_properties(std::move(props));
  471. return *this;
  472. }
  473. /**
  474. * Sets the properties for the disconnect message.
  475. * @param props The properties for the disconnect message.
  476. */
  477. auto properties(const mqtt::properties& props) -> self& {
  478. msg_->set_properties(props);
  479. return *this;
  480. }
  481. /**
  482. * Finish building the options and return them.
  483. * @return The option struct as built.
  484. */
  485. message_ptr finalize() { return msg_; }
  486. };
  487. /////////////////////////////////////////////////////////////////////////////
  488. } // namespace mqtt
  489. #endif // __mqtt_message_h