message.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.com
  6. *
  7. * chinese : http://mqtt.p2hp.com/mqtt-5-0
  8. * english : https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html
  9. *
  10. * Distributed under the Boost Software License, Version 1.0. (See accompanying
  11. * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  12. */
  13. #ifndef __ASIO2_MQTT_MESSAGE_HPP__
  14. #define __ASIO2_MQTT_MESSAGE_HPP__
  15. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  16. #pragma once
  17. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  18. #include <asio2/mqtt/protocol_v3.hpp>
  19. #include <asio2/mqtt/protocol_v4.hpp>
  20. #include <asio2/mqtt/protocol_v5.hpp>
  21. namespace asio2::mqtt
  22. {
  23. template<typename M>
  24. inline constexpr bool is_ctrlmsg()
  25. {
  26. return (is_v3_message<M>() || is_v4_message<M>() || is_v5_message<M>());
  27. }
  28. template<typename M>
  29. inline constexpr bool is_nullmsg()
  30. {
  31. return (std::is_same_v<asio2::detail::remove_cvref_t<M>, mqtt::nullmsg>);
  32. }
  33. template<typename M>
  34. inline constexpr bool is_rawmsg()
  35. {
  36. return (is_ctrlmsg<M>() || is_nullmsg<M>());
  37. }
  38. template<typename M> inline constexpr bool is_connect_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::connect > || std::is_same_v<T, mqtt::v4::connect > || std::is_same_v<T, mqtt::v5::connect >); }
  39. template<typename M> inline constexpr bool is_connack_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::connack > || std::is_same_v<T, mqtt::v4::connack > || std::is_same_v<T, mqtt::v5::connack >); }
  40. template<typename M> inline constexpr bool is_publish_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::publish > || std::is_same_v<T, mqtt::v4::publish > || std::is_same_v<T, mqtt::v5::publish >); }
  41. template<typename M> inline constexpr bool is_puback_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::puback > || std::is_same_v<T, mqtt::v4::puback > || std::is_same_v<T, mqtt::v5::puback >); }
  42. template<typename M> inline constexpr bool is_pubrec_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::pubrec > || std::is_same_v<T, mqtt::v4::pubrec > || std::is_same_v<T, mqtt::v5::pubrec >); }
  43. template<typename M> inline constexpr bool is_pubrel_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::pubrel > || std::is_same_v<T, mqtt::v4::pubrel > || std::is_same_v<T, mqtt::v5::pubrel >); }
  44. template<typename M> inline constexpr bool is_pubcomp_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::pubcomp > || std::is_same_v<T, mqtt::v4::pubcomp > || std::is_same_v<T, mqtt::v5::pubcomp >); }
  45. template<typename M> inline constexpr bool is_subscribe_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::subscribe > || std::is_same_v<T, mqtt::v4::subscribe > || std::is_same_v<T, mqtt::v5::subscribe >); }
  46. template<typename M> inline constexpr bool is_suback_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::suback > || std::is_same_v<T, mqtt::v4::suback > || std::is_same_v<T, mqtt::v5::suback >); }
  47. template<typename M> inline constexpr bool is_unsubscribe_message() { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::unsubscribe> || std::is_same_v<T, mqtt::v4::unsubscribe> || std::is_same_v<T, mqtt::v5::unsubscribe>); }
  48. template<typename M> inline constexpr bool is_unsuback_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::unsuback > || std::is_same_v<T, mqtt::v4::unsuback > || std::is_same_v<T, mqtt::v5::unsuback >); }
  49. template<typename M> inline constexpr bool is_pingreq_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::pingreq > || std::is_same_v<T, mqtt::v4::pingreq > || std::is_same_v<T, mqtt::v5::pingreq >); }
  50. template<typename M> inline constexpr bool is_pingresp_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::pingresp > || std::is_same_v<T, mqtt::v4::pingresp > || std::is_same_v<T, mqtt::v5::pingresp >); }
  51. template<typename M> inline constexpr bool is_disconnect_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v3::disconnect > || std::is_same_v<T, mqtt::v4::disconnect > || std::is_same_v<T, mqtt::v5::disconnect >); }
  52. template<typename M> inline constexpr bool is_auth_message () { using T = asio2::detail::remove_cvref_t<M>; return (std::is_same_v<T, mqtt::v5::auth > || std::is_same_v<T, mqtt::v5::auth > || std::is_same_v<T, mqtt::v5::auth >); }
  53. using message_variant = std::variant<
  54. mqtt::nullmsg , // 0
  55. v3::connect , // 1
  56. v3::connack , // 2
  57. v3::publish , // 3
  58. v3::puback , // 4
  59. v3::pubrec , // 5
  60. v3::pubrel , // 6
  61. v3::pubcomp , // 7
  62. v3::subscribe , // 8
  63. v3::suback , // 9
  64. v3::unsubscribe , // 10
  65. v3::unsuback , // 11
  66. v3::pingreq , // 12
  67. v3::pingresp , // 13
  68. v3::disconnect , // 14
  69. v4::connect , // 15
  70. v4::connack , // 16
  71. v4::publish , // 17
  72. v4::puback , // 18
  73. v4::pubrec , // 19
  74. v4::pubrel , // 20
  75. v4::pubcomp , // 21
  76. v4::subscribe , // 22
  77. v4::suback , // 23
  78. v4::unsubscribe , // 24
  79. v4::unsuback , // 25
  80. v4::pingreq , // 26
  81. v4::pingresp , // 27
  82. v4::disconnect , // 28
  83. v5::connect , // 29
  84. v5::connack , // 30
  85. v5::publish , // 31
  86. v5::puback , // 32
  87. v5::pubrec , // 33
  88. v5::pubrel , // 34
  89. v5::pubcomp , // 35
  90. v5::subscribe , // 36
  91. v5::suback , // 37
  92. v5::unsubscribe , // 38
  93. v5::unsuback , // 39
  94. v5::pingreq , // 40
  95. v5::pingresp , // 41
  96. v5::disconnect , // 42
  97. v5::auth // 43
  98. >;
  99. //using message_index_type = std::conditional_t<
  100. // std::variant_size_v<message_variant> <= (std::numeric_limits<std::uint8_t>::max)(),
  101. // std::uint8_t, std::uint16_t
  102. //>;
  103. namespace detail
  104. {
  105. struct invoke_if_callback_return_type_tag {};
  106. template<class T>
  107. struct invoke_if_callback_return_type
  108. {
  109. using type = T;
  110. };
  111. template<>
  112. struct invoke_if_callback_return_type<void>
  113. {
  114. using type = invoke_if_callback_return_type_tag;
  115. };
  116. }
  117. class message : public message_variant
  118. {
  119. public:
  120. using super = message_variant;
  121. // a default-constructed variant holds a value of its first alternative
  122. message() noexcept : message_variant()
  123. {
  124. }
  125. template<class T, std::enable_if_t<is_rawmsg<T>(), int> = 0>
  126. message(T&& v) : message_variant(std::forward<T>(v))
  127. {
  128. }
  129. template<class T, std::enable_if_t<is_rawmsg<T>(), int> = 0>
  130. message& operator=(T&& v)
  131. {
  132. this->base() = std::forward<T>(v);
  133. return (*this);
  134. }
  135. message(message&&) noexcept = default;
  136. message(message const&) = default;
  137. message& operator=(message&&) noexcept = default;
  138. message& operator=(message const&) = default;
  139. template<class T, std::enable_if_t<is_rawmsg<T>(), int> = 0>
  140. operator T&()
  141. {
  142. return std::get<T>(this->base());
  143. }
  144. template<class T, std::enable_if_t<is_rawmsg<T>(), int> = 0>
  145. operator const T&()
  146. {
  147. return std::get<T>(this->base());
  148. }
  149. template<class T, std::enable_if_t<is_rawmsg<T>(), int> = 0>
  150. operator const T&() const
  151. {
  152. return std::get<T>(this->base());
  153. }
  154. template<class T, std::enable_if_t<is_rawmsg<T>(), int> = 0>
  155. operator T*() noexcept
  156. {
  157. return std::get_if<T>(std::addressof(this->base()));
  158. }
  159. template<class T, std::enable_if_t<is_rawmsg<T>(), int> = 0>
  160. operator const T*() noexcept
  161. {
  162. return std::get_if<T>(std::addressof(this->base()));
  163. }
  164. template<class T, std::enable_if_t<is_rawmsg<T>(), int> = 0>
  165. operator const T*() const noexcept
  166. {
  167. return std::get_if<T>(std::addressof(this->base()));
  168. }
  169. /**
  170. * this overload will cause compile error on gcc, i don't know why:
  171. * mqtt::message msg(mqtt::v3::subscribe{});
  172. * mqtt::v3::subscribe sub = static_cast<mqtt::v3::subscribe>(msg);
  173. * compile error : call of overloaded subscribe(asio2::mqtt::message&) is ambiguous
  174. */
  175. //template<class T, std::enable_if_t<is_rawmsg<T>(), int> = 0>
  176. //operator T()
  177. //{
  178. // return std::get<T>(this->base());
  179. //}
  180. /// Returns the base variant of the message
  181. inline super const& base() const noexcept { return *this; }
  182. /// Returns the base variant of the message
  183. inline super& base() noexcept { return *this; }
  184. /// Returns the base variant of the message
  185. inline super const& variant() const noexcept { return *this; }
  186. /// Returns the base variant of the message
  187. inline super& variant() noexcept { return *this; }
  188. /**
  189. * @brief Checks if the variant holds anyone of the alternative Types...
  190. */
  191. template<class... Types>
  192. inline bool has() const noexcept
  193. {
  194. return (std::holds_alternative<Types>(this->base()) || ...);
  195. }
  196. /**
  197. * @brief Checks if the variant holds anyone of the alternative Types...
  198. */
  199. template<class... Types>
  200. inline bool holds() const noexcept
  201. {
  202. return (std::holds_alternative<Types>(this->base()) || ...);
  203. }
  204. /**
  205. * @brief Checks if the variant holds any v3 message
  206. */
  207. inline bool holds_v3_message() const noexcept
  208. {
  209. int i = static_cast<int>(this->base().index());
  210. return (i >= 1 && i <= 14);
  211. }
  212. /**
  213. * @brief Checks if the variant holds any v4 message
  214. */
  215. inline bool holds_v4_message() const noexcept
  216. {
  217. int i = static_cast<int>(this->base().index());
  218. return (i >= 15 && i <= 28);
  219. }
  220. /**
  221. * @brief Checks if the variant holds any v5 message
  222. */
  223. inline bool holds_v5_message() const noexcept
  224. {
  225. int i = static_cast<int>(this->base().index());
  226. return (i >= 29 && i <= 43);
  227. }
  228. /**
  229. * @brief If this holds the alternative T, returns a pointer to the value stored in the variant.
  230. * Otherwise, returns a null pointer value.
  231. */
  232. template<class T>
  233. inline std::add_pointer_t<T> get_if() noexcept
  234. {
  235. return std::get_if<T>(std::addressof(this->base()));
  236. }
  237. /**
  238. * @brief If this holds the alternative T, returns a pointer to the value stored in the variant.
  239. * Otherwise, returns a null pointer value.
  240. */
  241. template<class T>
  242. inline std::add_pointer_t<std::add_const_t<T>> get_if() const noexcept
  243. {
  244. return std::get_if<T>(std::addressof(this->base()));
  245. }
  246. /**
  247. * @brief If this holds the alternative T, returns a reference to the value stored in the variant.
  248. * Otherwise, throws std::bad_variant_access.
  249. */
  250. template<class T>
  251. inline T& get()
  252. {
  253. return std::get<T>(this->base());
  254. }
  255. /**
  256. * @brief If this holds the alternative T, returns a reference to the value stored in the variant.
  257. * Otherwise, throws std::bad_variant_access.
  258. */
  259. template<class T>
  260. inline T const& get() const
  261. {
  262. return std::get<T>(this->base());
  263. }
  264. /**
  265. * @brief If this holds a valid value.
  266. */
  267. inline bool empty() const noexcept
  268. {
  269. return (this->index() == std::variant_npos || std::holds_alternative<mqtt::nullmsg>(this->base()));
  270. }
  271. /**
  272. * @brief Invoke the callback if the variant holds the alternative Types...
  273. * @return
  274. * If the callback return type is void :
  275. * If the variant holds the alternative Types... , the callback will be called, then return true
  276. * If the variant has't holds the alternative Types... , the callback will not be called, then return false
  277. * If the callback return type is not void :
  278. * If the variant holds the alternative Types... , the callback will be called,
  279. * This return value is the callback returned value.
  280. * If the variant has't holds the alternative Types... , the callback will not be called,
  281. * This return value is a empty object of the callback returned type.
  282. * The callback signature : void(auto& msg) or bool(auto& msg) or others...
  283. */
  284. template<class... Types, class FunctionT>
  285. inline auto invoke_if(FunctionT&& callback) noexcept
  286. {
  287. using return_type = std::tuple_element_t<0, std::tuple<typename
  288. detail::invoke_if_callback_return_type<decltype(callback(std::declval<Types&>()))>::type...>>;
  289. if constexpr (std::is_same_v<return_type, detail::invoke_if_callback_return_type_tag>)
  290. {
  291. return ((this->template _invoke_for_each_type<Types>(callback)) || ...);
  292. }
  293. else
  294. {
  295. return_type r{};
  296. [[maybe_unused]] bool f = ((this->template _invoke_for_each_type<Types>(r, callback)) || ...);
  297. return r;
  298. }
  299. }
  300. protected:
  301. template<class T, class FunctionT>
  302. inline bool _invoke_for_each_type(FunctionT&& callback) noexcept
  303. {
  304. if (std::holds_alternative<T>(this->base()))
  305. {
  306. callback(std::get<T>(this->base()));
  307. return true;
  308. }
  309. return false;
  310. }
  311. template<class T, class ReturnT, class FunctionT>
  312. inline bool _invoke_for_each_type(ReturnT& r, FunctionT&& callback) noexcept
  313. {
  314. if (std::holds_alternative<T>(this->base()))
  315. {
  316. r = callback(std::get<T>(this->base()));
  317. return true;
  318. }
  319. return false;
  320. }
  321. };
  322. template<class, class = void>
  323. struct has_packet_id : std::false_type { };
  324. template<class T>
  325. struct has_packet_id<T, std::void_t<decltype(std::declval<T&>().packet_id())>> : std::true_type { };
  326. template<class Byte>
  327. inline mqtt::control_packet_type message_type_from_byte(Byte byte)
  328. {
  329. mqtt::fixed_header<0>::type_and_flags tf{};
  330. tf.byte = static_cast<std::uint8_t>(byte);
  331. return static_cast<mqtt::control_packet_type>(tf.bits.type);
  332. }
  333. template<typename = void>
  334. inline mqtt::control_packet_type message_type_from_data(std::string_view data)
  335. {
  336. return message_type_from_byte(data.front());
  337. }
  338. template<class Fun>
  339. inline void data_to_message(mqtt::version ver, std::string_view& data, Fun&& f)
  340. {
  341. mqtt::control_packet_type type = mqtt::message_type_from_data(data);
  342. asio2::clear_last_error();
  343. if /**/ (ver == mqtt::version::v3)
  344. {
  345. switch (type)
  346. {
  347. case mqtt::control_packet_type::connect : { mqtt::message m{ mqtt::v3::connect {} }; std::get<mqtt::v3::connect >(m).deserialize(data); f(std::move(m)); } break;
  348. case mqtt::control_packet_type::connack : { mqtt::message m{ mqtt::v3::connack {} }; std::get<mqtt::v3::connack >(m).deserialize(data); f(std::move(m)); } break;
  349. case mqtt::control_packet_type::publish : { mqtt::message m{ mqtt::v3::publish {} }; std::get<mqtt::v3::publish >(m).deserialize(data); f(std::move(m)); } break;
  350. case mqtt::control_packet_type::puback : { mqtt::message m{ mqtt::v3::puback {} }; std::get<mqtt::v3::puback >(m).deserialize(data); f(std::move(m)); } break;
  351. case mqtt::control_packet_type::pubrec : { mqtt::message m{ mqtt::v3::pubrec {} }; std::get<mqtt::v3::pubrec >(m).deserialize(data); f(std::move(m)); } break;
  352. case mqtt::control_packet_type::pubrel : { mqtt::message m{ mqtt::v3::pubrel {} }; std::get<mqtt::v3::pubrel >(m).deserialize(data); f(std::move(m)); } break;
  353. case mqtt::control_packet_type::pubcomp : { mqtt::message m{ mqtt::v3::pubcomp {} }; std::get<mqtt::v3::pubcomp >(m).deserialize(data); f(std::move(m)); } break;
  354. case mqtt::control_packet_type::subscribe : { mqtt::message m{ mqtt::v3::subscribe {} }; std::get<mqtt::v3::subscribe >(m).deserialize(data); f(std::move(m)); } break;
  355. case mqtt::control_packet_type::suback : { mqtt::message m{ mqtt::v3::suback {} }; std::get<mqtt::v3::suback >(m).deserialize(data); f(std::move(m)); } break;
  356. case mqtt::control_packet_type::unsubscribe : { mqtt::message m{ mqtt::v3::unsubscribe {} }; std::get<mqtt::v3::unsubscribe >(m).deserialize(data); f(std::move(m)); } break;
  357. case mqtt::control_packet_type::unsuback : { mqtt::message m{ mqtt::v3::unsuback {} }; std::get<mqtt::v3::unsuback >(m).deserialize(data); f(std::move(m)); } break;
  358. case mqtt::control_packet_type::pingreq : { mqtt::message m{ mqtt::v3::pingreq {} }; std::get<mqtt::v3::pingreq >(m).deserialize(data); f(std::move(m)); } break;
  359. case mqtt::control_packet_type::pingresp : { mqtt::message m{ mqtt::v3::pingresp {} }; std::get<mqtt::v3::pingresp >(m).deserialize(data); f(std::move(m)); } break;
  360. case mqtt::control_packet_type::disconnect : { mqtt::message m{ mqtt::v3::disconnect {} }; std::get<mqtt::v3::disconnect >(m).deserialize(data); f(std::move(m)); } break;
  361. default:
  362. asio2::set_last_error(mqtt::make_error_code(mqtt::error::malformed_packet));
  363. f(mqtt::message{});
  364. break;
  365. }
  366. }
  367. else if (ver == mqtt::version::v4)
  368. {
  369. switch (type)
  370. {
  371. case mqtt::control_packet_type::connect : { mqtt::message m{ mqtt::v4::connect {} }; std::get<mqtt::v4::connect >(m).deserialize(data); f(std::move(m)); } break;
  372. case mqtt::control_packet_type::connack : { mqtt::message m{ mqtt::v4::connack {} }; std::get<mqtt::v4::connack >(m).deserialize(data); f(std::move(m)); } break;
  373. case mqtt::control_packet_type::publish : { mqtt::message m{ mqtt::v4::publish {} }; std::get<mqtt::v4::publish >(m).deserialize(data); f(std::move(m)); } break;
  374. case mqtt::control_packet_type::puback : { mqtt::message m{ mqtt::v4::puback {} }; std::get<mqtt::v4::puback >(m).deserialize(data); f(std::move(m)); } break;
  375. case mqtt::control_packet_type::pubrec : { mqtt::message m{ mqtt::v4::pubrec {} }; std::get<mqtt::v4::pubrec >(m).deserialize(data); f(std::move(m)); } break;
  376. case mqtt::control_packet_type::pubrel : { mqtt::message m{ mqtt::v4::pubrel {} }; std::get<mqtt::v4::pubrel >(m).deserialize(data); f(std::move(m)); } break;
  377. case mqtt::control_packet_type::pubcomp : { mqtt::message m{ mqtt::v4::pubcomp {} }; std::get<mqtt::v4::pubcomp >(m).deserialize(data); f(std::move(m)); } break;
  378. case mqtt::control_packet_type::subscribe : { mqtt::message m{ mqtt::v4::subscribe {} }; std::get<mqtt::v4::subscribe >(m).deserialize(data); f(std::move(m)); } break;
  379. case mqtt::control_packet_type::suback : { mqtt::message m{ mqtt::v4::suback {} }; std::get<mqtt::v4::suback >(m).deserialize(data); f(std::move(m)); } break;
  380. case mqtt::control_packet_type::unsubscribe : { mqtt::message m{ mqtt::v4::unsubscribe {} }; std::get<mqtt::v4::unsubscribe >(m).deserialize(data); f(std::move(m)); } break;
  381. case mqtt::control_packet_type::unsuback : { mqtt::message m{ mqtt::v4::unsuback {} }; std::get<mqtt::v4::unsuback >(m).deserialize(data); f(std::move(m)); } break;
  382. case mqtt::control_packet_type::pingreq : { mqtt::message m{ mqtt::v4::pingreq {} }; std::get<mqtt::v4::pingreq >(m).deserialize(data); f(std::move(m)); } break;
  383. case mqtt::control_packet_type::pingresp : { mqtt::message m{ mqtt::v4::pingresp {} }; std::get<mqtt::v4::pingresp >(m).deserialize(data); f(std::move(m)); } break;
  384. case mqtt::control_packet_type::disconnect : { mqtt::message m{ mqtt::v4::disconnect {} }; std::get<mqtt::v4::disconnect >(m).deserialize(data); f(std::move(m)); } break;
  385. default:
  386. asio2::set_last_error(mqtt::make_error_code(mqtt::error::malformed_packet));
  387. f(mqtt::message{});
  388. break;
  389. }
  390. }
  391. else if (ver == mqtt::version::v5)
  392. {
  393. switch (type)
  394. {
  395. case mqtt::control_packet_type::connect : { mqtt::message m{ mqtt::v5::connect {} }; std::get<mqtt::v5::connect >(m).deserialize(data); f(std::move(m)); } break;
  396. case mqtt::control_packet_type::connack : { mqtt::message m{ mqtt::v5::connack {} }; std::get<mqtt::v5::connack >(m).deserialize(data); f(std::move(m)); } break;
  397. case mqtt::control_packet_type::publish : { mqtt::message m{ mqtt::v5::publish {} }; std::get<mqtt::v5::publish >(m).deserialize(data); f(std::move(m)); } break;
  398. case mqtt::control_packet_type::puback : { mqtt::message m{ mqtt::v5::puback {} }; std::get<mqtt::v5::puback >(m).deserialize(data); f(std::move(m)); } break;
  399. case mqtt::control_packet_type::pubrec : { mqtt::message m{ mqtt::v5::pubrec {} }; std::get<mqtt::v5::pubrec >(m).deserialize(data); f(std::move(m)); } break;
  400. case mqtt::control_packet_type::pubrel : { mqtt::message m{ mqtt::v5::pubrel {} }; std::get<mqtt::v5::pubrel >(m).deserialize(data); f(std::move(m)); } break;
  401. case mqtt::control_packet_type::pubcomp : { mqtt::message m{ mqtt::v5::pubcomp {} }; std::get<mqtt::v5::pubcomp >(m).deserialize(data); f(std::move(m)); } break;
  402. case mqtt::control_packet_type::subscribe : { mqtt::message m{ mqtt::v5::subscribe {} }; std::get<mqtt::v5::subscribe >(m).deserialize(data); f(std::move(m)); } break;
  403. case mqtt::control_packet_type::suback : { mqtt::message m{ mqtt::v5::suback {} }; std::get<mqtt::v5::suback >(m).deserialize(data); f(std::move(m)); } break;
  404. case mqtt::control_packet_type::unsubscribe : { mqtt::message m{ mqtt::v5::unsubscribe {} }; std::get<mqtt::v5::unsubscribe >(m).deserialize(data); f(std::move(m)); } break;
  405. case mqtt::control_packet_type::unsuback : { mqtt::message m{ mqtt::v5::unsuback {} }; std::get<mqtt::v5::unsuback >(m).deserialize(data); f(std::move(m)); } break;
  406. case mqtt::control_packet_type::pingreq : { mqtt::message m{ mqtt::v5::pingreq {} }; std::get<mqtt::v5::pingreq >(m).deserialize(data); f(std::move(m)); } break;
  407. case mqtt::control_packet_type::pingresp : { mqtt::message m{ mqtt::v5::pingresp {} }; std::get<mqtt::v5::pingresp >(m).deserialize(data); f(std::move(m)); } break;
  408. case mqtt::control_packet_type::disconnect : { mqtt::message m{ mqtt::v5::disconnect {} }; std::get<mqtt::v5::disconnect >(m).deserialize(data); f(std::move(m)); } break;
  409. case mqtt::control_packet_type::auth : { mqtt::message m{ mqtt::v5::auth {} }; std::get<mqtt::v5::auth >(m).deserialize(data); f(std::move(m)); } break;
  410. default:
  411. asio2::set_last_error(mqtt::make_error_code(mqtt::error::malformed_packet));
  412. f(mqtt::message{});
  413. break;
  414. }
  415. }
  416. else
  417. {
  418. asio2::set_last_error(mqtt::make_error_code(mqtt::error::malformed_packet));
  419. f(mqtt::message{});
  420. }
  421. }
  422. template<typename = void>
  423. inline mqtt::version version_from_connect_data(std::string_view data)
  424. {
  425. asio2::clear_last_error();
  426. mqtt::fixed_header<0> header{};
  427. header.deserialize(data);
  428. if (asio2::get_last_error())
  429. return static_cast<mqtt::version>(0);
  430. // The Protocol Name is a UTF-8 Encoded String that represents the protocol name MQTT.
  431. // The string, its offset and length will not be changed by future versions of the MQTT specification.
  432. mqtt::utf8_string protocol_name{};
  433. protocol_name.deserialize(data);
  434. if (asio2::get_last_error())
  435. return static_cast<mqtt::version>(0);
  436. // The 8 bit unsigned value that represents the revision level of the protocol used by the Client.
  437. // The value of the Protocol Level field for the version 3.1.1 of the protocol is 4 (0x04).
  438. mqtt::one_byte_integer protocol_version{};
  439. protocol_version.deserialize(data);
  440. if (asio2::get_last_error())
  441. return static_cast<mqtt::version>(0);
  442. return static_cast<mqtt::version>(protocol_version.value());
  443. }
  444. }
  445. #endif // !__ASIO2_MQTT_MESSAGE_HPP__