7 #ifndef CPPWAMP_INTERNAL_CALLER_TIMEOUT_HPP
8 #define CPPWAMP_INTERNAL_CALLER_TIMEOUT_HPP
14 #include <boost/asio/steady_timer.hpp>
15 #include <boost/asio/strand.hpp>
16 #include "../asiodefs.hpp"
17 #include "../peerdata.hpp"
26 struct CallerTimeoutRecord
28 using Clock = std::chrono::steady_clock;
29 using Duration = Clock::duration;
30 using Timepoint = Clock::time_point;
32 CallerTimeoutRecord() =
default;
34 CallerTimeoutRecord(Duration timeout,
RequestId rid)
35 : deadline(Clock::now() + timeout),
39 bool operator<(
const CallerTimeoutRecord& rhs)
const
41 return deadline < rhs.deadline;
49 class CallerTimeoutScheduler :
50 public std::enable_shared_from_this<CallerTimeoutScheduler>
53 using Duration = std::chrono::steady_clock::duration;
54 using TimeoutHandler = std::function<void (
RequestId)>;
56 using Ptr = std::shared_ptr<CallerTimeoutScheduler>;
60 return Ptr(
new CallerTimeoutScheduler(std::move(strand)));
63 void listen(TimeoutHandler handler)
65 timeoutHandler_ = std::move(handler);
73 CallerTimeoutRecord rec{timeout, rid};
74 bool wasIdle = deadlines_.empty();
75 bool preemptsCurrentDeadline =
76 !wasIdle && (rec < *deadlines_.begin());
78 deadlines_.insert(rec);
80 processNextDeadline();
81 else if (preemptsCurrentDeadline)
87 if (deadlines_.empty())
90 auto rec = deadlines_.begin();
91 if (rec->requestId == rid)
93 deadlines_.erase(rec);
99 auto end = deadlines_.end();
100 for (; rec != end; ++rec)
102 if (rec->requestId == rid)
104 deadlines_.erase(rec);
112 timeoutHandler_ =
nullptr;
118 using WeakPtr = std::weak_ptr<CallerTimeoutScheduler>;
120 explicit CallerTimeoutScheduler(
IoStrand strand)
121 : timer_(std::move(strand))
124 void processNextDeadline()
126 auto deadline = deadlines_.begin()->deadline;
127 auto requestId = deadlines_.begin()->requestId;
128 timer_.expires_at(deadline);
129 WeakPtr
self(shared_from_this());
130 timer_.async_wait([
self, requestId](boost::system::error_code ec)
132 auto ptr =
self.lock();
134 ptr->onTimer(ec, requestId);
138 void onTimer(boost::system::error_code ec,
RequestId requestId)
140 if (!deadlines_.empty())
142 auto top = deadlines_.begin();
143 bool preempted = top->requestId != requestId;
146 if (!ec && timeoutHandler_)
147 timeoutHandler_(top->requestId);
148 deadlines_.erase(top);
150 if (!deadlines_.empty())
151 processNextDeadline();
155 std::set<CallerTimeoutRecord> deadlines_;
156 boost::asio::steady_timer timer_;
157 TimeoutHandler timeoutHandler_;
164 #endif // CPPWAMP_INTERNAL_CALLER_TIMEOUT_HPP