OGLplus  (0.59.0) a C++ wrapper for rendering APIs

ping_pong.hpp
Go to the documentation of this file.
1 
9 #ifndef EAGINE_MESSAGE_BUS_SERVICE_PING_PONG_HPP
10 #define EAGINE_MESSAGE_BUS_SERVICE_PING_PONG_HPP
11 
12 #include "../../bool_aggregate.hpp"
13 #include "../../maybe_unused.hpp"
14 #include "../serialize.hpp"
15 #include "../subscriber.hpp"
16 #include <chrono>
17 #include <vector>
18 
19 namespace eagine::msgbus {
20 //------------------------------------------------------------------------------
21 template <typename Base = subscriber>
22 class pingable : public Base {
23  using This = pingable;
24 
25 protected:
26  using Base::Base;
27 
28  void add_methods() {
29  Base::add_methods();
30  Base::add_method(
31  this, EAGINE_MSG_MAP(eagiMsgBus, ping, This, _handle_ping));
32  }
33 
34 public:
35  virtual auto respond_to_ping(
36  identifier_t pinger_id,
38  verification_bits) -> bool {
39  EAGINE_MAYBE_UNUSED(pinger_id);
40  return true;
41  }
42 
43 private:
44  auto _handle_ping(const message_context&, stored_message& message) -> bool {
45  if(respond_to_ping(
46  message.source_id,
47  message.sequence_no,
48  this->verify_bits(message))) {
49  this->bus().respond_to(message, EAGINE_MSGBUS_ID(pong), {});
50  }
51  return true;
52  }
53 };
54 //------------------------------------------------------------------------------
55 template <typename Base = subscriber>
56 class pinger
57  : public Base
58  , protected std::chrono::steady_clock {
59 
60  using This = pinger;
61 
62  std::vector<std::tuple<identifier_t, message_sequence_t, timeout>>
63  _pending{};
64 
65 protected:
66  using Base::Base;
67 
68  void add_methods() {
69  Base::add_methods();
70  Base::add_method(
71  this, EAGINE_MSG_MAP(eagiMsgBus, pong, This, _handle_pong));
72  }
73 
74 public:
75  static constexpr auto ping_msg_id() noexcept {
76  return EAGINE_MSGBUS_ID(ping);
77  }
78 
79  void query_pingables() {
80  this->bus().query_subscribers_of(ping_msg_id());
81  }
82 
83  void ping(identifier_t pingable_id, std::chrono::milliseconds max_time) {
84  message_view message{};
85  auto msg_id{EAGINE_MSGBUS_ID(ping)};
86  message.set_target_id(pingable_id);
87  message.set_priority(message_priority::low);
88  this->bus().set_next_sequence_id(msg_id, message);
89  this->bus().post(msg_id, message);
90  _pending.emplace_back(message.target_id, message.sequence_no, max_time);
91  }
92 
93  void ping(identifier_t pingable_id) {
94  ping(pingable_id, std::chrono::milliseconds{5000});
95  }
96 
97  auto update() -> bool {
98  some_true something_done{};
99  something_done(Base::update());
100 
101  _pending.erase(
102  std::remove_if(
103  _pending.begin(),
104  _pending.end(),
105  [this, &something_done](auto& entry) {
106  auto& [pingable_id, sequence_no, ping_time] = entry;
107  if(ping_time.is_expired()) {
108  on_ping_timeout(
109  pingable_id,
110  sequence_no,
111  std::chrono::duration_cast<std::chrono::microseconds>(
112  ping_time.elapsed_time()));
113  something_done();
114  return true;
115  }
116  return false;
117  }),
118  _pending.end());
119  return something_done;
120  }
121 
122  auto has_pending_pings() const noexcept -> bool {
123  return !_pending.empty();
124  }
125 
126  virtual void on_ping_response(
127  identifier_t pingable_id,
128  message_sequence_t sequence_no,
129  std::chrono::microseconds age,
130  verification_bits) = 0;
131 
132  virtual void on_ping_timeout(
133  identifier_t pingable_id,
134  message_sequence_t sequence_no,
135  std::chrono::microseconds age) = 0;
136 
137 private:
138  auto _handle_pong(const message_context&, stored_message& message) -> bool {
139  _pending.erase(
140  std::remove_if(
141  _pending.begin(),
142  _pending.end(),
143  [this, &message](auto& entry) {
144  auto& [pingable_id, sequence_no, ping_time] = entry;
145  const bool is_response = (message.source_id == pingable_id) &&
146  (message.sequence_no == sequence_no);
147  if(is_response) {
148  on_ping_response(
149  message.source_id,
150  message.sequence_no,
151  std::chrono::duration_cast<std::chrono::microseconds>(
152  ping_time.elapsed_time()),
153  this->verify_bits(message));
154  return true;
155  }
156  return false;
157  }),
158  _pending.end());
159  return true;
160  }
161 };
162 //------------------------------------------------------------------------------
163 } // namespace eagine::msgbus
164 
165 #endif // EAGINE_MESSAGE_BUS_SERVICE_PING_PONG_HPP
bitfield< verification_bit > verification_bits
Alias for a bus message verification bitfield.
Definition: verification.hpp:47
#define EAGINE_MSG_MAP(CLASS_ID, METHOD_ID, CLASS, METHOD)
Constructs an instance of static message handler map.
Definition: handler_map.hpp:72
auto update() const noexcept -> bool
Updates the internal endpoint state (should be called repeatedly).
Definition: subscriber.hpp:51
std::uint32_t message_sequence_t
Alias for message sequence number type.
Definition: types.hpp:22
Message bus code is placed in this namespace.
Definition: eagine.hpp:58
std::uint64_t identifier_t
The underlying integer type for eagine::identifier.
Definition: identifier_t.hpp:19
@ low
Low message priority.
auto bus() noexcept -> auto &
Returns a reference to the associated endpoint.
Definition: subscriber.hpp:38

Copyright © 2015-2021 Matúš Chochlík.
<chochlik -at -gmail.com>
Documentation generated on Tue Apr 13 2021 by Doxygen (version 1.8.17).