any_authenticator.hpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. //
  2. // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic
  3. //
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_MQTT5_ANY_AUTHENTICATOR
  8. #define BOOST_MQTT5_ANY_AUTHENTICATOR
  9. #include <boost/mqtt5/types.hpp>
  10. #include <boost/asio/any_completion_handler.hpp>
  11. #include <boost/asio/async_result.hpp>
  12. #include <boost/system/error_code.hpp>
  13. #include <boost/type_traits/is_detected.hpp>
  14. #include <boost/type_traits/is_detected_convertible.hpp>
  15. #include <memory>
  16. #include <string>
  17. #include <string_view>
  18. #include <type_traits>
  19. namespace boost::mqtt5::detail {
  20. namespace asio = boost::asio;
  21. using error_code = boost::system::error_code;
  22. using auth_handler_type = asio::any_completion_handler<
  23. void (error_code, std::string)
  24. >;
  25. template <typename T, typename ...Ts>
  26. using async_auth_sig = decltype(
  27. std::declval<T>().async_auth(std::declval<Ts>()...)
  28. );
  29. template <typename T>
  30. using method_sig = decltype(
  31. std::declval<T>().method()
  32. );
  33. template <typename T>
  34. constexpr bool is_authenticator =
  35. boost::is_detected<
  36. async_auth_sig, T,
  37. auth_step_e, std::string, auth_handler_type
  38. >::value &&
  39. boost::is_detected_convertible_v<std::string_view, method_sig, T>;
  40. class auth_fun_base {
  41. using auth_func = void(*)(
  42. auth_step_e, std::string, auth_handler_type, auth_fun_base*
  43. );
  44. auth_func _auth_func;
  45. public:
  46. auth_fun_base(auth_func f) : _auth_func(f) {}
  47. ~auth_fun_base() = default;
  48. void async_auth(
  49. auth_step_e step, std::string data,
  50. auth_handler_type auth_handler
  51. ) {
  52. _auth_func(step, std::move(data), std::move(auth_handler), this);
  53. }
  54. };
  55. template <
  56. typename Authenticator,
  57. typename = std::enable_if_t<is_authenticator<Authenticator>>
  58. >
  59. class auth_fun : public auth_fun_base {
  60. Authenticator _authenticator;
  61. public:
  62. auth_fun(Authenticator authenticator) :
  63. auth_fun_base(&async_auth),
  64. _authenticator(std::forward<Authenticator>(authenticator))
  65. {}
  66. static void async_auth(
  67. auth_step_e step, std::string data, auth_handler_type auth_handler,
  68. auth_fun_base* base_ptr
  69. ) {
  70. auto auth_fun_ptr = static_cast<auth_fun*>(base_ptr);
  71. auth_fun_ptr->_authenticator.async_auth(
  72. step, std::move(data), std::move(auth_handler)
  73. );
  74. }
  75. };
  76. class any_authenticator {
  77. std::string _method;
  78. std::shared_ptr<detail::auth_fun_base> _auth_fun;
  79. public:
  80. any_authenticator() = default;
  81. template <
  82. typename Authenticator,
  83. std::enable_if_t<detail::is_authenticator<Authenticator>, bool> = true
  84. >
  85. any_authenticator(Authenticator&& a) :
  86. _method(a.method()),
  87. _auth_fun(
  88. new detail::auth_fun<Authenticator>(
  89. std::forward<Authenticator>(a)
  90. )
  91. )
  92. {}
  93. std::string_view method() const {
  94. return _method;
  95. }
  96. template <typename CompletionToken>
  97. decltype(auto) async_auth(
  98. auth_step_e step, std::string data,
  99. CompletionToken&& token
  100. ) {
  101. using Signature = void (error_code, std::string);
  102. auto initiation = [](
  103. auto handler, any_authenticator& self,
  104. auth_step_e step, std::string data
  105. ) {
  106. self._auth_fun->async_auth(
  107. step, std::move(data), std::move(handler)
  108. );
  109. };
  110. return asio::async_initiate<CompletionToken, Signature>(
  111. initiation, token, std::ref(*this), step, std::move(data)
  112. );
  113. }
  114. };
  115. } // end namespace boost::mqtt5::detail
  116. #endif // !BOOST_MQTT5_ANY_AUTHENTICATOR