message_bus.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /**
  2. *
  3. * @file message_bus.hpp
  4. * @author zxw
  5. * Copyright 2024, yjrobotics. All rights reserved.
  6. *
  7. * robotics
  8. *
  9. */
  10. #pragma once
  11. //stl
  12. #include <map>
  13. #include <any>
  14. #include <string>
  15. #include <functional>
  16. //boost
  17. #include <boost/noncopyable.hpp>
  18. //robotics
  19. #include "function_traits.hpp"
  20. #include "message_bus_impl.h"
  21. namespace robotics {
  22. namespace v3 {
  23. class message_bus :boost::noncopyable {
  24. public:
  25. /**
  26. * @brief 构造
  27. */
  28. message_bus() {
  29. message_bus_impl_ = message_bus_impl::instance();
  30. }
  31. /**
  32. * @brief 析构
  33. */
  34. ~message_bus() {
  35. }
  36. /**
  37. * @brief 注册消息
  38. * @tparam _Fn
  39. * @param str_topic
  40. * @param observer 观察者
  41. * @param f
  42. * @return
  43. */
  44. template<typename _Fn>
  45. bool bind(const std::string& str_topic, bool observer, _Fn&& f) {
  46. auto func = v3::to_function(std::forward<_Fn>(f));
  47. return add(str_topic, observer, std::move(func));
  48. }
  49. /**
  50. * @brief 注册消息
  51. * @tparam _Fn
  52. * @tparam _Obj
  53. * @param str_topic
  54. * @param observer 观察者
  55. * @param f
  56. * @param obj
  57. * @return
  58. */
  59. template<typename _Fn, typename _Obj>
  60. bool bind(const std::string& str_topic, bool observer, _Fn&& f, _Obj&& obj) {
  61. auto func = v3::to_function((v3::function_traits<_Fn>::stl_function_type)(std::bind_front(std::forward<_Fn>(f), std::forward<_Obj>(obj))));
  62. return add(str_topic, observer, std::move(func));
  63. }
  64. /**
  65. * @brief 发送消息
  66. * @param str_topic
  67. */
  68. template<typename _Ret,bool _BCast = false>
  69. _Ret invoke(const std::string& str_topic) {
  70. using function_type = std::function<_Ret()>;
  71. std::string str_msg_type = str_topic + typeid(function_type).name();
  72. auto funcs = message_bus_impl_->find(str_msg_type);
  73. if constexpr (!_BCast) {
  74. if (std::find_if(funcs.begin(), funcs.end(), [](auto it) {return !it.first; }) == funcs.end()) {
  75. throw std::runtime_error("no function binded to topic " + str_topic);
  76. }
  77. }
  78. if constexpr (std::is_same<_Ret, void>::value) {
  79. for (auto& fn : funcs) {
  80. std::any_cast<function_type>(fn.second)();
  81. }
  82. }
  83. else {
  84. _Ret result = _Ret{};
  85. for (auto& fn : funcs) {
  86. if (!fn.first) {
  87. result = std::any_cast<function_type>(fn.second)();
  88. }
  89. else {
  90. std::any_cast<function_type>(fn.second)();
  91. }
  92. }
  93. return result;
  94. }
  95. }
  96. /**
  97. * @brief 发送消息
  98. * @tparam ..._Args
  99. * @param str_topic
  100. * @param ...args
  101. */
  102. template<typename _Ret, bool _BCast = false,typename... _Args>
  103. _Ret invoke(const std::string& str_topic, _Args ...args) {
  104. using function_type = std::function<_Ret(_Args...)>;
  105. std::string str_msg_type = str_topic + typeid(function_type).name();
  106. auto funcs = message_bus_impl_->find(str_msg_type);
  107. if constexpr (!_BCast) {
  108. if (std::find_if(funcs.begin(), funcs.end(), [](auto it) {return !it.first; }) == funcs.end()) {
  109. throw std::runtime_error("no function binded to topic " + str_topic);
  110. }
  111. }
  112. if constexpr(std::is_same<_Ret, void>::value) {
  113. for(auto &fn : funcs) {
  114. std::any_cast<function_type>(fn.second)(args...);
  115. }
  116. }
  117. else {
  118. _Ret result = _Ret{};
  119. for (auto& fn : funcs) {
  120. if (!fn.first) {
  121. result = std::any_cast<function_type>(fn.second)(args...);
  122. }
  123. else {
  124. std::any_cast<function_type>(fn.second)(args...);
  125. }
  126. }
  127. return result;
  128. }
  129. }
  130. /**
  131. * @brief 移除某个主题,需要主题和消息类型
  132. * @tparam ...Args
  133. * @param strTopic
  134. */
  135. template<typename..._Args>
  136. void remove(const std::string& str_topic) {
  137. using function_type = std::function<void(_Args...)>;
  138. std::string str_msg_type = str_topic + typeid(function_type).name();
  139. message_bus_impl_->remove(str_msg_type);
  140. }
  141. private:
  142. /**
  143. * @brief 单个添加
  144. * @tparam _Fn
  145. * @param str_topic
  146. * @param f
  147. * @return
  148. */
  149. template<typename _Fn>
  150. bool add(const std::string& str_topic, bool observer, _Fn&& f) {
  151. std::string str_msg_type = str_topic + typeid(f).name();
  152. return message_bus_impl_->bind(str_msg_type, observer, std::forward<_Fn>(f));
  153. }
  154. private:
  155. message_bus_impl* message_bus_impl_ = nullptr;
  156. };
  157. }
  158. }