mal-packet-weaver
C++20 packet serialization/deserialization library.
Loading...
Searching...
No Matches
common.hpp
Go to the documentation of this file.
1#pragma once
2#if defined(_WIN32)
3#include <SDKDDKVer.h>
4#endif
5#include <algorithm>
6#include <boost/asio/awaitable.hpp>
7#include <boost/asio/co_spawn.hpp>
8#include <boost/asio/detached.hpp>
9#include <boost/asio/ip/tcp.hpp>
10#include <boost/asio/read.hpp>
11#include <boost/asio/spawn.hpp>
12#include <boost/asio/steady_timer.hpp>
13#include <boost/asio/streambuf.hpp>
14#include <boost/asio/write.hpp>
15#include <boost/asio/thread_pool.hpp>
16#include <boost/bind/bind.hpp>
17#include <boost/endian/conversion.hpp>
18#include <boost/lockfree/queue.hpp>
19#include <boost/range/begin.hpp>
20#include <boost/range/end.hpp>
21#include <boost/thread.hpp>
22#include <deque>
23#include <future>
24#include <memory>
25#include <mutex>
26#include <queue>
27#include <unordered_map>
28
29#include <cereal/cereal.hpp>
30#include <cereal/types/string.hpp>
31#include <cereal/types/map.hpp>
32#include <cereal/archives/portable_binary.hpp>
33
42{
43 class timeout_exception : public std::runtime_error
44 {
45 public:
46 using std::runtime_error::runtime_error;
47 };
48 class future_failed : public std::runtime_error
49 {
50 public:
51 using std::runtime_error::runtime_error;
52 };
61 using namespace mal_toolkit;
62// clang-format off
63 namespace _await_future_impl
64 {
65 template <typename T, typename ChronoType, typename Executor>
66 boost::asio::awaitable<T> await_future(Executor &executor, std::future<T>& fut, ChronoType timeout)
67 {
68 auto timer = std::shared_ptr<boost::asio::steady_timer>{
69 new boost::asio::steady_timer{executor, timeout}
70 };
71 static boost::thread::attributes attrs;
72 attrs.set_stack_size(4096 * 8); // 32 Kb per thread
73 if constexpr (std::is_same_v<T, void>)
74 {
75 if (fut.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
76 {
77 co_return;
78 }
79 boost::thread thread(attrs,
80 [timer, &fut]()
81 {
82 try { fut.wait(); timer->cancel(); }
83 #ifdef _DEBUG
84 catch (std::exception& e) { spdlog::error("Future failed with exception: {}", e.what()); }
85 #endif
86 catch (...) { timer->cancel(); }
87 });
88 thread.detach();
89 try { co_await timer->async_wait(boost::asio::use_awaitable);}
90 catch(...) { }
91 co_return;
92 }
93 else
94 {
95 if (fut.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
96 {
97 co_return fut.get();
98 }
99 auto result = std::make_shared<std::optional<T>>(std::nullopt);
100 boost::thread thread(attrs,
101 [timer = timer, result = result, &fut]()
102 {
103 try { fut.wait(); *result = fut.get(); timer->cancel(); }
104 #ifdef _DEBUG
105 catch (std::exception& e) { spdlog::error("Future failed with exception: {}", e.what()); }
106 #endif
107 catch (...) { timer->cancel(); }
108 });
109 thread.detach();
110 try { co_await timer->async_wait(boost::asio::use_awaitable); }
111 catch(std::exception &e) { }
112 if (*result == std::nullopt) { throw future_failed{"Future failed for unknown reason."}; }
113 co_return std::move(result->value());
114 }
115 }
116 }
117 template <typename T, typename Executor>
118 boost::asio::awaitable<T> await_future(Executor& executor, std::future<T>& fut)
119 {
120 return _await_future_impl::await_future(executor, fut, std::chrono::steady_clock::time_point::max());
121 }
122
123 template <typename T, typename ChronoType, typename Executor>
124 boost::asio::awaitable<T> await_future(Executor& executor, std::future<T>& fut, ChronoType timeout)
125 {
126 return _await_future_impl::await_future(executor, fut, timeout);
127 }
128// clang-format on
129
131 public:
132 SignalHandler(boost::asio::io_context& io_context) : io_context_(io_context) {}
133
134 // Asynchronously wait for the signal
135 boost::asio::awaitable<void> wait()
136 {
137 auto timer = std::make_shared<boost::asio::steady_timer>(co_await boost::asio::this_coro::executor,
138 std::chrono::steady_clock::time_point::max());
139 {
140 std::lock_guard<std::mutex> lock(mutex_);
141 waiters_.emplace_back(timer);
142 }
143 try
144 {
145 co_await timer->async_wait(boost::asio::use_awaitable);
146 }
147 catch(...) {}
148 }
149 // Asynchronously wait for the signal
150 template <typename ChronoType>
151 boost::asio::awaitable<void> wait(ChronoType timeout)
152 {
153 auto timer = std::make_shared<boost::asio::steady_timer>(co_await boost::asio::this_coro::executor,
154 timeout);
155 {
156 std::lock_guard<std::mutex> lock(mutex_);
157 waiters_.emplace_back(timer);
158 }
159 try
160 {
161 co_await timer->async_wait(boost::asio::use_awaitable);
162 }
163 catch (...) { }
164 }
165
166 // Notify all waiters
167 void notify() {
168 std::deque<std::shared_ptr<boost::asio::steady_timer>> waiters;
169 {
170 std::lock_guard<std::mutex> lock(mutex_);
171 waiters_.swap(waiters);
172 }
173 for (auto& waiter : waiters) {
174 waiter->cancel();
175 }
176 }
177
178 private:
179 boost::asio::io_context& io_context_;
180 std::mutex mutex_;
181 std::deque<std::shared_ptr<boost::asio::steady_timer>> waiters_;
182 };
183
184} // namespace mal_packet_weaver
boost::asio::awaitable< void > wait(ChronoType timeout)
Definition common.hpp:151
boost::asio::io_context & io_context_
Definition common.hpp:179
boost::asio::awaitable< void > wait()
Definition common.hpp:135
std::deque< std::shared_ptr< boost::asio::steady_timer > > waiters_
Definition common.hpp:181
SignalHandler(boost::asio::io_context &io_context)
Definition common.hpp:132
Main header file for the MAL Toolkit library, providing a comprehensive set of tools and utilities.
boost::asio::awaitable< T > await_future(Executor &executor, std::future< T > &fut, ChronoType timeout)
Definition common.hpp:66
This is the main namespace for the Mal Packet Weaver library.
Definition common.hpp:42
boost::asio::awaitable< T > await_future(Executor &executor, std::future< T > &fut)
Definition common.hpp:118
Contains a collection of tools and utilities provided by the MAL Toolkit library.
Definition backoffs.hpp:7