feat: Integrate new webserver (#1722)

For #919.
The new web server is not using dosguard yet. It will be fixed by a
separate PR.
This commit is contained in:
Sergey Kuznetsov
2024-11-21 14:48:32 +00:00
committed by GitHub
parent fc3ba07f2e
commit c77154a5e6
90 changed files with 4029 additions and 683 deletions

View File

@@ -31,7 +31,7 @@
namespace util {
CoroutineGroup::CoroutineGroup(boost::asio::yield_context yield, std::optional<int> maxChildren)
CoroutineGroup::CoroutineGroup(boost::asio::yield_context yield, std::optional<size_t> maxChildren)
: timer_{yield.get_executor(), boost::asio::steady_timer::duration::max()}, maxChildren_{maxChildren}
{
}
@@ -41,28 +41,30 @@ CoroutineGroup::~CoroutineGroup()
ASSERT(childrenCounter_ == 0, "CoroutineGroup is destroyed without waiting for child coroutines to finish");
}
bool
CoroutineGroup::canSpawn() const
{
return not maxChildren_.has_value() or childrenCounter_ < *maxChildren_;
}
bool
CoroutineGroup::spawn(boost::asio::yield_context yield, std::function<void(boost::asio::yield_context)> fn)
{
if (not canSpawn())
if (isFull())
return false;
++childrenCounter_;
boost::asio::spawn(yield, [this, fn = std::move(fn)](boost::asio::yield_context yield) {
fn(yield);
--childrenCounter_;
if (childrenCounter_ == 0)
timer_.cancel();
onCoroutineCompleted();
});
return true;
}
std::optional<std::function<void()>>
CoroutineGroup::registerForeign()
{
if (isFull())
return std::nullopt;
++childrenCounter_;
return [this]() { onCoroutineCompleted(); };
}
void
CoroutineGroup::asyncWait(boost::asio::yield_context yield)
{
@@ -79,4 +81,20 @@ CoroutineGroup::size() const
return childrenCounter_;
}
bool
CoroutineGroup::isFull() const
{
return maxChildren_.has_value() && childrenCounter_ >= *maxChildren_;
}
void
CoroutineGroup::onCoroutineCompleted()
{
ASSERT(childrenCounter_ != 0, "onCoroutineCompleted() called more times than the number of child coroutines");
--childrenCounter_;
if (childrenCounter_ == 0)
timer_.cancel();
}
} // namespace util

View File

@@ -22,6 +22,7 @@
#include <boost/asio/spawn.hpp>
#include <boost/asio/steady_timer.hpp>
#include <atomic>
#include <cstddef>
#include <functional>
#include <optional>
@@ -31,11 +32,12 @@ namespace util {
/**
* @brief CoroutineGroup is a helper class to manage a group of coroutines. It allows to spawn multiple coroutines and
* wait for all of them to finish.
* @note This class is safe to use from multiple threads.
*/
class CoroutineGroup {
boost::asio::steady_timer timer_;
std::optional<int> maxChildren_;
int childrenCounter_{0};
std::optional<size_t> maxChildren_;
std::atomic_size_t childrenCounter_{0};
public:
/**
@@ -45,7 +47,7 @@ public:
* @param maxChildren The maximum number of coroutines that can be spawned at the same time. If not provided, there
* is no limit
*/
CoroutineGroup(boost::asio::yield_context yield, std::optional<int> maxChildren = std::nullopt);
CoroutineGroup(boost::asio::yield_context yield, std::optional<size_t> maxChildren = std::nullopt);
/**
* @brief Destroy the Coroutine Group object
@@ -54,14 +56,6 @@ public:
*/
~CoroutineGroup();
/**
* @brief Check if a new coroutine can be spawned (i.e. there is space for a new coroutine in the group)
*
* @return true If a new coroutine can be spawned. false if the maximum number of coroutines has been reached
*/
bool
canSpawn() const;
/**
* @brief Spawn a new coroutine in the group
*
@@ -74,6 +68,16 @@ public:
bool
spawn(boost::asio::yield_context yield, std::function<void(boost::asio::yield_context)> fn);
/**
* @brief Register a foreign coroutine this group should wait for.
* @note A foreign coroutine is still counted as a child one, i.e. calling this method increases the size of the
* group.
*
* @return A callback to call on foreign coroutine completes or std::nullopt if the group is already full.
*/
std::optional<std::function<void()>>
registerForeign();
/**
* @brief Wait for all the coroutines in the group to finish
*
@@ -91,6 +95,18 @@ public:
*/
size_t
size() const;
/**
* @brief Check if the group is full
*
* @return true If the group is full false otherwise
*/
bool
isFull() const;
private:
void
onCoroutineCompleted();
};
} // namespace util