topic.h 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /////////////////////////////////////////////////////////////////////////////
  2. /// @file topic.h
  3. /// Declaration of classes for MQTT topics and filters
  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. *******************************************************************************/
  22. #ifndef __mqtt_topic_h
  23. #define __mqtt_topic_h
  24. #include <vector>
  25. #include <variant>
  26. #include "MQTTAsync.h"
  27. #include "mqtt/delivery_token.h"
  28. #include "mqtt/message.h"
  29. #include "mqtt/subscribe_options.h"
  30. #include "mqtt/types.h"
  31. namespace mqtt {
  32. class iasync_client;
  33. /////////////////////////////////////////////////////////////////////////////
  34. /**
  35. * Represents a topic destination, used for publish/subscribe messaging.
  36. *
  37. * This is primarily a convenience class for publishing multiple messages to
  38. * the same topic. It holds all the parameters for publishing the message
  39. * other than the payload: topic, QoS, and retain flag. Each publish
  40. * operation then only needs to supply the payload.
  41. *
  42. * It can also be used to subscribe to the specific topic, but this is not
  43. * the normal use case.
  44. */
  45. class topic
  46. {
  47. /** The client to which this topic is connected */
  48. iasync_client& cli_;
  49. /** The topic name */
  50. string name_;
  51. /** The default QoS */
  52. int qos_;
  53. /** The default retained flag */
  54. bool retained_;
  55. public:
  56. /** A smart/shared pointer to this class. */
  57. using ptr_t = std::shared_ptr<topic>;
  58. /** A smart/shared pointer to this class. */
  59. using const_ptr_t = std::shared_ptr<const topic>;
  60. /**
  61. * Construct an MQTT topic destination for messages.
  62. * @param cli Client to which the topic is attached
  63. * @param name The topic string
  64. * @param qos The default QoS for publishing.
  65. * @param retained The default retained flag for the topic.
  66. */
  67. topic(
  68. iasync_client& cli, const string& name, int qos = message::DFLT_QOS,
  69. bool retained = message::DFLT_RETAINED
  70. )
  71. : cli_(cli), name_(name), qos_(qos), retained_(retained) {}
  72. /**
  73. * Creates a new topic.
  74. * @param cli Client to which the topic is attached
  75. * @param name The topic string
  76. * @param qos The default QoS for publishing.
  77. * @param retained The default retained flag for the topic.
  78. * @return A shared pointer to the topic.
  79. */
  80. static ptr_t create(
  81. iasync_client& cli, const string& name, int qos = message::DFLT_QOS,
  82. bool retained = message::DFLT_RETAINED
  83. ) {
  84. return std::make_shared<topic>(cli, name, qos, retained);
  85. }
  86. /**
  87. * Gets a reference to the MQTT client used by this topic.
  88. * @return The MQTT client used by this topic
  89. */
  90. iasync_client& get_client() { return cli_; }
  91. /**
  92. * Gets the name of the topic.
  93. * @return The name of the topic.
  94. */
  95. const string& get_name() const { return name_; }
  96. /**
  97. * Splits a topic string into individual fields.
  98. *
  99. * @param topic A slash-delimited MQTT topic string.
  100. * @return A vector containing the fields of the topic.
  101. */
  102. static std::vector<std::string> split(const std::string& topic);
  103. /**
  104. * Gets the default quality of service for this topic.
  105. * @return The default quality of service for this topic.
  106. */
  107. int get_qos() const { return qos_; }
  108. /**
  109. * Gets the default retained flag used for this topic.
  110. * @return The default retained flag used for this topic.
  111. */
  112. bool get_retained() const { return retained_; }
  113. /**
  114. * Sets the default quality of service for this topic.
  115. * @param qos The default quality of service for this topic.
  116. */
  117. void set_qos(int qos) {
  118. message::validate_qos(qos);
  119. qos_ = qos;
  120. }
  121. /**
  122. * Sets the default retained flag used for this topic.
  123. * @param retained The default retained flag used for this topic.
  124. */
  125. void set_retained(bool retained) { retained_ = retained; }
  126. /**
  127. * Publishes a message on the topic using the default QoS and retained
  128. * flag.
  129. * @param payload the bytes to use as the message payload
  130. * @param n the number of bytes in the payload
  131. * @return The delivery token used to track and wait for the publish to
  132. * complete.
  133. */
  134. delivery_token_ptr publish(const void* payload, size_t n);
  135. /**
  136. * Publishes a message on the topic.
  137. * @param payload the bytes to use as the message payload
  138. * @param n the number of bytes in the payload
  139. * @param qos the Quality of Service to deliver the message at. Valid
  140. * values are 0, 1 or 2.
  141. * @param retained whether or not this message should be retained by the
  142. * server.
  143. * @return The delivery token used to track and wait for the publish to
  144. * complete.
  145. */
  146. delivery_token_ptr publish(const void* payload, size_t n, int qos, bool retained);
  147. /**
  148. * Publishes a message on the topic using the default QoS and retained
  149. * flag.
  150. * @param payload the bytes to use as the message payload
  151. * @return The delivery token used to track and wait for the publish to
  152. * complete.
  153. */
  154. delivery_token_ptr publish(binary_ref payload);
  155. /**
  156. * Publishes a message on the topic.
  157. * @param payload the bytes to use as the message payload
  158. * @param qos the Quality of Service to deliver the message at. Valid
  159. * values are 0, 1 or 2.
  160. * @param retained whether or not this message should be retained by the
  161. * server.
  162. * @return The delivery token used to track and wait for the publish to
  163. * complete.
  164. */
  165. delivery_token_ptr publish(binary_ref payload, int qos, bool retained);
  166. /**
  167. * Subscribe to the topic.
  168. * @return A token used to track the progress of the operation.
  169. */
  170. token_ptr subscribe(const subscribe_options& opts = subscribe_options());
  171. /**
  172. * Returns a string representation of this topic.
  173. * @return The name of the topic
  174. */
  175. string to_string() const { return name_; }
  176. };
  177. /** A smart/shared pointer to a topic object. */
  178. using topic_ptr = topic::ptr_t;
  179. /** A smart/shared pointer to a const topic object. */
  180. using const_topic_ptr = topic::const_ptr_t;
  181. /////////////////////////////////////////////////////////////////////////////
  182. // Topic Filter
  183. /////////////////////////////////////////////////////////////////////////////
  184. /**
  185. * An MQTT topic filter.
  186. *
  187. * This is a multi-field string, delimited by forward slashes, '/', in which
  188. * fields can contain the wildcards:
  189. *
  190. * '+' - Matches a single field
  191. * '#' - Matches all subsequent fields (must be last field in filter)
  192. *
  193. * It can be used to match against specific topics.
  194. *
  195. * This is simple class for individual topics. For a collection of topics
  196. * mapped to arbitrary values, like queues or callback functions, for
  197. * processing incoming messages, consider the @ref topic_mapper.
  198. */
  199. class topic_filter
  200. {
  201. /**
  202. * If the filter contains wildcards, we split it and store it as a
  203. * vector of the individual fields. Otherwise we store the filter as
  204. * a string and match with a simple string comparison.
  205. */
  206. std::variant<string, std::vector<string>> filter_;
  207. public:
  208. /**
  209. * Creates a new topic filter.
  210. *
  211. * @param filter A string MQTT topic filter. This is a slash ('/')
  212. * delimited topic string that can contain wildcards
  213. * '+' and '#'.
  214. */
  215. explicit topic_filter(const string& filter);
  216. /**
  217. * Determines if the character is a wildcard, '+' or '#'
  218. * @param c The character to check
  219. * @return @em true if `c` is a wildcard, '+' or '#'
  220. */
  221. static bool is_wildcard(char c) { return c == '+' || c == '#'; }
  222. /**
  223. * Determines if the string (field) is a wildcard, "+" or "#"
  224. * @param s The string to check
  225. * @return @em true if `c` is a wildcard, "+" or "#"
  226. */
  227. static bool is_wildcard(const string& s) { return s.size() == 1 && is_wildcard(s[0]); }
  228. /**
  229. * Determines if the specified topic/filter contains any wildcards.
  230. *
  231. * @param filter The topic/filter string to check for wildcards.
  232. * @return @em true if any of the fields contain a wildcard, @em false
  233. * if not.
  234. */
  235. static bool has_wildcards(const string& filter);
  236. /**
  237. * Determines if this topic filter contains any wildcards.
  238. *
  239. * @return @em true if any of the fields contain a wildcard, @em false
  240. * if not.
  241. */
  242. bool has_wildcards() const;
  243. /**
  244. * Determine if the topic matches this filter.
  245. *
  246. * @param topic An MQTT topic. It should not contain wildcards.
  247. * @return @em true of the topic matches this filter, @em false
  248. * otherwise.
  249. */
  250. bool matches(const string& topic) const;
  251. /**
  252. * Gets the topic filter string.
  253. * @return The topic filter string.
  254. */
  255. string to_string() const;
  256. };
  257. /////////////////////////////////////////////////////////////////////////////
  258. } // namespace mqtt
  259. #endif // __mqtt_topic_h