message.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  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-2023 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 "MQTTAsync.h"
  26. #include "mqtt/buffer_ref.h"
  27. #include "mqtt/properties.h"
  28. #include "mqtt/exception.h"
  29. #include "mqtt/platform.h"
  30. #include <memory>
  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. PAHO_MQTTPP_EXPORT static const int DFLT_QOS; // =0
  54. /** The default retained flag */
  55. PAHO_MQTTPP_EXPORT static const bool DFLT_RETAINED; // =false
  56. private:
  57. /** Initializer for the C struct (from the C library) */
  58. PAHO_MQTTPP_EXPORT static const MQTTAsync_message DFLT_C_STRUCT;
  59. /** The underlying C message struct */
  60. MQTTAsync_message msg_;
  61. /** The topic that the message was (or should be) sent on. */
  62. string_ref topic_;
  63. /** The message payload - an arbitrary binary blob. */
  64. binary_ref payload_;
  65. /** The properties for the message */
  66. properties props_;
  67. /** The client has special access. */
  68. friend class async_client;
  69. /**
  70. * Set the dup flag in the underlying message
  71. * @param dup
  72. */
  73. void set_duplicate(bool dup) { msg_.dup = to_int(dup); }
  74. public:
  75. /** Smart/shared pointer to this class. */
  76. using ptr_t = std::shared_ptr<message>;
  77. /** Smart/shared pointer to this class. */
  78. using const_ptr_t = std::shared_ptr<const message>;
  79. /**
  80. * Constructs a message with an empty payload, and all other values set
  81. * to defaults.
  82. */
  83. message();
  84. /**
  85. * Constructs a message with the specified array as a payload, and all
  86. * other values set to defaults.
  87. * @param topic The message topic
  88. * @param payload the bytes to use as the message payload
  89. * @param len the number of bytes in the payload
  90. * @param qos The quality of service for the message.
  91. * @param retained Whether the message should be retained by the broker.
  92. * @param props The MQTT v5 properties for the message.
  93. */
  94. message(string_ref topic, const void* payload, size_t len,
  95. int qos, bool retained,
  96. const properties& props=properties());
  97. /**
  98. * Constructs a message with the specified array as a payload, and all
  99. * other values set to defaults.
  100. * @param topic The message topic
  101. * @param payload the bytes to use as the message payload
  102. * @param len the number of bytes in the payload
  103. */
  104. message(string_ref topic, const void* payload, size_t len)
  105. : message(std::move(topic), payload, len, DFLT_QOS, DFLT_RETAINED) {}
  106. /**
  107. * Constructs a message from a byte buffer.
  108. * Note that the payload accepts copy or move semantics.
  109. * @param topic The message topic
  110. * @param payload A byte buffer to use as the message payload.
  111. * @param qos The quality of service for the message.
  112. * @param retained Whether the message should be retained by the broker.
  113. * @param props The MQTT v5 properties for the message.
  114. */
  115. message(string_ref topic, binary_ref payload, int qos, bool retained,
  116. const properties& props=properties());
  117. /**
  118. * Constructs a message from a byte buffer.
  119. * Note that the payload accepts copy or move semantics.
  120. * @param topic The message topic
  121. * @param payload A byte buffer to use as the message payload.
  122. */
  123. message(string_ref topic, binary_ref payload)
  124. : message(std::move(topic), std::move(payload), DFLT_QOS, DFLT_RETAINED) {}
  125. /**
  126. * Constructs a message as a copy of the message structure.
  127. * @param topic The message topic
  128. * @param cmsg A "C" MQTTAsync_message structure.
  129. */
  130. message(string_ref topic, const MQTTAsync_message& cmsg);
  131. /**
  132. * Constructs a message as a copy of the other message.
  133. * @param other The message to copy into this one.
  134. */
  135. message(const message& other);
  136. /**
  137. * Moves the other message to this one.
  138. * @param other The message to move into this one.
  139. */
  140. message(message&& other);
  141. /**
  142. * Destroys a message and frees all associated resources.
  143. */
  144. ~message() {}
  145. /**
  146. * Constructs a message with the specified array as a payload, and all
  147. * other values set to defaults.
  148. * @param topic The message topic
  149. * @param payload the bytes to use as the message payload
  150. * @param len the number of bytes in the payload
  151. * @param qos The quality of service for the message.
  152. * @param retained Whether the message should be retained by the broker.
  153. * @param props The MQTT v5 properties for the message.
  154. */
  155. static ptr_t create(string_ref topic, const void* payload, size_t len,
  156. int qos, bool retained, const properties& props=properties()) {
  157. return std::make_shared<message>(std::move(topic), payload, len,
  158. qos, retained, props);
  159. }
  160. /**
  161. * Constructs a message with the specified array as a payload, and all
  162. * other values set to defaults.
  163. * @param topic The message topic
  164. * @param payload the bytes to use as the message payload
  165. * @param len the number of bytes in the payload
  166. */
  167. static ptr_t create(string_ref topic, const void* payload, size_t len) {
  168. return std::make_shared<message>(std::move(topic), payload, len,
  169. DFLT_QOS, DFLT_RETAINED);
  170. }
  171. /**
  172. * Constructs a message from a byte buffer.
  173. * Note that the payload accepts copy or move semantics.
  174. * @param topic The message topic
  175. * @param payload A byte buffer to use as the message payload.
  176. * @param qos The quality of service for the message.
  177. * @param retained Whether the message should be retained by the broker.
  178. * @param props The MQTT v5 properties for the message.
  179. */
  180. static ptr_t create(string_ref topic, binary_ref payload, int qos, bool retained,
  181. const properties& props=properties()) {
  182. return std::make_shared<message>(std::move(topic), std::move(payload),
  183. qos, retained, props);
  184. }
  185. /**
  186. * Constructs a message from a byte buffer.
  187. * Note that the payload accepts copy or move semantics.
  188. * @param topic The message topic
  189. * @param payload A byte buffer to use as the message payload.
  190. */
  191. static ptr_t create(string_ref topic, binary_ref payload) {
  192. return std::make_shared<message>(std::move(topic), std::move(payload),
  193. DFLT_QOS, DFLT_RETAINED);
  194. }
  195. /**
  196. * Constructs a message as a copy of the C message struct.
  197. * @param topic The message topic
  198. * @param msg A "C" MQTTAsync_message structure.
  199. */
  200. static ptr_t create(string_ref topic, const MQTTAsync_message& msg) {
  201. return std::make_shared<message>(std::move(topic), msg);
  202. }
  203. /**
  204. * Copies another message to this one.
  205. * @param rhs The other message.
  206. * @return A reference to this message.
  207. */
  208. message& operator=(const message& rhs);
  209. /**
  210. * Moves another message to this one.
  211. * @param rhs The other message.
  212. * @return A reference to this message.
  213. */
  214. message& operator=(message&& rhs);
  215. /**
  216. * Expose the underlying C struct for the unit tests.
  217. */
  218. #if defined(UNIT_TESTS)
  219. const MQTTAsync_message& c_struct() const { return msg_; }
  220. #endif
  221. /**
  222. * Sets the topic string.
  223. * @param topic The topic on which the message is published.
  224. */
  225. void set_topic(string_ref topic) {
  226. topic_ = topic ? std::move(topic) : string_ref(string());
  227. }
  228. /**
  229. * Gets the topic reference for the message.
  230. * @return The topic reference for the message.
  231. */
  232. const string_ref& get_topic_ref() const { return topic_; }
  233. /**
  234. * Gets the topic for the message.
  235. * @return The topic string for the message.
  236. */
  237. const string& get_topic() const {
  238. static const string EMPTY_STR;
  239. return topic_ ? topic_.str() : EMPTY_STR;
  240. }
  241. /**
  242. * Clears the payload, resetting it to be empty.
  243. */
  244. void clear_payload();
  245. /**
  246. * Gets the payload reference.
  247. */
  248. const binary_ref& get_payload_ref() const { return payload_; }
  249. /**
  250. * Gets the payload
  251. */
  252. const binary& get_payload() const {
  253. static const binary EMPTY_BIN;
  254. return payload_ ? payload_.str() : EMPTY_BIN;
  255. }
  256. /**
  257. * Gets the payload as a string
  258. */
  259. const string& get_payload_str() const {
  260. static const string EMPTY_STR;
  261. return payload_ ? payload_.str() : EMPTY_STR;
  262. }
  263. /**
  264. * Returns the quality of service for this message.
  265. * @return The quality of service for this message.
  266. */
  267. int get_qos() const { return msg_.qos; }
  268. /**
  269. * Returns whether or not this message might be a duplicate of one which
  270. * has already been received.
  271. * @return true this message might be a duplicate of one which
  272. * has already been received, false otherwise
  273. */
  274. bool is_duplicate() const { return to_bool(msg_.dup); }
  275. /**
  276. * Returns whether or not this message should be/was retained by the
  277. * server.
  278. * @return true if this message should be/was retained by the
  279. * server, false otherwise.
  280. */
  281. bool is_retained() const { return to_bool(msg_.retained); }
  282. /**
  283. * Sets the payload of this message to be the specified buffer.
  284. * Note that this accepts copy or move operations:
  285. * set_payload(buf);
  286. * set_payload(std::move(buf));
  287. * @param payload A buffer to use as the message payload.
  288. */
  289. void set_payload(binary_ref payload);
  290. /**
  291. * Sets the payload of this message to be the specified byte array.
  292. * @param payload the bytes to use as the message payload
  293. * @param n the number of bytes in the payload
  294. */
  295. void set_payload(const void* payload, size_t n) {
  296. set_payload(binary_ref(static_cast<const binary_ref::value_type*>(payload), n));
  297. }
  298. /**
  299. * Sets the quality of service for this message.
  300. * @param qos The integer Quality of Service for the message
  301. */
  302. void set_qos(int qos) {
  303. validate_qos(qos);
  304. msg_.qos = qos;
  305. }
  306. /**
  307. * Determines if the QOS value is a valid one.
  308. * @param qos The QOS value.
  309. * @throw std::invalid_argument If the qos value is invalid.
  310. */
  311. static void validate_qos(int qos) {
  312. if (qos < 0 || qos > 2)
  313. throw exception(MQTTASYNC_BAD_QOS, "Bad QoS");
  314. }
  315. /**
  316. * Whether or not the publish message should be retained by the broker.
  317. * @param retained @em true if the message should be retained by the
  318. * broker, @em false if not.
  319. */
  320. void set_retained(bool retained) { msg_.retained = to_int(retained); }
  321. /**
  322. * Gets the properties in the message.
  323. * @return A const reference to the properties in the message.
  324. */
  325. const properties& get_properties() const {
  326. return props_;
  327. }
  328. /**
  329. * Sets the properties in the message.
  330. * @param props The properties to place into the message.
  331. */
  332. void set_properties(const properties& props) {
  333. props_ = props;
  334. msg_.properties = props_.c_struct();
  335. }
  336. /**
  337. * Moves the properties into the message.
  338. * @param props The properties to move into the message.
  339. */
  340. void set_properties(properties&& props) {
  341. props_ = std::move(props);
  342. msg_.properties = props_.c_struct();
  343. }
  344. /**
  345. * Returns a string representation of this messages payload.
  346. * @return A string representation of this messages payload.
  347. */
  348. string to_string() const { return get_payload_str(); }
  349. };
  350. /** Smart/shared pointer to a message */
  351. using message_ptr = message::ptr_t;
  352. /** Smart/shared pointer to a const message */
  353. using const_message_ptr = message::const_ptr_t;
  354. /**
  355. * Constructs a message with the specified array as a payload, and all
  356. * other values set to defaults.
  357. * @param topic The message topic
  358. * @param payload the bytes to use as the message payload
  359. * @param len the number of bytes in the payload
  360. */
  361. inline message_ptr make_message(string_ref topic, const void* payload, size_t len) {
  362. return mqtt::message::create(std::move(topic), payload, len);
  363. }
  364. /**
  365. * Constructs a message with the specified array as a payload, and all
  366. * other values set to defaults.
  367. * @param topic The message topic
  368. * @param payload the bytes to use as the message payload
  369. * @param len the number of bytes in the payload
  370. * @param qos The quality of service for the message.
  371. * @param retained Whether the message should be retained by the broker.
  372. */
  373. inline message_ptr make_message(string_ref topic, const void* payload, size_t len,
  374. int qos, bool retained) {
  375. return mqtt::message::create(std::move(topic), payload, len, qos, retained);
  376. }
  377. /**
  378. * Constructs a message with the specified buffer as a payload, and
  379. * all other values set to defaults.
  380. * @param topic The message topic
  381. * @param payload A string to use as the message payload.
  382. */
  383. inline message_ptr make_message(string_ref topic, binary_ref payload) {
  384. return mqtt::message::create(std::move(topic), std::move(payload));
  385. }
  386. /**
  387. * Constructs a message with the specified values.
  388. * @param topic The message topic
  389. * @param payload A buffer to use as the message payload.
  390. * @param qos The quality of service for the message.
  391. * @param retained Whether the message should be retained by the broker.
  392. */
  393. inline message_ptr make_message(string_ref topic, binary_ref payload,
  394. int qos, bool retained) {
  395. return mqtt::message::create(std::move(topic), std::move(payload), qos, retained);
  396. }
  397. /////////////////////////////////////////////////////////////////////////////
  398. /**
  399. * Class to build messages.
  400. */
  401. class message_ptr_builder
  402. {
  403. /** The underlying message */
  404. message_ptr msg_;
  405. public:
  406. /** This class */
  407. using self = message_ptr_builder;
  408. /**
  409. * Default constructor.
  410. */
  411. message_ptr_builder() : msg_{ std::make_shared<message>() } {}
  412. /**
  413. * Sets the topic string.
  414. * @param topic The topic on which the message is published.
  415. */
  416. auto topic(string_ref topic) -> self& {
  417. msg_->set_topic(topic);
  418. return *this;
  419. }
  420. /**
  421. * Sets the payload of this message to be the specified buffer.
  422. * Note that this accepts copy or move operations:
  423. * set_payload(buf);
  424. * set_payload(std::move(buf));
  425. * @param payload A buffer to use as the message payload.
  426. */
  427. auto payload(binary_ref payload) -> self& {
  428. msg_->set_payload(payload);
  429. return *this;
  430. }
  431. /**
  432. * Sets the payload of this message to be the specified byte array.
  433. * @param payload the bytes to use as the message payload
  434. * @param n the number of bytes in the payload
  435. */
  436. auto payload(const void* payload, size_t n) -> self& {
  437. msg_->set_payload(payload, n);
  438. return *this;
  439. }
  440. /**
  441. * Sets the quality of service for this message.
  442. * @param qos The integer Quality of Service for the message
  443. */
  444. auto qos(int qos) -> self& {
  445. msg_->set_qos(qos);
  446. return *this;
  447. }
  448. /**
  449. * Whether or not the publish message should be retained by the broker.
  450. * @param on @em true if the message should be retained by the broker, @em
  451. * false if not.
  452. */
  453. auto retained(bool on) -> self& {
  454. msg_->set_retained(on);
  455. return *this;
  456. }
  457. /**
  458. * Sets the properties for the disconnect message.
  459. * @param props The properties for the disconnect message.
  460. */
  461. auto properties(mqtt::properties&& props) -> self& {
  462. msg_->set_properties(std::move(props));
  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(const mqtt::properties& props) -> self& {
  470. msg_->set_properties(props);
  471. return *this;
  472. }
  473. /**
  474. * Finish building the options and return them.
  475. * @return The option struct as built.
  476. */
  477. message_ptr finalize() { return msg_; }
  478. };
  479. /////////////////////////////////////////////////////////////////////////////
  480. // end namespace mqtt
  481. }
  482. #endif // __mqtt_message_h