Add clang-tidy, clang-format and fixes
This commit is contained in:
parent
c6a1198ed2
commit
7c00dc1860
22 changed files with 459 additions and 499 deletions
13
.clang-format
Normal file
13
.clang-format
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
BasedOnStyle: Google
|
||||||
|
IndentWidth: 2
|
||||||
|
ColumnLimit: 140
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
BreakConstructorInitializers: AfterColon
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
SpaceBeforeParens: Never
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortLambdasOnASingleLine: Empty
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
AlwaysBreakTemplateDeclarations: true
|
1
.clang-tidy
Normal file
1
.clang-tidy
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Checks: '-*,google-*,cppcoreguidelines-*,-cppcoreguidelines-c-copy-assignment-signature,-cppcoreguidelines-special-member-functions,-cppcoreguidelines-avoid-const-or-ref-data-members,modernize-*'
|
|
@ -1,12 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
#include <cserver/clients/http/request.hpp>
|
#include <cserver/clients/http/request.hpp>
|
||||||
#include <cserver/clients/http/response.hpp>
|
#include <cserver/clients/http/response.hpp>
|
||||||
#include <cserver/engine/components.hpp>
|
#include <cserver/engine/components.hpp>
|
||||||
#include <cserver/engine/coroutine.hpp>
|
#include <cserver/engine/coroutine.hpp>
|
||||||
#include <cserver/utils/boost_error_wrapper.hpp>
|
|
||||||
#include <cserver/engine/use_streaming.hpp>
|
#include <cserver/engine/use_streaming.hpp>
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include <boost/asio/ssl.hpp>
|
|
||||||
#include <utempl/constexpr_string.hpp>
|
#include <utempl/constexpr_string.hpp>
|
||||||
|
|
||||||
namespace cserver::server::http {
|
namespace cserver::server::http {
|
||||||
|
@ -16,9 +15,8 @@ inline constexpr auto ParseHttpHeader(std::string header) -> std::pair<std::stri
|
||||||
std::string key = header.substr(0, pos);
|
std::string key = header.substr(0, pos);
|
||||||
std::string value = header.substr(pos + 2, header.size() - 1);
|
std::string value = header.substr(pos + 2, header.size() - 1);
|
||||||
return std::make_pair(key, value);
|
return std::make_pair(key, value);
|
||||||
|
|
||||||
};
|
};
|
||||||
} // namespace cserver::server::http
|
} // namespace cserver::server::http
|
||||||
namespace cserver::components {
|
namespace cserver::components {
|
||||||
template <typename TaskProcessor = int>
|
template <typename TaskProcessor = int>
|
||||||
struct HttpClient {
|
struct HttpClient {
|
||||||
|
@ -30,20 +28,20 @@ struct HttpClient {
|
||||||
return clients::http::Request{*this};
|
return clients::http::Request{*this};
|
||||||
};
|
};
|
||||||
inline constexpr HttpClient(auto, auto& context) :
|
inline constexpr HttpClient(auto, auto& context) :
|
||||||
taskProcessor(context.template FindComponent<"basicTaskProcessor">()),
|
taskProcessor(context.template FindComponent<"basicTaskProcessor">()),
|
||||||
ctx(boost::asio::ssl::context::method::sslv23_client),
|
ctx(boost::asio::ssl::context::method::sslv23_client),
|
||||||
resolver(this->taskProcessor.ioContext) {}
|
resolver(this->taskProcessor.ioContext) {};
|
||||||
|
|
||||||
template <utempl::ConstexprString name, Options Options, typename T>
|
template <utempl::ConstexprString name, Options Options, typename T>
|
||||||
static consteval auto Adder(const T& context) {
|
static consteval auto Adder(const T& context) {
|
||||||
using Type = std::remove_cvref_t<decltype(context.template FindComponent<"basicTaskProcessor">())>;
|
using Type = std::remove_cvref_t<decltype(context.template FindComponent<"basicTaskProcessor">())>;
|
||||||
return context.TransformComponents(
|
return context.TransformComponents(
|
||||||
[&](const ComponentConfig<name, HttpClient<>, Options>&) -> ComponentConfig<name, HttpClient<Type>, Options> {
|
[&](const ComponentConfig<name, HttpClient<>, Options>&) -> ComponentConfig<name, HttpClient<Type>, Options> {
|
||||||
return {};
|
return {};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename Socket, typename... Flags>
|
template <typename Socket, typename... Flags>
|
||||||
static consteval auto GetPerformReturnType(Flags...) {
|
static consteval auto GetPerformReturnType(Flags...) {
|
||||||
constexpr auto kUseStreaming = utempl::Find<UseStreaming>(utempl::kTypeList<Flags...>) != sizeof...(Flags);
|
constexpr auto kUseStreaming = utempl::Find<UseStreaming>(utempl::kTypeList<Flags...>) != sizeof...(Flags);
|
||||||
|
@ -54,7 +52,7 @@ private:
|
||||||
} else {
|
} else {
|
||||||
return [] -> server::http::HttpResponse {
|
return [] -> server::http::HttpResponse {
|
||||||
std::unreachable();
|
std::unreachable();
|
||||||
}();
|
}();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
template <typename Socket>
|
template <typename Socket>
|
||||||
|
@ -76,14 +74,18 @@ private:
|
||||||
inline auto ReadBody(Socket&& socket, std::size_t length, auto&&...) const -> cserver::Task<std::string> {
|
inline auto ReadBody(Socket&& socket, std::size_t length, auto&&...) const -> cserver::Task<std::string> {
|
||||||
std::string response;
|
std::string response;
|
||||||
response.reserve(length);
|
response.reserve(length);
|
||||||
co_await boost::asio::async_read(socket, boost::asio::dynamic_buffer(response), boost::asio::transfer_at_least(length), boost::asio::use_awaitable);
|
co_await boost::asio::async_read(
|
||||||
|
socket, boost::asio::dynamic_buffer(response), boost::asio::transfer_at_least(length), boost::asio::use_awaitable);
|
||||||
co_return response;
|
co_return response;
|
||||||
};
|
};
|
||||||
template <typename Socket>
|
template <typename Socket>
|
||||||
inline auto ReadBody(Socket&& socket, auto&&...) const -> cserver::Task<std::string> {
|
inline auto ReadBody(Socket&& socket, auto&&...) const -> cserver::Task<std::string> {
|
||||||
std::string response;
|
std::string response;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
auto [ec, n] = co_await boost::asio::async_read(socket, boost::asio::dynamic_buffer(response), boost::asio::transfer_at_least(1), boost::asio::as_tuple(boost::asio::use_awaitable));
|
auto [ec, n] = co_await boost::asio::async_read(socket,
|
||||||
|
boost::asio::dynamic_buffer(response),
|
||||||
|
boost::asio::transfer_at_least(1),
|
||||||
|
boost::asio::as_tuple(boost::asio::use_awaitable));
|
||||||
if(ec && ec == boost::asio::error::eof) {
|
if(ec && ec == boost::asio::error::eof) {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
@ -93,19 +95,23 @@ private:
|
||||||
};
|
};
|
||||||
co_return response;
|
co_return response;
|
||||||
};
|
};
|
||||||
public:
|
|
||||||
|
public:
|
||||||
template <typename... Flags, typename T>
|
template <typename... Flags, typename T>
|
||||||
inline auto PerformRequest(T&& request, Flags... flags) -> cserver::Task<decltype(this->GetPerformReturnType<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>(flags...))> {
|
inline auto PerformRequest(T&& request, Flags... flags)
|
||||||
|
-> cserver::Task<decltype(this->GetPerformReturnType<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>(flags...))> {
|
||||||
constexpr bool kUseStreaming = utempl::Find<UseStreaming>(utempl::kTypeList<Flags...>) != sizeof...(Flags);
|
constexpr bool kUseStreaming = utempl::Find<UseStreaming>(utempl::kTypeList<Flags...>) != sizeof...(Flags);
|
||||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket(this->taskProcessor.ioContext, this->ctx);
|
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket(this->taskProcessor.ioContext, this->ctx);
|
||||||
boost::asio::ip::tcp::resolver::iterator endpoint =
|
boost::asio::ip::tcp::resolver::iterator endpoint = co_await this->resolver.async_resolve(
|
||||||
co_await this->resolver.async_resolve({request.request.url.host(), request.request.url.has_port() ? request.request.url.port() : request.request.url.scheme()}, boost::asio::use_awaitable);
|
{request.request.url.host(), request.request.url.has_port() ? request.request.url.port() : request.request.url.scheme()},
|
||||||
|
boost::asio::use_awaitable);
|
||||||
co_await boost::asio::async_connect(socket.lowest_layer(), endpoint, boost::asio::use_awaitable);
|
co_await boost::asio::async_connect(socket.lowest_layer(), endpoint, boost::asio::use_awaitable);
|
||||||
|
|
||||||
co_await socket.async_handshake(boost::asio::ssl::stream_base::client, boost::asio::use_awaitable);
|
co_await socket.async_handshake(boost::asio::ssl::stream_base::client, boost::asio::use_awaitable);
|
||||||
|
|
||||||
std::string req(request.request.ToString());
|
std::string req(request.request.ToString());
|
||||||
co_await boost::asio::async_write(socket, boost::asio::buffer(req.data(), req.size()), boost::asio::transfer_all(), boost::asio::use_awaitable);
|
co_await boost::asio::async_write(
|
||||||
|
socket, boost::asio::buffer(req.data(), req.size()), boost::asio::transfer_all(), boost::asio::use_awaitable);
|
||||||
auto response = co_await this->ReadHeaders(socket, flags...);
|
auto response = co_await this->ReadHeaders(socket, flags...);
|
||||||
if constexpr(kUseStreaming) {
|
if constexpr(kUseStreaming) {
|
||||||
co_return clients::http::Response<HttpClient<TaskProcessor>, decltype(socket)>{*this, std::move(socket), std::move(response)};
|
co_return clients::http::Response<HttpClient<TaskProcessor>, decltype(socket)>{*this, std::move(socket), std::move(response)};
|
||||||
|
@ -120,4 +126,4 @@ public:
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cserver::clients::http
|
} // namespace cserver::components
|
||||||
|
|
|
@ -1,69 +1,67 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <cserver/engine/coroutine.hpp>
|
||||||
#include <cserver/server/http/http_request.hpp>
|
#include <cserver/server/http/http_request.hpp>
|
||||||
#include <cserver/server/http/http_response.hpp>
|
#include <cserver/server/http/http_response.hpp>
|
||||||
#include <cserver/engine/coroutine.hpp>
|
|
||||||
|
|
||||||
namespace cserver::clients::http {
|
namespace cserver::clients::http {
|
||||||
template <typename HttpClient>
|
template <typename HttpClient>
|
||||||
struct Request {
|
struct Request {
|
||||||
HttpClient& client;
|
HttpClient& client;
|
||||||
server::http::HttpRequest request;
|
server::http::HttpRequest request;
|
||||||
Request(HttpClient& client) :
|
explicit Request(HttpClient& client) : client(client) {
|
||||||
client(client) {
|
|
||||||
this->AddHeader("User-Agent", "cserver/1");
|
this->AddHeader("User-Agent", "cserver/1");
|
||||||
};
|
};
|
||||||
inline constexpr auto Post(this auto&& self) -> decltype(auto) {
|
constexpr auto Post(this auto&& self) -> decltype(auto) {
|
||||||
self.request.method = "POST";
|
self.request.method = "POST";
|
||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
inline constexpr auto Get(this auto&& self) -> decltype(auto) {
|
constexpr auto Get(this auto&& self) -> decltype(auto) {
|
||||||
self.request.method = "GET";
|
self.request.method = "GET";
|
||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
inline constexpr auto Put(this auto&& self) -> decltype(auto) {
|
constexpr auto Put(this auto&& self) -> decltype(auto) {
|
||||||
self.request.method = "PUT";
|
self.request.method = "PUT";
|
||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
inline constexpr auto SetCustomMethod(this auto&& self, std::string method) -> decltype(auto) {
|
constexpr auto SetCustomMethod(this auto&& self, std::string method) -> decltype(auto) {
|
||||||
self.request.method = std::move(method);
|
self.request.method = std::move(method);
|
||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
inline constexpr auto AddHeader(this auto&& self, std::string first, std::string second) -> decltype(auto) {
|
constexpr auto AddHeader(this auto&& self, std::string first, std::string second) -> decltype(auto) {
|
||||||
self.request.headers.emplace(std::move(first), std::move(second));
|
self.request.headers.emplace(std::move(first), std::move(second));
|
||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
template <typename Self>
|
template <typename Self>
|
||||||
inline constexpr auto AddHeaderIfNotExists(this Self&& self,
|
constexpr auto AddHeaderIfNotExists(this Self&& self, std::string check, std::string first, std::string second) -> decltype(auto) {
|
||||||
std::string check,
|
|
||||||
std::string first,
|
|
||||||
std::string second) -> decltype(auto) {
|
|
||||||
if(!self.request.headers.contains(std::move(check))) {
|
if(!self.request.headers.contains(std::move(check))) {
|
||||||
return std::forward<Self>(self).AddHeader(std::move(first), std::move(second));
|
return std::forward<Self>(self).AddHeader(std::move(first), std::move(second));
|
||||||
};
|
};
|
||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
template <typename Self>
|
template <typename Self>
|
||||||
inline constexpr auto Url(this Self&& self,
|
constexpr auto Url(this Self&& self, std::string url) -> auto&& {
|
||||||
std::string url) -> auto&& {
|
|
||||||
self.request.url = boost::urls::url{std::move(url)};
|
self.request.url = boost::urls::url{std::move(url)};
|
||||||
auto authority = self.request.url.authority();
|
auto authority = self.request.url.authority();
|
||||||
return std::forward<Self>(self).AddHeader("Host", std::string{authority.data(), authority.size()});
|
return std::forward<Self>(self).AddHeader("Host", std::string{authority.data(), authority.size()});
|
||||||
};
|
};
|
||||||
inline constexpr auto Data(this auto&& self, std::string data) -> decltype(auto) {
|
constexpr auto Data(this auto&& self, std::string data) -> decltype(auto) {
|
||||||
self.request.body = std::move(data);
|
self.request.body = std::move(data);
|
||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
inline constexpr auto ToString() const -> std::string {
|
[[nodiscard]] constexpr auto ToString() const -> std::string {
|
||||||
return this->request.ToString();
|
return this->request.ToString();
|
||||||
};
|
};
|
||||||
template <typename Self, typename... Flags>
|
template <typename Self, typename... Flags>
|
||||||
inline auto Perform(this Self&& self, Flags&&... flags)
|
inline auto Perform(this Self&& self, Flags&&... flags)
|
||||||
-> decltype(self.client.PerformRequest(std::forward<Self>(self).AddHeaderIfNotExists("Transfer-Encoding", "Content-Length", std::to_string(self.request.body.size())), std::forward<Flags>(flags)...)) {
|
-> decltype(self.client.PerformRequest(
|
||||||
|
std::forward<Self>(self).AddHeaderIfNotExists("Transfer-Encoding", "Content-Length", std::to_string(self.request.body.size())),
|
||||||
|
std::forward<Flags>(flags)...)) {
|
||||||
HttpClient& client = self.client;
|
HttpClient& client = self.client;
|
||||||
std::string size = std::to_string(self.request.body.size());
|
std::string size = std::to_string(self.request.body.size());
|
||||||
co_return co_await client.PerformRequest(std::forward<Self>(self).AddHeaderIfNotExists("Transfer-Encoding", "Content-Length", std::move(size)), std::forward<Flags>(flags)...);
|
co_return co_await client.PerformRequest(
|
||||||
|
std::forward<Self>(self).AddHeaderIfNotExists("Transfer-Encoding", "Content-Length", std::move(size)),
|
||||||
|
std::forward<Flags>(flags)...);
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
} // namespace cserver::clients::http
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cserver/server/http/http_response.hpp>
|
|
||||||
#include <cserver/engine/coroutine.hpp>
|
|
||||||
#include <boost/asio/ssl.hpp>
|
#include <boost/asio/ssl.hpp>
|
||||||
|
#include <cserver/engine/coroutine.hpp>
|
||||||
|
#include <cserver/server/http/http_response.hpp>
|
||||||
|
|
||||||
namespace cserver::clients::http {
|
namespace cserver::clients::http {
|
||||||
|
|
||||||
|
@ -10,10 +10,12 @@ class Response : public server::http::HttpResponse {
|
||||||
HttpClient& client;
|
HttpClient& client;
|
||||||
Socket socket;
|
Socket socket;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline auto ReadChunk() -> cserver::Task<bool> {
|
inline auto ReadChunk() -> cserver::Task<bool> {
|
||||||
this->body.resize(4479);
|
this->body.resize(4479); // NOLINT
|
||||||
auto [ec, n] = co_await this->socket.async_read_some(boost::asio::buffer(this->body.data(), 4479), boost::asio::as_tuple(boost::asio::use_awaitable));
|
|
||||||
|
auto [ec, n] = co_await this->socket.async_read_some(boost::asio::buffer(this->body.data(), 4479), // NOLINT
|
||||||
|
boost::asio::as_tuple(boost::asio::use_awaitable));
|
||||||
if(ec == boost::asio::error::eof || ec == boost::asio::error::operation_aborted || ec == boost::asio::ssl::error::stream_truncated) {
|
if(ec == boost::asio::error::eof || ec == boost::asio::error::operation_aborted || ec == boost::asio::ssl::error::stream_truncated) {
|
||||||
co_return false;
|
co_return false;
|
||||||
};
|
};
|
||||||
|
@ -23,12 +25,10 @@ public:
|
||||||
this->body.resize(n);
|
this->body.resize(n);
|
||||||
co_return true;
|
co_return true;
|
||||||
};
|
};
|
||||||
inline constexpr Response(Response&&) = default;
|
constexpr Response(Response&&) = default;
|
||||||
inline constexpr Response(const Response&) = default;
|
constexpr Response(const Response&) = default;
|
||||||
inline constexpr Response(HttpClient& client, Socket socket, server::http::HttpResponse response) :
|
inline Response(HttpClient& client, Socket socket, server::http::HttpResponse response) :
|
||||||
client(client),
|
client(client), socket(std::move(socket)), HttpResponse(std::move(response)) {};
|
||||||
socket(std::move(socket)),
|
|
||||||
HttpResponse(std::move(response)) {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cserver::clients::http
|
} // namespace cserver::clients::http
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <utempl/optional.hpp>
|
|
||||||
#include <cserver/engine/not_implemented.hpp>
|
|
||||||
#include <cserver/engine/components.hpp>
|
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
#include <nameof.hpp>
|
#include <cserver/engine/components.hpp>
|
||||||
|
#include <cserver/engine/not_implemented.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <nameof.hpp>
|
||||||
|
#include <utempl/optional.hpp>
|
||||||
|
|
||||||
namespace cserver::cli {
|
namespace cserver::cli {
|
||||||
|
|
||||||
|
@ -22,25 +22,19 @@ struct StructConfig {
|
||||||
static constexpr auto kValue = utempl::Tuple{Configs...};
|
static constexpr auto kValue = utempl::Tuple{Configs...};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T, std::size_t N, std::size_t NN>
|
template <typename T, std::size_t N, std::size_t NN>
|
||||||
consteval auto CreateOptionConfig(utempl::ConstexprString<N> name,
|
consteval auto CreateOptionConfig(utempl::ConstexprString<N> name, utempl::ConstexprString<NN> description) -> OptionConfig<N, NN, T> {
|
||||||
utempl::ConstexprString<NN> description) -> OptionConfig<N, NN, T> {
|
|
||||||
return {name, description};
|
return {name, description};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <StructConfig... Configs>
|
template <StructConfig... Configs>
|
||||||
struct Manager {
|
struct Manager {
|
||||||
boost::program_options::variables_map variableMap;
|
boost::program_options::variables_map variableMap;
|
||||||
static constexpr utempl::ConstexprString kName = "cliManager";
|
static constexpr utempl::ConstexprString kName = "cliManager";
|
||||||
constexpr Manager(auto& context) {
|
explicit constexpr Manager(auto& context) {
|
||||||
boost::program_options::options_description general("General options");
|
boost::program_options::options_description general("General options");
|
||||||
general.add_options()
|
general.add_options()("help,h", "Show help");
|
||||||
("help,h", "Show help");
|
// clang-format off
|
||||||
([&]{
|
([&]{
|
||||||
using Current = decltype(Configs)::Type;
|
using Current = decltype(Configs)::Type;
|
||||||
boost::program_options::options_description desc(fmt::format("{} options",
|
boost::program_options::options_description desc(fmt::format("{} options",
|
||||||
|
@ -48,7 +42,6 @@ struct Manager {
|
||||||
utempl::Unpack(utempl::PackConstexprWrapper<decltype(Configs)::kValue>(), [&](auto... vs) {
|
utempl::Unpack(utempl::PackConstexprWrapper<decltype(Configs)::kValue>(), [&](auto... vs) {
|
||||||
auto&& add = desc.add_options();
|
auto&& add = desc.add_options();
|
||||||
([&]{
|
([&]{
|
||||||
//static_assert((std::ignore = utempl::kWrapper<*vs>, false));
|
|
||||||
if constexpr((*vs).description.size() == 0) {
|
if constexpr((*vs).description.size() == 0) {
|
||||||
add((*vs).name.data.begin(),
|
add((*vs).name.data.begin(),
|
||||||
boost::program_options::value<typename decltype(*vs)::Type>());
|
boost::program_options::value<typename decltype(*vs)::Type>());
|
||||||
|
@ -61,6 +54,7 @@ struct Manager {
|
||||||
});
|
});
|
||||||
general.add(desc);
|
general.add(desc);
|
||||||
}(), ...);
|
}(), ...);
|
||||||
|
// clang-format-on
|
||||||
boost::program_options::store(boost::program_options::parse_command_line(context.argc, context.argv, general), this->variableMap);
|
boost::program_options::store(boost::program_options::parse_command_line(context.argc, context.argv, general), this->variableMap);
|
||||||
boost::program_options::notify(this->variableMap);
|
boost::program_options::notify(this->variableMap);
|
||||||
if(this->variableMap.count("help")) {
|
if(this->variableMap.count("help")) {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cserver/engine/not_implemented.hpp>
|
|
||||||
#include <cserver/engine/components.hpp>
|
|
||||||
#include <cserver/components/cli/manager.hpp>
|
|
||||||
#include <utempl/attributes.hpp>
|
|
||||||
#include <boost/pfr.hpp>
|
#include <boost/pfr.hpp>
|
||||||
|
#include <cserver/components/cli/manager.hpp>
|
||||||
|
#include <cserver/engine/components.hpp>
|
||||||
|
#include <cserver/engine/not_implemented.hpp>
|
||||||
|
#include <utempl/attributes.hpp>
|
||||||
|
|
||||||
namespace cserver::cli {
|
namespace cserver::cli {
|
||||||
|
|
||||||
|
@ -17,32 +17,28 @@ struct Description {
|
||||||
static constexpr utempl::ConstexprString kValue = Value;
|
static constexpr utempl::ConstexprString kValue = Value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct IsNameM {
|
struct IsNameM {
|
||||||
static constexpr bool value = utempl::Overloaded(
|
static constexpr bool value = utempl::Overloaded(
|
||||||
[]<utempl::ConstexprString V>(utempl::TypeList<Name<V>>) {
|
[]<utempl::ConstexprString V>(utempl::TypeList<Name<V>>) {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
[](auto) {return false;}
|
[](auto) {
|
||||||
)(utempl::kType<T>);
|
return false;
|
||||||
|
})(utempl::kType<T>);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct IsDescriptionM {
|
struct IsDescriptionM {
|
||||||
static constexpr bool value = utempl::Overloaded(
|
static constexpr bool value = utempl::Overloaded(
|
||||||
[]<utempl::ConstexprString V>(utempl::TypeList<Description<V>>) {
|
[]<utempl::ConstexprString V>(utempl::TypeList<Description<V>>) {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
[](auto) {return false;}
|
[](auto) {
|
||||||
)(utempl::kType<T>);
|
return false;
|
||||||
|
})(utempl::kType<T>);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <typename Self, typename T>
|
template <typename Self, typename T>
|
||||||
struct Struct : T {
|
struct Struct : T {
|
||||||
static constexpr utempl::ConstexprString kCliManagerName = "cliManager";
|
static constexpr utempl::ConstexprString kCliManagerName = "cliManager";
|
||||||
|
@ -61,23 +57,18 @@ struct Struct : T {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static consteval auto GetConfig() {
|
static consteval auto GetConfig() {
|
||||||
static constexpr auto names = boost::pfr::names_as_array<T>();
|
static constexpr auto names = boost::pfr::names_as_array<T>();
|
||||||
return [&](auto... is) {
|
return [&](auto... is) {
|
||||||
return StructConfig<Self, [&] {
|
return StructConfig<Self, [&] {
|
||||||
return CreateOptionConfig<std::remove_reference_t<decltype(boost::pfr::get<is>(std::declval<T&>()))>>(
|
return CreateOptionConfig<std::remove_reference_t<decltype(boost::pfr::get<is>(std::declval<T&>()))>>(
|
||||||
GetFirstOrDefault<is, IsNameM>(utempl::ConstexprString<names[is].size() + 1>(names[is].data())),
|
GetFirstOrDefault<is, IsNameM>(utempl::ConstexprString<names[is].size() + 1>(names[is].data())),
|
||||||
GetFirstOrDefault<is, IsDescriptionM>(utempl::ConstexprString<0>{}));
|
GetFirstOrDefault<is, IsDescriptionM>(utempl::ConstexprString<0>{}));
|
||||||
}()...>{};
|
}()...>{};
|
||||||
} | utempl::kSeq<boost::pfr::tuple_size_v<T>>;
|
} | utempl::kSeq<boost::pfr::tuple_size_v<T>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
explicit constexpr Struct(auto& context) : T(context.template FindComponent<Self::kCliManagerName>().template Get<GetConfig()>()) {};
|
||||||
constexpr Struct(auto& context) :
|
|
||||||
T(context.template FindComponent<Self::kCliManagerName>().template Get<GetConfig()>()) {};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <utempl::ConstexprString Name, Options>
|
template <utempl::ConstexprString Name, Options>
|
||||||
static consteval auto CliStructAdder(const auto& context) {
|
static consteval auto CliStructAdder(const auto& context) {
|
||||||
|
@ -96,4 +87,4 @@ struct StructWithAdder : Struct<Self, T> {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cserver::cli
|
} // namespace cserver::cli
|
||||||
|
|
|
@ -7,18 +7,23 @@ namespace cserver {
|
||||||
struct ComponentBase {
|
struct ComponentBase {
|
||||||
Logging& logging;
|
Logging& logging;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr ComponentBase(T& context) :
|
explicit constexpr ComponentBase(T& context) : logging(context.template FindComponent<"logging">()){};
|
||||||
logging(context.template FindComponent<"logging">()) {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define LOG_TRACE \
|
||||||
|
if(this->logging.level == ::cserver::LoggingLevel::kTrace) \
|
||||||
|
this->logging.Trace
|
||||||
|
#define LOG_DEBUG \
|
||||||
|
if(this->logging.level <= ::cserver::LoggingLevel::kDebug) \
|
||||||
|
this->logging.Debug
|
||||||
|
#define LOG_INFO \
|
||||||
|
if(this->logging.level <= ::cserver::LoggingLevel::kInfo) \
|
||||||
|
this->logging.Info
|
||||||
|
#define LOG_WARNING \
|
||||||
|
if(this->logging.level <= ::cserver::LoggingLevel::kWarning) \
|
||||||
|
this->logging.Warning
|
||||||
|
#define LOG_ERROR \
|
||||||
|
if(this->logging.level <= ::cserver::LoggingLevel::kError) \
|
||||||
|
this->logging.Error
|
||||||
|
|
||||||
#define LOG_TRACE if(this->logging.level == ::cserver::LoggingLevel::kTrace) this->logging.Trace
|
} // namespace cserver
|
||||||
#define LOG_DEBUG if(this->logging.level <= ::cserver::LoggingLevel::kDebug) this->logging.Debug
|
|
||||||
#define LOG_INFO if(this->logging.level <= ::cserver::LoggingLevel::kInfo) this->logging.Info
|
|
||||||
#define LOG_WARNING if(this->logging.level <= ::cserver::LoggingLevel::kWarning) this->logging.Warning
|
|
||||||
#define LOG_ERROR if(this->logging.level <= ::cserver::LoggingLevel::kError) this->logging.Error
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace cserver
|
|
||||||
|
|
|
@ -1,26 +1,20 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <utempl/constexpr_string.hpp>
|
|
||||||
#include <array>
|
|
||||||
#include <fmt/compile.h>
|
#include <fmt/compile.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <utempl/constexpr_string.hpp>
|
||||||
|
|
||||||
namespace cserver {
|
namespace cserver {
|
||||||
|
|
||||||
|
enum class LoggingLevel { kTrace, kDebug, kInfo, kWarning, kError };
|
||||||
enum class LoggingLevel {
|
|
||||||
kTrace,
|
|
||||||
kDebug,
|
|
||||||
kInfo,
|
|
||||||
kWarning,
|
|
||||||
kError
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Logging {
|
struct Logging {
|
||||||
static constexpr utempl::ConstexprString kName = "logging";
|
static constexpr utempl::ConstexprString kName = "logging";
|
||||||
LoggingLevel level;
|
LoggingLevel level;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr Logging(T&) : level(T::kConfig.template Get<T::kName>().template Get<"level">()) {
|
explicit constexpr Logging(T&) : level(T::kConfig.template Get<T::kName>().template Get<"level">()) {
|
||||||
std::ios::sync_with_stdio(false);
|
std::ios::sync_with_stdio(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,13 +22,12 @@ struct Logging {
|
||||||
this->level = level;
|
this->level = level;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <std::size_t N, std::size_t NN>
|
template <std::size_t N, std::size_t NN>
|
||||||
static consteval auto GetFormatStringFor(utempl::ConstexprString<N> fmt, utempl::ConstexprString<NN> level) {
|
static consteval auto GetFormatStringFor(utempl::ConstexprString<N> fmt, utempl::ConstexprString<NN> level) {
|
||||||
constexpr auto f = FMT_COMPILE("[{}]: {}\n");
|
constexpr auto f = FMT_COMPILE("[{}]: {}\n");
|
||||||
constexpr auto size = N + NN + 6;
|
constexpr auto size = N + NN + 6;
|
||||||
char data[size]{};
|
std::array<char, size> data{};
|
||||||
fmt::format_to(data, f, static_cast<std::string_view>(level), static_cast<std::string_view>(fmt));
|
fmt::format_to(data.begin(), f, static_cast<std::string_view>(level), static_cast<std::string_view>(fmt));
|
||||||
return utempl::ConstexprString<size>(data);
|
return utempl::ConstexprString<size>(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,7 +35,6 @@ struct Logging {
|
||||||
std::cout << data;
|
std::cout << data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <utempl::ConstexprString Fmt, typename... Ts>
|
template <utempl::ConstexprString Fmt, typename... Ts>
|
||||||
constexpr auto Debug(Ts&&... args) {
|
constexpr auto Debug(Ts&&... args) {
|
||||||
static constexpr auto fmt = GetFormatStringFor(Fmt, utempl::ConstexprString{"DEBUG"});
|
static constexpr auto fmt = GetFormatStringFor(Fmt, utempl::ConstexprString{"DEBUG"});
|
||||||
|
@ -74,5 +66,4 @@ struct Logging {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace cserver
|
||||||
} // namespace cserver
|
|
||||||
|
|
|
@ -3,11 +3,9 @@
|
||||||
|
|
||||||
namespace cserver {
|
namespace cserver {
|
||||||
|
|
||||||
|
|
||||||
struct StopBlocker {
|
struct StopBlocker {
|
||||||
boost::asio::io_context::work guard;
|
boost::asio::io_context::work guard;
|
||||||
inline constexpr StopBlocker(auto& context) :
|
explicit constexpr StopBlocker(auto& context) : guard(context.template FindComponent<kBasicTaskProcessorName>().ioContext) {};
|
||||||
guard(context.template FindComponent<kBasicTaskProcessorName>().ioContext) {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cserver
|
} // namespace cserver
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <utempl/constexpr_string.hpp>
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <utempl/constexpr_string.hpp>
|
||||||
|
|
||||||
namespace cserver::engine::basic {
|
namespace cserver::engine::basic {
|
||||||
|
|
||||||
template <std::size_t Size = 0>
|
template <std::size_t Size = 0>
|
||||||
struct TaskProcessor {
|
struct TaskProcessor {
|
||||||
boost::asio::io_context ioContext;
|
boost::asio::io_context ioContext;
|
||||||
std::array<std::optional<std::thread>, Size> pool;
|
std::array<std::optional<std::thread>, Size> pool{};
|
||||||
static constexpr utempl::ConstexprString kName = "basicTaskProcessor";
|
static constexpr utempl::ConstexprString kName = "basicTaskProcessor";
|
||||||
inline constexpr TaskProcessor(auto, auto&) :
|
inline constexpr TaskProcessor(auto, auto&) : ioContext{} {};
|
||||||
ioContext{},
|
|
||||||
pool{} {
|
|
||||||
};
|
|
||||||
|
|
||||||
inline ~TaskProcessor() {
|
inline ~TaskProcessor() {
|
||||||
for(auto& thread : this->pool) {
|
for(auto& thread : this->pool) {
|
||||||
|
@ -28,7 +25,7 @@ struct TaskProcessor {
|
||||||
if(this->ioContext.stopped()) {
|
if(this->ioContext.stopped()) {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
thread = std::thread([&]{
|
thread = std::thread([&] {
|
||||||
if(this->ioContext.stopped()) {
|
if(this->ioContext.stopped()) {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -38,4 +35,4 @@ struct TaskProcessor {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace cserver::engine::basic
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <cxxabi.h>
|
||||||
|
|
||||||
|
#include <boost/core/demangle.hpp>
|
||||||
#include <cserver/engine/basic/task_processor.hpp>
|
#include <cserver/engine/basic/task_processor.hpp>
|
||||||
#include <cserver/engine/coroutine.hpp>
|
#include <cserver/engine/coroutine.hpp>
|
||||||
#include <utempl/utils.hpp>
|
|
||||||
#include <utempl/loopholes/counter.hpp>
|
#include <utempl/loopholes/counter.hpp>
|
||||||
#include <cxxabi.h>
|
#include <utempl/utils.hpp>
|
||||||
#include <boost/core/demangle.hpp>
|
|
||||||
|
|
||||||
namespace cserver {
|
namespace cserver {
|
||||||
|
|
||||||
|
@ -29,34 +30,32 @@ struct NamedValue {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using GetTypeFromComponentConfig = decltype(
|
using GetTypeFromComponentConfig = decltype([]<utempl::ConstexprString name, typename TT, Options Options>(
|
||||||
[]<utempl::ConstexprString name, typename TT, Options Options>(const ComponentConfig<name, TT, Options>&) -> TT {
|
const ComponentConfig<name, TT, Options>&) -> TT {}(std::declval<T>()));
|
||||||
}(std::declval<T>()));
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline constexpr utempl::ConstexprString kNameFromComponentConfig =
|
inline constexpr utempl::ConstexprString kNameFromComponentConfig =
|
||||||
decltype([]<utempl::ConstexprString name, typename TT, Options Options>(const ComponentConfig<name, TT, Options>&) {
|
decltype([]<utempl::ConstexprString name, typename TT, Options Options>(const ComponentConfig<name, TT, Options>&) {
|
||||||
return utempl::Wrapper<name>{};
|
return utempl::Wrapper<name>{};
|
||||||
}(std::declval<T>()))::kValue;
|
}(std::declval<T>()))::kValue;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline constexpr auto TransformIfOk(T&& value, auto&& f) {
|
inline constexpr auto TransformIfOk(T&& value, auto&& f) {
|
||||||
if constexpr(requires{f(std::forward<T>(value));}) {
|
if constexpr(requires { f(std::forward<T>(value)); }) {
|
||||||
return f(std::forward<T>(value));
|
return f(std::forward<T>(value));
|
||||||
} else {
|
} else {
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
} // namespace impl
|
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct ConstexprConfig {
|
struct ConstexprConfig {
|
||||||
utempl::Tuple<Ts...> data;
|
utempl::Tuple<Ts...> data;
|
||||||
template <utempl::ConstexprString Key>
|
template <utempl::ConstexprString Key>
|
||||||
inline constexpr auto Get() const -> auto {
|
inline constexpr auto Get() const -> auto {
|
||||||
return [&]<typename... TTs, utempl::ConstexprString... names>(const ConstexprConfig<impl::NamedValue<names, TTs>...>&){
|
return [&]<typename... TTs, utempl::ConstexprString... names>(const ConstexprConfig<impl::NamedValue<names, TTs>...>&) {
|
||||||
constexpr auto list = utempl::TypeList<utempl::Wrapper<names>...>{};
|
constexpr auto list = utempl::TypeList<utempl::Wrapper<names>...>{};
|
||||||
constexpr std::size_t I = Find<utempl::Wrapper<Key>>(list);
|
constexpr std::size_t I = Find<utempl::Wrapper<Key>>(list);
|
||||||
if constexpr(I < sizeof...(Ts)) {
|
if constexpr(I < sizeof...(Ts)) {
|
||||||
|
@ -81,30 +80,30 @@ inline constexpr auto GetInitFlagFor(auto&... args) -> InitFlag& {
|
||||||
template <typename InitFlag, utempl::Tuple Tuple>
|
template <typename InitFlag, utempl::Tuple Tuple>
|
||||||
constexpr auto TransformDependencyGraphToTupleWithDependenciesToInitedFlagChanges(auto&&... args) {
|
constexpr auto TransformDependencyGraphToTupleWithDependenciesToInitedFlagChanges(auto&&... args) {
|
||||||
return utempl::Map(utempl::PackConstexprWrapper<Tuple>(), [&]<auto Array>(utempl::Wrapper<Array>) {
|
return utempl::Map(utempl::PackConstexprWrapper<Tuple>(), [&]<auto Array>(utempl::Wrapper<Array>) {
|
||||||
return utempl::Map(utempl::PackConstexprWrapper<Array, utempl::Tuple<>>(), [&](auto elem) {
|
return utempl::Map(
|
||||||
return &GetInitFlagFor<InitFlag, static_cast<std::size_t>(elem)>(args...);
|
utempl::PackConstexprWrapper<Array, utempl::Tuple<>>(),
|
||||||
}, utempl::kType<std::array<InitFlag*, Array.size()>>);
|
[&](auto elem) {
|
||||||
|
return &GetInitFlagFor<InitFlag, static_cast<std::size_t>(elem)>(args...);
|
||||||
|
},
|
||||||
|
utempl::kType<std::array<InitFlag*, Array.size()>>);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AsyncConditionVariable {
|
struct AsyncConditionVariable {
|
||||||
inline AsyncConditionVariable(boost::asio::io_context& ioContext) :
|
explicit inline AsyncConditionVariable(boost::asio::io_context& ioContext) : mtx{}, deadlineTimer(ioContext) {};
|
||||||
mtx{},
|
|
||||||
deadlineTimer(ioContext),
|
|
||||||
flag{} {};
|
|
||||||
template <typename Token = boost::asio::use_awaitable_t<>>
|
template <typename Token = boost::asio::use_awaitable_t<>>
|
||||||
inline auto AsyncWait(Token&& token = {}) -> Task<> {
|
inline auto AsyncWait(Token&& token = {}) -> Task<> {
|
||||||
return boost::asio::async_initiate<
|
return boost::asio::async_initiate<Token, void(void)>(
|
||||||
Token,
|
[this]<typename Handler>(Handler&& handler) -> void {
|
||||||
void(void)>([this]<typename Handler>(Handler&& handler) -> void {
|
std::unique_lock lc(this->mtx);
|
||||||
std::unique_lock lc(this->mtx);
|
if(this->flag) {
|
||||||
if(this->flag) {
|
return handler();
|
||||||
return handler();
|
};
|
||||||
};
|
this->deadlineTimer.async_wait([h = std::make_unique<Handler>(std::forward<Handler>(handler))](const boost::system::error_code&) {
|
||||||
this->deadlineTimer.async_wait([h = std::make_unique<Handler>(std::forward<Handler>(handler))](const boost::system::error_code&){
|
return (*h)();
|
||||||
return (*h)();
|
});
|
||||||
});
|
},
|
||||||
}, token);
|
token);
|
||||||
};
|
};
|
||||||
inline auto Wait() -> void {
|
inline auto Wait() -> void {
|
||||||
this->deadlineTimer.wait();
|
this->deadlineTimer.wait();
|
||||||
|
@ -120,7 +119,7 @@ struct AsyncConditionVariable {
|
||||||
};
|
};
|
||||||
std::mutex mtx;
|
std::mutex mtx;
|
||||||
boost::asio::deadline_timer deadlineTimer;
|
boost::asio::deadline_timer deadlineTimer;
|
||||||
bool flag;
|
bool flag{};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Component, typename T>
|
template <typename Component, typename T>
|
||||||
|
@ -136,8 +135,8 @@ struct ServiceContextForComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <utempl::ConstexprString Name>
|
template <utempl::ConstexprString Name>
|
||||||
constexpr auto FindComponent() -> auto&
|
constexpr auto FindComponent() -> auto& requires(Name == kBasicTaskProcessorName ||
|
||||||
requires (Name == kBasicTaskProcessorName || requires {this->FindComponent<kUtils.template GetIndexByName(Name)>();}) {
|
requires { this->FindComponent<kUtils.template GetIndexByName(Name)>(); }) {
|
||||||
if constexpr(Name == kBasicTaskProcessorName) {
|
if constexpr(Name == kBasicTaskProcessorName) {
|
||||||
return this->context.taskProcessor;
|
return this->context.taskProcessor;
|
||||||
} else {
|
} else {
|
||||||
|
@ -155,7 +154,7 @@ struct ServiceContextForComponent {
|
||||||
};
|
};
|
||||||
template <template <typename...> typename F>
|
template <template <typename...> typename F>
|
||||||
constexpr auto FindAllComponents() {
|
constexpr auto FindAllComponents() {
|
||||||
return utempl::Unpack(utempl::PackConstexprWrapper<kUtils.template GetAllIndexes<F>(), utempl::Tuple<>>(),
|
return utempl::Unpack(utempl::PackConstexprWrapper<kUtils.template GetAllIndexes<F>(), utempl::Tuple<>>(),
|
||||||
[&](auto... is) -> utempl::Tuple<decltype(*Get<is>(context.storage))&...> {
|
[&](auto... is) -> utempl::Tuple<decltype(*Get<is>(context.storage))&...> {
|
||||||
return {context.template FindComponent<Component, is>()...};
|
return {context.template FindComponent<Component, is>()...};
|
||||||
});
|
});
|
||||||
|
@ -168,13 +167,9 @@ struct ServiceContextForComponentWithCliArgs : ServiceContextForComponent<Compon
|
||||||
const char** argv;
|
const char** argv;
|
||||||
|
|
||||||
constexpr ServiceContextForComponentWithCliArgs(T& context, int argc, const char** argv) :
|
constexpr ServiceContextForComponentWithCliArgs(T& context, int argc, const char** argv) :
|
||||||
ServiceContextForComponent<Component, T>(context),
|
ServiceContextForComponent<Component, T>(context), argc(argc), argv(argv) {};
|
||||||
argc(argc),
|
|
||||||
argv(argv) {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <utempl::Tuple DependencyGraph, typename T>
|
template <utempl::Tuple DependencyGraph, typename T>
|
||||||
inline constexpr auto InitComponents(T& ccontext, int ac, const char** av) -> void {
|
inline constexpr auto InitComponents(T& ccontext, int ac, const char** av) -> void {
|
||||||
static auto& context = ccontext;
|
static auto& context = ccontext;
|
||||||
|
@ -189,9 +184,11 @@ inline constexpr auto InitComponents(T& ccontext, int ac, const char** av) -> vo
|
||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
}();
|
}();
|
||||||
static utempl::Tuple inited = TransformDependencyGraphToTupleWithDependenciesToInitedFlagChanges<AsyncConditionVariable, DependencyGraph>(ioContext);
|
static utempl::Tuple inited =
|
||||||
|
TransformDependencyGraphToTupleWithDependenciesToInitedFlagChanges<AsyncConditionVariable, DependencyGraph>(ioContext);
|
||||||
auto work = make_work_guard(ioContext);
|
auto work = make_work_guard(ioContext);
|
||||||
[]<std::size_t... Is>(std::index_sequence<Is...>){
|
[]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||||
|
// clang-format off
|
||||||
(boost::asio::co_spawn(ioContext, []() -> cserver::Task<> {
|
(boost::asio::co_spawn(ioContext, []() -> cserver::Task<> {
|
||||||
using Current = decltype(Get<Is>(decltype(T::kUtils)::kComponentConfigs));
|
using Current = decltype(Get<Is>(decltype(T::kUtils)::kComponentConfigs));
|
||||||
auto& dependencies = Get<Is>(inited);
|
auto& dependencies = Get<Is>(inited);
|
||||||
|
@ -226,6 +223,7 @@ inline constexpr auto InitComponents(T& ccontext, int ac, const char** av) -> vo
|
||||||
Get<Is>(context.storage)->Run();
|
Get<Is>(context.storage)->Run();
|
||||||
};
|
};
|
||||||
}(), boost::asio::detached), ...);
|
}(), boost::asio::detached), ...);
|
||||||
|
// clang-format on
|
||||||
}(std::make_index_sequence<utempl::kTupleSize<decltype(DependencyGraph)>>());
|
}(std::make_index_sequence<utempl::kTupleSize<decltype(DependencyGraph)>>());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -239,7 +237,7 @@ struct DependenciesUtils {
|
||||||
static consteval auto GetIndexByType() -> std::size_t {
|
static consteval auto GetIndexByType() -> std::size_t {
|
||||||
return utempl::Find<std::remove_cvref_t<T>>(kTypeList);
|
return utempl::Find<std::remove_cvref_t<T>>(kTypeList);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
static consteval auto GetIndexByName(const utempl::ConstexprString<N>& name) -> std::size_t {
|
static consteval auto GetIndexByName(const utempl::ConstexprString<N>& name) -> std::size_t {
|
||||||
return utempl::Find(kNames, name);
|
return utempl::Find(kNames, name);
|
||||||
|
@ -254,58 +252,52 @@ struct DependenciesUtils {
|
||||||
template <template <typename...> typename F>
|
template <template <typename...> typename F>
|
||||||
static consteval auto GetAllIndexes() {
|
static consteval auto GetAllIndexes() {
|
||||||
return [&](auto... is) {
|
return [&](auto... is) {
|
||||||
return utempl::TupleCat(std::array<std::size_t, 0>{}, [&]{
|
return utempl::TupleCat(std::array<std::size_t, 0>{}, [&] {
|
||||||
if constexpr(F<typename Ts::Type>::value) {
|
if constexpr(F<typename Ts::Type>::value) {
|
||||||
return std::to_array<std::size_t>({is});
|
return std::to_array<std::size_t>({is});
|
||||||
} else {
|
} else {
|
||||||
return std::array<std::size_t, 0>{};
|
return std::array<std::size_t, 0>{};
|
||||||
};
|
};
|
||||||
}()...);} | utempl::kSeq<sizeof...(Ts)>;
|
}()...);
|
||||||
|
} | utempl::kSeq<sizeof...(Ts)>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <std::size_t I>
|
template <std::size_t I>
|
||||||
static consteval auto GetName() {
|
static consteval auto GetName() {
|
||||||
return Get<I>(kNames);
|
return Get<I>(kNames);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
|
|
||||||
} // namespace impl
|
#define COMPONENT_REQUIRES(name, impl) /* NOLINT */ \
|
||||||
|
template <typename T> \
|
||||||
#define COMPONENT_REQUIRES(name, impl) \
|
concept name = impl; \
|
||||||
template <typename T> \
|
template <typename T> \
|
||||||
concept name = impl ; \
|
struct name##M { \
|
||||||
template <typename T> \
|
static constexpr auto value = name<T>; \
|
||||||
struct name##M { \
|
|
||||||
static constexpr auto value = name<T>;\
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <ConstexprConfig config, utempl::Tuple DependencyGraph, typename... Ts>
|
template <ConstexprConfig config, utempl::Tuple DependencyGraph, typename... Ts>
|
||||||
struct ServiceContext {
|
struct ServiceContext {
|
||||||
static constexpr auto kConfig = config;
|
static constexpr auto kConfig = config;
|
||||||
static constexpr auto kThreadsCount = config.template Get<"threads">();
|
static constexpr auto kThreadsCount = config.template Get<"threads">();
|
||||||
static constexpr impl::DependenciesUtils<Ts...> kUtils;
|
static constexpr impl::DependenciesUtils<Ts...> kUtils;
|
||||||
engine::basic::TaskProcessor<kThreadsCount - 1> taskProcessor;
|
engine::basic::TaskProcessor<kThreadsCount - 1> taskProcessor;
|
||||||
utempl::Tuple<std::optional<typename Ts::Type>...> storage;
|
utempl::Tuple<std::optional<typename Ts::Type>...> storage{};
|
||||||
|
|
||||||
constexpr ServiceContext() :
|
constexpr ServiceContext() : taskProcessor{utempl::Wrapper<utempl::ConstexprString{kBasicTaskProcessorName}>{}, *this} {};
|
||||||
taskProcessor{utempl::Wrapper<utempl::ConstexprString{kBasicTaskProcessorName}>{}, *this}
|
|
||||||
,storage{} {
|
|
||||||
};
|
|
||||||
constexpr auto Run(int argc, const char** argv) {
|
constexpr auto Run(int argc, const char** argv) {
|
||||||
impl::InitComponents<DependencyGraph>(*this, argc, argv);
|
impl::InitComponents<DependencyGraph>(*this, argc, argv);
|
||||||
this->taskProcessor.Run();
|
this->taskProcessor.Run();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename Component>
|
template <typename Component>
|
||||||
constexpr auto GetContextFor() /* Internal Use Only */ {
|
constexpr auto GetContextFor() /* Internal Use Only */ {
|
||||||
return impl::ServiceContextForComponent<Component, std::decay_t<decltype(*this)>>{*this};
|
return impl::ServiceContextForComponent<Component, std::decay_t<decltype(*this)>>{*this};
|
||||||
};
|
};
|
||||||
private:
|
|
||||||
|
private:
|
||||||
static constexpr struct {
|
static constexpr struct {
|
||||||
constexpr auto operator=(auto&&) const noexcept {};
|
constexpr auto operator=(auto&&) const noexcept {};
|
||||||
} ComponentType{};
|
} ComponentType{};
|
||||||
|
@ -318,28 +310,27 @@ private:
|
||||||
static constexpr struct {
|
static constexpr struct {
|
||||||
constexpr auto operator=(auto&&) const noexcept {};
|
constexpr auto operator=(auto&&) const noexcept {};
|
||||||
} RequiredComponent;
|
} RequiredComponent;
|
||||||
public:
|
|
||||||
|
public:
|
||||||
template <typename Current, std::size_t I>
|
template <typename Current, std::size_t I>
|
||||||
constexpr auto FindComponent() -> decltype(*Get<I>(this->storage))& {
|
constexpr auto FindComponent() -> decltype(*Get<I>(this->storage))& {
|
||||||
constexpr auto Index = kUtils.GetIndexByName(Current::kName);
|
constexpr auto Index = kUtils.GetIndexByName(Current::kName);
|
||||||
constexpr auto J = utempl::loopholes::Counter<Current, utempl::Wrapper<I>>();
|
constexpr auto J = utempl::loopholes::Counter<Current, utempl::Wrapper<I>>();
|
||||||
constexpr auto dependencies = Get<Index>(DependencyGraph);
|
constexpr auto dependencies = Get<Index>(DependencyGraph);
|
||||||
|
|
||||||
static_assert((
|
static_assert((ComponentType = utempl::kType<typename Current::Type>,
|
||||||
ComponentType = utempl::kType<typename Current::Type>,
|
ComponentName = utempl::kWrapper<Current::kName>,
|
||||||
ComponentName = utempl::kWrapper<Current::kName>,
|
ComponentOptions = utempl::kWrapper<Current::kOptions>,
|
||||||
ComponentOptions = utempl::kWrapper<Current::kOptions>,
|
RequiredComponent = utempl::kType<decltype(Get<I>(kUtils.kComponentConfigs))>,
|
||||||
RequiredComponent = utempl::kType<decltype(Get<I>(kUtils.kComponentConfigs))>,
|
dependencies.size() > J),
|
||||||
dependencies.size() > J), "Constructor is not declared as constexpr");
|
"Constructor is not declared as constexpr");
|
||||||
|
|
||||||
return *Get<I>(this->storage);
|
return *Get<I>(this->storage);
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
|
|
||||||
template <typename Current, std::size_t I>
|
template <typename Current, std::size_t I>
|
||||||
struct DependencyInfoKey {};
|
struct DependencyInfoKey {};
|
||||||
|
|
||||||
|
@ -363,7 +354,8 @@ struct DependencyInfoInjector {
|
||||||
if constexpr(name == kBasicTaskProcessorName) {
|
if constexpr(name == kBasicTaskProcessorName) {
|
||||||
return [] -> engine::basic::TaskProcessor<Config.template Get<"threads">() - 1> {
|
return [] -> engine::basic::TaskProcessor<Config.template Get<"threads">() - 1> {
|
||||||
std::unreachable();
|
std::unreachable();
|
||||||
}();
|
}
|
||||||
|
();
|
||||||
} else {
|
} else {
|
||||||
return [] -> decltype(Get<kUtils.GetIndexByName(name)>(kUtils.kTypeList)) {
|
return [] -> decltype(Get<kUtils.GetIndexByName(name)>(kUtils.kTypeList)) {
|
||||||
std::unreachable();
|
std::unreachable();
|
||||||
|
@ -371,69 +363,48 @@ struct DependencyInfoInjector {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <
|
template <utempl::ConstexprString name,
|
||||||
utempl::ConstexprString name,
|
typename...,
|
||||||
typename...,
|
std::size_t I = utempl::loopholes::Counter<Current, utempl::Wrapper<name>>(),
|
||||||
std::size_t I = utempl::loopholes::Counter<Current, utempl::Wrapper<name>>(),
|
auto = utempl::loopholes::Injector<DependencyInfoKey<Current, I>{}, name>{}>
|
||||||
auto = utempl::loopholes::Injector<
|
|
||||||
DependencyInfoKey<
|
|
||||||
Current,
|
|
||||||
I
|
|
||||||
>{},
|
|
||||||
name
|
|
||||||
>{}
|
|
||||||
>
|
|
||||||
static auto FindComponent() -> decltype(FindComponentType<name>())&;
|
static auto FindComponent() -> decltype(FindComponentType<name>())&;
|
||||||
|
|
||||||
|
template <typename T, typename..., typename R = decltype(FindComponent<Get<kUtils.template GetIndexByType<T>()>(kUtils.kNames)>())>
|
||||||
template <
|
|
||||||
typename T,
|
|
||||||
typename...,
|
|
||||||
typename R = decltype(FindComponent<Get<kUtils.template GetIndexByType<T>()>(kUtils.kNames)>())
|
|
||||||
>
|
|
||||||
static auto FindComponent() -> R;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <
|
|
||||||
template <typename...> typename F,
|
|
||||||
typename...,
|
|
||||||
auto Arr = std::to_array<bool>({F<typename Ts::Type>::value...}),
|
|
||||||
std::size_t I = std::ranges::find(Arr, true) - Arr.begin(),
|
|
||||||
typename R = decltype(FindComponent<decltype(Get<I>(utempl::TypeList<Ts...>{}))::kName>())
|
|
||||||
>
|
|
||||||
static auto FindComponent() -> R;
|
static auto FindComponent() -> R;
|
||||||
|
|
||||||
private:
|
template <template <typename...> typename F,
|
||||||
|
typename...,
|
||||||
|
auto Arr = std::to_array<bool>({F<typename Ts::Type>::value...}),
|
||||||
|
std::size_t I = std::ranges::find(Arr, true) - Arr.begin(),
|
||||||
|
typename R = decltype(FindComponent<decltype(Get<I>(utempl::TypeList<Ts...>{}))::kName>())>
|
||||||
|
static auto FindComponent() -> R;
|
||||||
|
|
||||||
|
private:
|
||||||
template <std::size_t... Ids>
|
template <std::size_t... Ids>
|
||||||
static auto FindAllComponentsImpl() -> utempl::Tuple<decltype(FindComponent<decltype(Get<Ids>(utempl::TypeList<Ts...>{}))::kName>())...> {};
|
static auto FindAllComponentsImpl() -> utempl::Tuple<decltype(FindComponent<decltype(Get<Ids>(utempl::TypeList<Ts...>{}))::kName>())...> {
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
template <template <typename...> typename F,
|
||||||
|
typename...,
|
||||||
|
typename R = decltype(utempl::Unpack(utempl::PackConstexprWrapper<kUtils.template GetAllIndexes<F>(), utempl::Tuple<>>(),
|
||||||
template <
|
[](auto... is) -> decltype(FindAllComponentsImpl<is...>()) {
|
||||||
template <typename...> typename F,
|
std::unreachable();
|
||||||
typename...,
|
}))>
|
||||||
typename R = decltype(utempl::Unpack(utempl::PackConstexprWrapper<kUtils.template GetAllIndexes<F>(), utempl::Tuple<>>(),
|
|
||||||
[](auto... is) -> decltype(FindAllComponentsImpl<is...>()) {
|
|
||||||
std::unreachable();
|
|
||||||
}))
|
|
||||||
>
|
|
||||||
static auto FindAllComponents() -> R;
|
static auto FindAllComponents() -> R;
|
||||||
|
|
||||||
template <auto = 0>
|
template <auto = 0>
|
||||||
static consteval auto GetDependencies() {
|
static consteval auto GetDependencies() {
|
||||||
return [](auto... is) {
|
return [](auto... is) {
|
||||||
return ([&]{
|
return ([&] {
|
||||||
constexpr auto response = Magic(utempl::loopholes::Getter<DependencyInfoKey<Current, is>{}>{});
|
constexpr auto response = Magic(utempl::loopholes::Getter<DependencyInfoKey<Current, is>{}>{});
|
||||||
if constexpr(response == kBasicTaskProcessorName) {
|
if constexpr(response == kBasicTaskProcessorName) {
|
||||||
return utempl::Tuple{};
|
return utempl::Tuple{};
|
||||||
} else {
|
} else {
|
||||||
return utempl::Tuple{response};
|
return utempl::Tuple{response};
|
||||||
};
|
};
|
||||||
}() + ... + utempl::Tuple{});
|
}() + ... +
|
||||||
|
utempl::Tuple{});
|
||||||
} | utempl::kSeq<utempl::loopholes::Counter<Current>()>;
|
} | utempl::kSeq<utempl::loopholes::Counter<Current>()>;
|
||||||
};
|
};
|
||||||
static inline consteval auto Inject() {
|
static inline consteval auto Inject() {
|
||||||
|
@ -441,12 +412,11 @@ public:
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace impl
|
} // namespace impl
|
||||||
|
|
||||||
template <utempl::ConstexprString Name, utempl::Tuple Dependencies>
|
template <utempl::ConstexprString Name, utempl::Tuple Dependencies>
|
||||||
struct DependencyGraphElement {};
|
struct DependencyGraphElement {};
|
||||||
|
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct DependencyGraph {
|
struct DependencyGraph {
|
||||||
static constexpr auto kValue = utempl::TypeList<Ts...>{};
|
static constexpr auto kValue = utempl::TypeList<Ts...>{};
|
||||||
|
@ -460,7 +430,7 @@ struct CompileTimeStack {
|
||||||
std::size_t current{};
|
std::size_t current{};
|
||||||
inline constexpr auto Push(T value) {
|
inline constexpr auto Push(T value) {
|
||||||
if(this->current == Size) {
|
if(this->current == Size) {
|
||||||
throw std::out_of_range{0};
|
throw std::out_of_range{nullptr};
|
||||||
};
|
};
|
||||||
this->data[current].emplace(std::move(value));
|
this->data[current].emplace(std::move(value));
|
||||||
this->current++;
|
this->current++;
|
||||||
|
@ -471,25 +441,24 @@ struct CompileTimeStack {
|
||||||
return std::move(*this->data[tmp]);
|
return std::move(*this->data[tmp]);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
} // namespace impl
|
} // namespace impl
|
||||||
|
|
||||||
template <utempl::ConstexprString... Names, utempl::Tuple... Dependencies>
|
template <utempl::ConstexprString... Names, utempl::Tuple... Dependencies>
|
||||||
consteval auto TopologicalSort(const DependencyGraph<DependencyGraphElement<Names, Dependencies>...>&) {
|
consteval auto TopologicalSort(const DependencyGraph<DependencyGraphElement<Names, Dependencies>...>&) {
|
||||||
constexpr utempl::Tuple names = {Names...};
|
constexpr utempl::Tuple names = {Names...};
|
||||||
constexpr utempl::Tuple storage = Map(utempl::Tuple{Dependencies...},
|
constexpr utempl::Tuple storage = Map(utempl::Tuple{Dependencies...}, [&]<utempl::TupleLike Tuple>(Tuple&& tuple) {
|
||||||
[&]<utempl::TupleLike Tuple>(Tuple&& tuple){
|
static constexpr auto Size = utempl::kTupleSize<Tuple>;
|
||||||
static constexpr auto Size = utempl::kTupleSize<Tuple>;
|
return utempl::Unpack(std::forward<Tuple>(tuple), [&]<typename... Args>(Args&&... args) -> std::array<std::size_t, Size> {
|
||||||
return utempl::Unpack(std::forward<Tuple>(tuple),
|
return {Find(names, std::forward<Args>(args))...};
|
||||||
[&]<typename... Args>(Args&&... args) -> std::array<std::size_t, Size> {
|
});
|
||||||
return {Find(names, std::forward<Args>(args))...};
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
constexpr auto Size = utempl::kTupleSize<decltype(storage)>;
|
constexpr auto Size = utempl::kTupleSize<decltype(storage)>;
|
||||||
const std::array adj = utempl::Map(storage,
|
const std::array adj = utempl::Map(
|
||||||
[](std::ranges::range auto& arg){
|
storage,
|
||||||
return std::ranges::subrange(arg.data(), arg.data() + arg.size());
|
[](std::ranges::range auto& arg) {
|
||||||
}, utempl::kType<std::array<std::size_t, 0>>);
|
return std::ranges::subrange(arg.data(), arg.data() + arg.size());
|
||||||
|
},
|
||||||
|
utempl::kType<std::array<std::size_t, 0>>);
|
||||||
std::array<bool, Size> visited{};
|
std::array<bool, Size> visited{};
|
||||||
constexpr auto ResultSize = sizeof...(Dependencies);
|
constexpr auto ResultSize = sizeof...(Dependencies);
|
||||||
impl::CompileTimeStack<std::size_t, ResultSize> response{};
|
impl::CompileTimeStack<std::size_t, ResultSize> response{};
|
||||||
|
@ -507,36 +476,41 @@ consteval auto TopologicalSort(const DependencyGraph<DependencyGraphElement<Name
|
||||||
response.Push(v);
|
response.Push(v);
|
||||||
}(i);
|
}(i);
|
||||||
};
|
};
|
||||||
return utempl::Map(std::move(response.data), [](auto&& data){
|
return utempl::Map(std::move(response.data), [](auto&& data) {
|
||||||
return *data;
|
return *data;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <ConstexprConfig config = {}, typename... ComponentConfigs>
|
template <ConstexprConfig config = {}, typename... ComponentConfigs>
|
||||||
struct ServiceContextBuilder {
|
struct ServiceContextBuilder {
|
||||||
static constexpr auto kList = utempl::kTypeList<ComponentConfigs...>;
|
static constexpr auto kList = utempl::kTypeList<ComponentConfigs...>;
|
||||||
static constexpr impl::DependenciesUtils<ComponentConfigs...> kUtils;
|
static constexpr impl::DependenciesUtils<ComponentConfigs...> kUtils;
|
||||||
static constexpr auto kConfig = config;
|
static constexpr auto kConfig = config;
|
||||||
template <typename T, utempl::ConstexprString name = T::kName, typename... Os>
|
template <typename T, utempl::ConstexprString name = T::kName, typename... Os>
|
||||||
static consteval auto Append(Options<Os...> = {}) -> decltype(T::template Adder<name, Options<Os...>{}>(ServiceContextBuilder<config, ComponentConfigs..., ComponentConfig<name, T, Options<Os...>{}>>{})) {
|
static consteval auto Append(Options<Os...> = {})
|
||||||
|
-> decltype(T::template Adder<name, Options<Os...>{}>(
|
||||||
|
ServiceContextBuilder<config, ComponentConfigs..., ComponentConfig<name, T, Options<Os...>{}>>{})) {
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, utempl::ConstexprString name = T::kName, typename... Os>
|
template <typename T, utempl::ConstexprString name = T::kName, typename... Os>
|
||||||
static consteval auto Append(Options<Os...> = {}) -> ServiceContextBuilder<config, ComponentConfigs..., ComponentConfig<name, T, Options<Os...>{}>>
|
static consteval auto Append(Options<Os...> = {})
|
||||||
requires (!requires(ServiceContextBuilder<config, ComponentConfigs..., ComponentConfig<name, T, Options<Os...>{}>> builder) {T::template Adder<name, Options<Os...>{}>(builder);}) {
|
-> ServiceContextBuilder<config, ComponentConfigs..., ComponentConfig<name, T, Options<Os...>{}>>
|
||||||
|
requires(!requires(ServiceContextBuilder<config, ComponentConfigs..., ComponentConfig<name, T, Options<Os...>{}>> builder) {
|
||||||
|
T::template Adder<name, Options<Os...>{}>(builder);
|
||||||
|
})
|
||||||
|
{
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <utempl::ConstexprString Key, auto Value>
|
template <utempl::ConstexprString Key, auto Value>
|
||||||
static consteval auto AppendConfigParam() -> ServiceContextBuilder<config.template Append<Key>(Value), ComponentConfigs...> {
|
static consteval auto AppendConfigParam() -> ServiceContextBuilder<config.template Append<Key>(Value), ComponentConfigs...> {
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
static consteval auto TransformComponents(F&& f) -> ServiceContextBuilder<config, decltype(impl::TransformIfOk(ComponentConfigs{}, f))...> {
|
static consteval auto TransformComponents(F&& f)
|
||||||
|
-> ServiceContextBuilder<config, decltype(impl::TransformIfOk(ComponentConfigs{}, f))...> {
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
template <utempl::ConstexprString name>
|
template <utempl::ConstexprString name>
|
||||||
|
@ -544,11 +518,12 @@ struct ServiceContextBuilder {
|
||||||
if constexpr(name == kBasicTaskProcessorName) {
|
if constexpr(name == kBasicTaskProcessorName) {
|
||||||
return [] -> engine::basic::TaskProcessor<config.template Get<"threads">() - 1> {
|
return [] -> engine::basic::TaskProcessor<config.template Get<"threads">() - 1> {
|
||||||
std::unreachable();
|
std::unreachable();
|
||||||
}();
|
}
|
||||||
|
();
|
||||||
} else {
|
} else {
|
||||||
return []<typename... TTs, utempl::ConstexprString... names, Options... Options>
|
return []<typename... TTs, utempl::ConstexprString... names, Options... Options>(
|
||||||
(const ServiceContextBuilder<config, ComponentConfig<names, TTs, Options>...>&)
|
const ServiceContextBuilder<config, ComponentConfig<names, TTs, Options>...>&)
|
||||||
-> decltype(utempl::Get<Find(utempl::Tuple{names...}, name)>(utempl::TypeList<TTs...>{})) {
|
-> decltype(utempl::Get<Find(utempl::Tuple{names...}, name)>(utempl::TypeList<TTs...>{})) {
|
||||||
std::unreachable();
|
std::unreachable();
|
||||||
}(ServiceContextBuilder<config, ComponentConfigs...>{});
|
}(ServiceContextBuilder<config, ComponentConfigs...>{});
|
||||||
};
|
};
|
||||||
|
@ -561,44 +536,42 @@ struct ServiceContextBuilder {
|
||||||
|
|
||||||
template <template <typename...> typename F>
|
template <template <typename...> typename F>
|
||||||
static consteval auto FindAllComponents() {
|
static consteval auto FindAllComponents() {
|
||||||
return utempl::Unpack(utempl::PackConstexprWrapper<kUtils.template GetAllIndexes<F>(), utempl::Tuple<>>(),
|
return utempl::Unpack(utempl::PackConstexprWrapper<kUtils.template GetAllIndexes<F>(), utempl::Tuple<>>(),
|
||||||
[](auto... is) -> utempl::Tuple<typename decltype(Get<is>(utempl::kTypeList<ComponentConfigs...>))::Type...> {
|
[](auto... is) -> utempl::Tuple<typename decltype(Get<is>(utempl::kTypeList<ComponentConfigs...>))::Type...> {
|
||||||
std::unreachable();
|
std::unreachable();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static consteval auto Config() {
|
static consteval auto Config() {
|
||||||
return config;
|
return config;
|
||||||
};
|
};
|
||||||
|
|
||||||
static consteval auto GetDependencyGraph() {
|
static consteval auto GetDependencyGraph() {
|
||||||
return [&]<utempl::ConstexprString... names, typename... Components, Options... Options>
|
return [&]<utempl::ConstexprString... names, typename... Components, Options... Options>(
|
||||||
(ComponentConfig<names, Components, Options>...){
|
ComponentConfig<names, Components, Options>...) {
|
||||||
return DependencyGraph<DependencyGraphElement<names,
|
return DependencyGraph<DependencyGraphElement<names,
|
||||||
[]<utempl::ConstexprString name, typename Component, ::cserver::Options OOptions>
|
[]<utempl::ConstexprString name, typename Component, ::cserver::Options OOptions>(
|
||||||
(ComponentConfig<name, Component, OOptions>) {
|
ComponentConfig<name, Component, OOptions>) {
|
||||||
impl::DependencyInfoInjector<Component, name, config, ComponentConfigs...> injector;
|
impl::DependencyInfoInjector<Component, name, config, ComponentConfigs...> injector;
|
||||||
injector.Inject();
|
injector.Inject();
|
||||||
return injector.GetDependencies();
|
return injector.GetDependencies();
|
||||||
}(ComponentConfigs{})>...>{};
|
}(ComponentConfigs{})>...>{};
|
||||||
}(ComponentConfigs{}...);
|
}(ComponentConfigs{}...);
|
||||||
};
|
};
|
||||||
|
|
||||||
static consteval auto GetIndexDependencyGraph() {
|
static consteval auto GetIndexDependencyGraph() {
|
||||||
return []<utempl::ConstexprString... Names, utempl::Tuple... Dependencies>
|
return []<utempl::ConstexprString... Names, utempl::Tuple... Dependencies>(
|
||||||
(DependencyGraph<DependencyGraphElement<Names, Dependencies>...>){
|
DependencyGraph<DependencyGraphElement<Names, Dependencies>...>) {
|
||||||
return utempl::Tuple{Unpack(Dependencies, [](auto... dependencies) -> std::array<std::size_t, sizeof...(dependencies)> {
|
return utempl::Tuple{Unpack(
|
||||||
return {Find(utempl::Tuple{Names...}, dependencies)...};
|
Dependencies, [](auto... dependencies) -> std::array<std::size_t, sizeof...(dependencies)> {
|
||||||
})...};
|
return {Find(utempl::Tuple{Names...}, dependencies)...};
|
||||||
|
})...};
|
||||||
}(GetDependencyGraph());
|
}(GetDependencyGraph());
|
||||||
};
|
};
|
||||||
|
|
||||||
static consteval auto Sort() {
|
static consteval auto Sort() {
|
||||||
constexpr auto sorted = TopologicalSort(GetDependencyGraph());
|
constexpr auto sorted = TopologicalSort(GetDependencyGraph());
|
||||||
return [&]<std::size_t... Is>(std::index_sequence<Is...>){
|
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||||
constexpr auto list = utempl::TypeList<ComponentConfigs...>{};
|
constexpr auto list = utempl::TypeList<ComponentConfigs...>{};
|
||||||
return ServiceContextBuilder<config, decltype(Get<sorted[Is]>(list))...>{};
|
return ServiceContextBuilder<config, decltype(Get<sorted[Is]>(list))...>{};
|
||||||
}(std::index_sequence_for<ComponentConfigs...>{});
|
}(std::index_sequence_for<ComponentConfigs...>{});
|
||||||
|
@ -614,4 +587,4 @@ struct ServiceContextBuilder {
|
||||||
context.taskProcessor.ioContext.run();
|
context.taskProcessor.ioContext.run();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
} // namespace cserver
|
} // namespace cserver
|
||||||
|
|
|
@ -18,7 +18,7 @@ struct SetThreadId : public std::suspend_never {
|
||||||
std::size_t threadId;
|
std::size_t threadId;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace this_coro
|
} // namespace this_coro
|
||||||
|
|
||||||
template <typename T = void>
|
template <typename T = void>
|
||||||
using Task = boost::asio::awaitable<T>;
|
using Task = boost::asio::awaitable<T>;
|
||||||
|
@ -26,7 +26,7 @@ using Task = boost::asio::awaitable<T>;
|
||||||
template <typename...>
|
template <typename...>
|
||||||
struct TaskAwaitable {};
|
struct TaskAwaitable {};
|
||||||
|
|
||||||
} // namespace cserver
|
} // namespace cserver
|
||||||
|
|
||||||
namespace boost::asio::detail {
|
namespace boost::asio::detail {
|
||||||
/*
|
/*
|
||||||
|
@ -58,23 +58,22 @@ DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
template <>
|
template <>
|
||||||
struct awaitable_frame_base<any_io_executor> {
|
struct awaitable_frame_base<any_io_executor> {
|
||||||
public:
|
public:
|
||||||
using Executor = any_io_executor;
|
using Executor = any_io_executor;
|
||||||
#if !defined(BOOST_ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
|
#if !defined(BOOST_ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
|
||||||
inline auto operator new(std::size_t size) -> void* {
|
inline auto operator new(std::size_t size) -> void* {
|
||||||
return boost::asio::detail::thread_info_base::allocate(
|
return boost::asio::detail::thread_info_base::allocate(boost::asio::detail::thread_info_base::awaitable_frame_tag(),
|
||||||
boost::asio::detail::thread_info_base::awaitable_frame_tag(),
|
boost::asio::detail::thread_context::top_of_thread_call_stack(),
|
||||||
boost::asio::detail::thread_context::top_of_thread_call_stack(),
|
size);
|
||||||
size);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto operator delete(void* pointer, std::size_t size) -> void {
|
inline auto operator delete(void* pointer, std::size_t size) -> void {
|
||||||
boost::asio::detail::thread_info_base::deallocate(
|
boost::asio::detail::thread_info_base::deallocate(boost::asio::detail::thread_info_base::awaitable_frame_tag(),
|
||||||
boost::asio::detail::thread_info_base::awaitable_frame_tag(),
|
boost::asio::detail::thread_context::top_of_thread_call_stack(),
|
||||||
boost::asio::detail::thread_context::top_of_thread_call_stack(),
|
pointer,
|
||||||
pointer, size);
|
size);
|
||||||
};
|
};
|
||||||
#endif // !defined(BOOST_ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
|
#endif // !defined(BOOST_ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
|
||||||
|
|
||||||
// The frame starts in a suspended state until the awaitable_thread object
|
// The frame starts in a suspended state until the awaitable_thread object
|
||||||
// pumps the stack.
|
// pumps the stack.
|
||||||
|
@ -124,8 +123,8 @@ public:
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline constexpr auto await_transform(awaitable<T, Executor> a) const -> awaitable<T, Executor> {
|
inline constexpr auto await_transform(awaitable<T, Executor> a) const -> awaitable<T, Executor> {
|
||||||
if (attached_thread_->entry_point()->throw_if_cancelled_) {
|
if(attached_thread_->entry_point()->throw_if_cancelled_) {
|
||||||
if (!!attached_thread_->get_cancellation_state().cancelled()) {
|
if(!!attached_thread_->get_cancellation_state().cancelled()) {
|
||||||
throw_error(boost::asio::error::operation_aborted, "co_await");
|
throw_error(boost::asio::error::operation_aborted, "co_await");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -134,28 +133,29 @@ public:
|
||||||
|
|
||||||
template <typename Op>
|
template <typename Op>
|
||||||
inline constexpr auto await_transform(Op&& op,
|
inline constexpr auto await_transform(Op&& op,
|
||||||
constraint_t<is_async_operation<Op>::value> = 0
|
constraint_t<is_async_operation<Op>::value> = 0
|
||||||
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
|
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
|
||||||
# if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
|
#if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
|
||||||
, detail::source_location location = detail::source_location::current()
|
,
|
||||||
# endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
|
detail::source_location location = detail::source_location::current()
|
||||||
#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
|
#endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
|
||||||
) {
|
#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
|
||||||
if (attached_thread_->entry_point()->throw_if_cancelled_) {
|
) {
|
||||||
if (!!attached_thread_->get_cancellation_state().cancelled()) {
|
if(attached_thread_->entry_point()->throw_if_cancelled_) {
|
||||||
|
if(!!attached_thread_->get_cancellation_state().cancelled()) {
|
||||||
throw_error(boost::asio::error::operation_aborted, "co_await");
|
throw_error(boost::asio::error::operation_aborted, "co_await");
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return awaitable_async_op<
|
return awaitable_async_op<completion_signature_of_t<Op>, decay_t<Op>, Executor>{std::forward<Op>(op),
|
||||||
completion_signature_of_t<Op>, decay_t<Op>, Executor>{
|
this
|
||||||
std::forward<Op>(op), this
|
|
||||||
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
|
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
|
||||||
# if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
|
#if defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
|
||||||
, location
|
,
|
||||||
# endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
|
location
|
||||||
#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
|
#endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
|
||||||
};
|
#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// This await transformation obtains the associated executor of the thread of
|
// This await transformation obtains the associated executor of the thread of
|
||||||
|
@ -168,7 +168,7 @@ public:
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void {};
|
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void{};
|
||||||
|
|
||||||
inline auto await_resume() const noexcept {
|
inline auto await_resume() const noexcept {
|
||||||
return this_->attached_thread_->get_executor();
|
return this_->attached_thread_->get_executor();
|
||||||
|
@ -188,7 +188,7 @@ public:
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void {};
|
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void{};
|
||||||
|
|
||||||
auto await_resume() const noexcept {
|
auto await_resume() const noexcept {
|
||||||
return this_->attached_thread_->get_cancellation_state();
|
return this_->attached_thread_->get_cancellation_state();
|
||||||
|
@ -207,7 +207,7 @@ public:
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void {};
|
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void{};
|
||||||
|
|
||||||
inline constexpr auto await_resume() const {
|
inline constexpr auto await_resume() const {
|
||||||
return this_->attached_thread_->reset_cancellation_state();
|
return this_->attached_thread_->reset_cancellation_state();
|
||||||
|
@ -219,8 +219,7 @@ public:
|
||||||
|
|
||||||
// This await transformation resets the associated cancellation state.
|
// This await transformation resets the associated cancellation state.
|
||||||
template <typename Filter>
|
template <typename Filter>
|
||||||
inline constexpr auto await_transform(
|
inline constexpr auto await_transform(this_coro::reset_cancellation_state_1_t<Filter> reset) noexcept {
|
||||||
this_coro::reset_cancellation_state_1_t<Filter> reset) noexcept {
|
|
||||||
struct Result {
|
struct Result {
|
||||||
awaitable_frame_base* this_;
|
awaitable_frame_base* this_;
|
||||||
Filter filter_;
|
Filter filter_;
|
||||||
|
@ -229,11 +228,10 @@ public:
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void {};
|
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void{};
|
||||||
|
|
||||||
inline constexpr auto await_resume() {
|
inline constexpr auto await_resume() {
|
||||||
return this_->attached_thread_->reset_cancellation_state(
|
return this_->attached_thread_->reset_cancellation_state(static_cast<Filter&&>(filter_));
|
||||||
static_cast<Filter&&>(filter_));
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -246,8 +244,7 @@ public:
|
||||||
|
|
||||||
// This await transformation resets the associated cancellation state.
|
// This await transformation resets the associated cancellation state.
|
||||||
template <typename InFilter, typename OutFilter>
|
template <typename InFilter, typename OutFilter>
|
||||||
inline constexpr auto await_transform(
|
inline constexpr auto await_transform(this_coro::reset_cancellation_state_2_t<InFilter, OutFilter> reset) noexcept {
|
||||||
this_coro::reset_cancellation_state_2_t<InFilter, OutFilter> reset) noexcept {
|
|
||||||
struct Result {
|
struct Result {
|
||||||
awaitable_frame_base* this_;
|
awaitable_frame_base* this_;
|
||||||
InFilter in_filter_;
|
InFilter in_filter_;
|
||||||
|
@ -256,19 +253,16 @@ public:
|
||||||
inline constexpr auto await_ready() const noexcept -> bool {
|
inline constexpr auto await_ready() const noexcept -> bool {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void {};
|
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void{};
|
||||||
|
|
||||||
inline constexpr auto await_resume() {
|
inline constexpr auto await_resume() {
|
||||||
return this_->attached_thread_->reset_cancellation_state(
|
return this_->attached_thread_->reset_cancellation_state(static_cast<InFilter&&>(in_filter_),
|
||||||
static_cast<InFilter&&>(in_filter_),
|
static_cast<OutFilter&&>(out_filter_));
|
||||||
static_cast<OutFilter&&>(out_filter_));
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return Result{this,
|
return Result{this, static_cast<InFilter&&>(reset.in_filter), static_cast<OutFilter&&>(reset.out_filter)};
|
||||||
static_cast<InFilter&&>(reset.in_filter),
|
|
||||||
static_cast<OutFilter&&>(reset.out_filter)};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// This await transformation determines whether cancellation is propagated as
|
// This await transformation determines whether cancellation is propagated as
|
||||||
|
@ -281,7 +275,7 @@ public:
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void {};
|
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void{};
|
||||||
|
|
||||||
inline constexpr auto await_resume() {
|
inline constexpr auto await_resume() {
|
||||||
return this_->attached_thread_->throw_if_cancelled();
|
return this_->attached_thread_->throw_if_cancelled();
|
||||||
|
@ -302,7 +296,7 @@ public:
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void {};
|
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void{};
|
||||||
|
|
||||||
inline constexpr auto await_resume() {
|
inline constexpr auto await_resume() {
|
||||||
this_->attached_thread_->throw_if_cancelled(value_);
|
this_->attached_thread_->throw_if_cancelled(value_);
|
||||||
|
@ -317,13 +311,9 @@ public:
|
||||||
// immediate resumption of the coroutine in another thread does not cause a
|
// immediate resumption of the coroutine in another thread does not cause a
|
||||||
// race condition.
|
// race condition.
|
||||||
template <typename Function>
|
template <typename Function>
|
||||||
inline constexpr auto await_transform(Function f,
|
inline constexpr auto await_transform(
|
||||||
enable_if_t<
|
Function f,
|
||||||
is_convertible<
|
enable_if_t<is_convertible<result_of_t<Function(awaitable_frame_base*)>, awaitable_thread<Executor>*>::value>* = nullptr) {
|
||||||
result_of_t<Function(awaitable_frame_base*)>,
|
|
||||||
awaitable_thread<Executor>*
|
|
||||||
>::value
|
|
||||||
>* = nullptr) {
|
|
||||||
struct Result {
|
struct Result {
|
||||||
Function function_;
|
Function function_;
|
||||||
awaitable_frame_base* this_;
|
awaitable_frame_base* this_;
|
||||||
|
@ -334,11 +324,11 @@ public:
|
||||||
|
|
||||||
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void {
|
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void {
|
||||||
this_->after_suspend(
|
this_->after_suspend(
|
||||||
[](void* arg)
|
[](void* arg) {
|
||||||
{
|
|
||||||
Result* r = static_cast<Result*>(arg);
|
Result* r = static_cast<Result*>(arg);
|
||||||
r->function_(r->this_);
|
r->function_(r->this_);
|
||||||
}, this);
|
},
|
||||||
|
this);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto await_resume() const noexcept -> void {};
|
inline constexpr auto await_resume() const noexcept -> void {};
|
||||||
|
@ -356,7 +346,7 @@ public:
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void {};
|
inline constexpr auto await_suspend(coroutine_handle<void>) noexcept -> void{};
|
||||||
|
|
||||||
inline constexpr auto await_resume() const noexcept -> bool& {
|
inline constexpr auto await_resume() const noexcept -> bool& {
|
||||||
return this_->attached_thread_->entry_point()->has_context_switched_;
|
return this_->attached_thread_->entry_point()->has_context_switched_;
|
||||||
|
@ -370,7 +360,7 @@ public:
|
||||||
attached_thread_ = handler;
|
attached_thread_ = handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto detach_thread() noexcept ->awaitable_thread<Executor>* {
|
inline constexpr auto detach_thread() noexcept -> awaitable_thread<Executor>* {
|
||||||
attached_thread_->entry_point()->has_context_switched_ = true;
|
attached_thread_->entry_point()->has_context_switched_ = true;
|
||||||
return std::exchange(attached_thread_, nullptr);
|
return std::exchange(attached_thread_, nullptr);
|
||||||
};
|
};
|
||||||
|
@ -384,7 +374,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto pop_frame() noexcept -> void {
|
inline constexpr auto pop_frame() noexcept -> void {
|
||||||
if (caller_) {
|
if(caller_) {
|
||||||
caller_->attached_thread_ = attached_thread_;
|
caller_->attached_thread_ = attached_thread_;
|
||||||
};
|
};
|
||||||
attached_thread_->entry_point()->top_of_stack_ = caller_;
|
attached_thread_->entry_point()->top_of_stack_ = caller_;
|
||||||
|
@ -394,14 +384,14 @@ public:
|
||||||
|
|
||||||
struct resume_context {
|
struct resume_context {
|
||||||
void (*after_suspend_fn_)(void*) = nullptr;
|
void (*after_suspend_fn_)(void*) = nullptr;
|
||||||
void *after_suspend_arg_ = nullptr;
|
void* after_suspend_arg_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto resume() -> void {
|
inline constexpr auto resume() -> void {
|
||||||
resume_context context;
|
resume_context context;
|
||||||
resume_context_ = &context;
|
resume_context_ = &context;
|
||||||
coro_.resume();
|
coro_.resume();
|
||||||
if (context.after_suspend_fn_) {
|
if(context.after_suspend_fn_) {
|
||||||
context.after_suspend_fn_(context.after_suspend_arg_);
|
context.after_suspend_fn_(context.after_suspend_arg_);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -424,7 +414,8 @@ public:
|
||||||
return awaitable;
|
return awaitable;
|
||||||
};
|
};
|
||||||
std::size_t threadId{};
|
std::size_t threadId{};
|
||||||
protected:
|
|
||||||
|
protected:
|
||||||
coroutine_handle<void> coro_ = nullptr;
|
coroutine_handle<void> coro_ = nullptr;
|
||||||
awaitable_thread<Executor>* attached_thread_ = nullptr;
|
awaitable_thread<Executor>* attached_thread_ = nullptr;
|
||||||
awaitable_frame_base<Executor>* caller_ = nullptr;
|
awaitable_frame_base<Executor>* caller_ = nullptr;
|
||||||
|
@ -432,4 +423,4 @@ protected:
|
||||||
resume_context* resume_context_ = nullptr;
|
resume_context* resume_context_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace boost::asio::detail
|
} // namespace boost::asio::detail
|
||||||
|
|
|
@ -9,15 +9,16 @@ class TcpResolver;
|
||||||
|
|
||||||
class IoContext {
|
class IoContext {
|
||||||
boost::asio::io_context impl;
|
boost::asio::io_context impl;
|
||||||
public:
|
|
||||||
inline constexpr IoContext() : impl() {};
|
public:
|
||||||
|
inline IoContext() : impl() {};
|
||||||
class Work {
|
class Work {
|
||||||
boost::asio::io_context::work impl;
|
boost::asio::io_context::work impl;
|
||||||
public:
|
|
||||||
inline constexpr Work(IoContext& ioContext) :
|
public:
|
||||||
impl(ioContext.impl) {};
|
explicit inline Work(IoContext& ioContext) : impl(ioContext.impl) {};
|
||||||
inline constexpr Work(Work&&) = default;
|
inline Work(Work&&) = default;
|
||||||
inline constexpr Work(const Work&) = default;
|
inline Work(const Work&) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
friend DeadLineTimer;
|
friend DeadLineTimer;
|
||||||
|
@ -26,13 +27,12 @@ public:
|
||||||
friend TcpResolver;
|
friend TcpResolver;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class DeadLineTimer {
|
class DeadLineTimer {
|
||||||
boost::asio::deadline_timer impl;
|
boost::asio::deadline_timer impl;
|
||||||
public:
|
|
||||||
inline constexpr DeadLineTimer(IoContext& ioContext) :
|
public:
|
||||||
impl(ioContext.impl) {};
|
explicit inline DeadLineTimer(IoContext& ioContext) : impl(ioContext.impl) {};
|
||||||
inline constexpr auto AsyncWait() -> Task<> {
|
inline auto AsyncWait() -> Task<> {
|
||||||
return this->impl.async_wait(boost::asio::use_awaitable);
|
return this->impl.async_wait(boost::asio::use_awaitable);
|
||||||
};
|
};
|
||||||
inline constexpr auto Cancel() -> void {
|
inline constexpr auto Cancel() -> void {
|
||||||
|
@ -45,11 +45,10 @@ public:
|
||||||
|
|
||||||
class TcpSocket {
|
class TcpSocket {
|
||||||
boost::asio::ip::tcp::socket impl;
|
boost::asio::ip::tcp::socket impl;
|
||||||
public:
|
|
||||||
inline constexpr TcpSocket(IoContext& ioContext) :
|
public:
|
||||||
impl(ioContext.impl) {};
|
explicit inline TcpSocket(IoContext& ioContext) : impl(ioContext.impl) {};
|
||||||
inline constexpr TcpSocket(TcpSocket&& other) :
|
inline TcpSocket(TcpSocket&& other) : impl(std::move(other.impl)) {};
|
||||||
impl(std::move(other.impl)) {};
|
|
||||||
|
|
||||||
template <typename Buffer, typename CompletionCondition>
|
template <typename Buffer, typename CompletionCondition>
|
||||||
friend inline constexpr auto AsyncWrite(TcpSocket& socket, Buffer buffer, CompletionCondition completion);
|
friend inline constexpr auto AsyncWrite(TcpSocket& socket, Buffer buffer, CompletionCondition completion);
|
||||||
|
@ -68,40 +67,38 @@ class TcpEntry;
|
||||||
|
|
||||||
class TcpEndpoint {
|
class TcpEndpoint {
|
||||||
boost::asio::ip::tcp::endpoint impl;
|
boost::asio::ip::tcp::endpoint impl;
|
||||||
inline constexpr TcpEndpoint(boost::asio::ip::tcp::endpoint impl) : impl(std::move(impl)) {};
|
explicit inline TcpEndpoint(boost::asio::ip::tcp::endpoint impl) : impl(std::move(impl)) {};
|
||||||
public:
|
|
||||||
|
public:
|
||||||
friend TcpEntry;
|
friend TcpEntry;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TcpEntry {
|
class TcpEntry {
|
||||||
boost::asio::ip::tcp::resolver::results_type::value_type impl;
|
boost::asio::ip::tcp::resolver::results_type::value_type impl;
|
||||||
public:
|
|
||||||
inline constexpr TcpEntry() = default;
|
public:
|
||||||
inline constexpr TcpEntry(const TcpEndpoint& ep,
|
inline TcpEntry() = default;
|
||||||
std::string_view host,
|
inline TcpEntry(const TcpEndpoint& ep, std::string_view host, std::string_view service) : impl(ep.impl, host, service) {};
|
||||||
std::string_view service) : impl(ep.impl, host, service) {};
|
inline auto Endpoint() -> TcpEndpoint {
|
||||||
inline constexpr auto Endpoint() -> TcpEndpoint {
|
return TcpEndpoint{this->impl.endpoint()};
|
||||||
return {this->impl.endpoint()};
|
|
||||||
};
|
};
|
||||||
inline constexpr auto HostName() -> std::string {
|
inline auto HostName() -> std::string {
|
||||||
return this->impl.host_name();
|
return this->impl.host_name();
|
||||||
};
|
};
|
||||||
inline constexpr auto ServiceName() -> std::string {
|
inline constexpr auto ServiceName() -> std::string {
|
||||||
return this->impl.service_name();
|
return this->impl.service_name();
|
||||||
};
|
};
|
||||||
inline constexpr operator TcpEndpoint() {
|
explicit inline operator TcpEndpoint() {
|
||||||
return {this->impl};
|
return TcpEndpoint{this->impl};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TcpResolver {
|
class TcpResolver {
|
||||||
boost::asio::ip::tcp::resolver impl;
|
boost::asio::ip::tcp::resolver impl;
|
||||||
public:
|
|
||||||
inline constexpr TcpResolver(IoContext& ioContext) : impl(ioContext.impl) {};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit inline TcpResolver(IoContext& ioContext) : impl(ioContext.impl) {};
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline constexpr auto Buffer(const T* ptr, std::size_t size) {
|
inline constexpr auto Buffer(const T* ptr, std::size_t size) {
|
||||||
|
@ -113,34 +110,33 @@ inline constexpr auto DynamicBuffer(T&& arg) -> decltype(boost::asio::dynamic_bu
|
||||||
return boost::asio::dynamic_buffer(std::forward<T>(arg));
|
return boost::asio::dynamic_buffer(std::forward<T>(arg));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename Socket, typename Buffer>
|
template <typename Socket, typename Buffer>
|
||||||
inline constexpr auto AsyncWrite(Socket&& socket, Buffer buffer) -> Task<> {
|
inline auto AsyncWrite(Socket&& socket, Buffer buffer) -> Task<> {
|
||||||
return boost::asio::async_write(std::forward<Socket>(socket).impl, std::move(buffer), boost::asio::use_awaitable);
|
return boost::asio::async_write(std::forward<Socket>(socket).impl, std::move(buffer), boost::asio::use_awaitable);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Socket, typename Buffer, typename CompletionCondition>
|
template <typename Socket, typename Buffer, typename CompletionCondition>
|
||||||
inline constexpr auto AsyncWrite(Socket&& socket, Buffer buffer, CompletionCondition completion) -> Task<> {
|
inline auto AsyncWrite(Socket&& socket, Buffer buffer, CompletionCondition completion) -> Task<> {
|
||||||
return boost::asio::async_write(std::forward<Socket>(socket).impl, std::move(buffer), std::move(completion), boost::asio::use_awaitable);
|
return boost::asio::async_write(std::forward<Socket>(socket).impl, std::move(buffer), std::move(completion), boost::asio::use_awaitable);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Socket, typename Buffer>
|
template <typename Socket, typename Buffer>
|
||||||
inline constexpr auto AsyncRead(Socket&& socket, Buffer buffer) -> Task<> {
|
inline auto AsyncRead(Socket&& socket, Buffer buffer) -> Task<> {
|
||||||
return boost::asio::async_read(std::forward<Socket>(socket).impl, std::move(buffer), boost::asio::use_awaitable);
|
return boost::asio::async_read(std::forward<Socket>(socket).impl, std::move(buffer), boost::asio::use_awaitable);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Socket, typename Buffer, typename CompletionCondition>
|
template <typename Socket, typename Buffer, typename CompletionCondition>
|
||||||
inline constexpr auto AsyncRead(Socket&& socket, Buffer buffer, CompletionCondition completion) -> Task<> {
|
inline auto AsyncRead(Socket&& socket, Buffer buffer, CompletionCondition completion) -> Task<> {
|
||||||
return boost::asio::async_read(std::forward<Socket>(socket).impl, std::move(buffer), std::move(completion), boost::asio::use_awaitable);
|
return boost::asio::async_read(std::forward<Socket>(socket).impl, std::move(buffer), std::move(completion), boost::asio::use_awaitable);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Socket, typename Buffer, typename Match>
|
template <typename Socket, typename Buffer, typename Match>
|
||||||
inline constexpr auto AsyncReadUntil(Socket&& socket, Buffer buffer, Match match) -> Task<> {
|
inline auto AsyncReadUntil(Socket&& socket, Buffer buffer, Match match) -> Task<> {
|
||||||
return boost::asio::async_read_until(std::forward<Socket>(socket).impl, std::move(buffer), std::move(match), boost::asio::use_awaitable);
|
return boost::asio::async_read_until(std::forward<Socket>(socket).impl, std::move(buffer), std::move(match), boost::asio::use_awaitable);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr auto TransferAll() {
|
inline auto TransferAll() {
|
||||||
return boost::asio::transfer_all();
|
return boost::asio::transfer_all();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cserver::network
|
} // namespace cserver::network
|
||||||
|
|
|
@ -8,4 +8,4 @@ struct NotImplemented : std::runtime_error {
|
||||||
using std::runtime_error::runtime_error;
|
using std::runtime_error::runtime_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cserver::engine
|
} // namespace cserver::engine
|
||||||
|
|
|
@ -6,4 +6,4 @@ struct UseStreaming {};
|
||||||
|
|
||||||
inline constexpr auto kUseStreaming = UseStreaming{};
|
inline constexpr auto kUseStreaming = UseStreaming{};
|
||||||
|
|
||||||
} // namespace cserver
|
} // namespace cserver
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <cserver/components/loggable_component_base.hpp>
|
||||||
#include <cserver/engine/components.hpp>
|
#include <cserver/engine/components.hpp>
|
||||||
|
#include <cserver/engine/coroutine.hpp>
|
||||||
#include <cserver/server/http/http_request.hpp>
|
#include <cserver/server/http/http_request.hpp>
|
||||||
#include <cserver/server/http/http_response.hpp>
|
#include <cserver/server/http/http_response.hpp>
|
||||||
#include <cserver/server/http/http_stream.hpp>
|
#include <cserver/server/http/http_stream.hpp>
|
||||||
#include <cserver/engine/coroutine.hpp>
|
|
||||||
#include <cserver/components/loggable_component_base.hpp>
|
|
||||||
|
|
||||||
namespace cserver::server::handlers {
|
namespace cserver::server::handlers {
|
||||||
|
|
||||||
|
|
||||||
struct HttpHandlerBase : ComponentBase {
|
struct HttpHandlerBase : ComponentBase {
|
||||||
template <typename T, utempl::ConstexprString name, Options>
|
template <typename T, utempl::ConstexprString name, Options>
|
||||||
static consteval auto HttpHandlerAdder(const auto& context) {
|
static consteval auto HttpHandlerAdder(const auto& context) {
|
||||||
|
@ -17,25 +16,31 @@ struct HttpHandlerBase : ComponentBase {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
template <typename Self>
|
template <typename Self>
|
||||||
inline auto HandleRequest(this Self&& self, http::HttpRequest&& request
|
inline auto HandleRequest(this Self&& self, http::HttpRequest&& request) -> Task<http::HttpResponse>
|
||||||
) -> Task<http::HttpResponse> requires requires{self.HandleRequestThrow(std::move(request));} {
|
requires requires { self.HandleRequestThrow(std::move(request)); }
|
||||||
|
{
|
||||||
using T = std::remove_cvref_t<Self>;
|
using T = std::remove_cvref_t<Self>;
|
||||||
try {
|
try {
|
||||||
co_return co_await std::forward<Self>(self).HandleRequestThrow(std::move(request));
|
co_return co_await std::forward<Self>(self).HandleRequestThrow(std::move(request));
|
||||||
} catch(const std::exception& err) {
|
} catch(const std::exception& err) {
|
||||||
auto typeName = boost::core::demangle(__cxxabiv1::__cxa_current_exception_type()->name());
|
auto typeName = boost::core::demangle(__cxxabiv1::__cxa_current_exception_type()->name());
|
||||||
if(self.logging.level <= LoggingLevel::kWarning)
|
if(self.logging.level <= LoggingLevel::kWarning) {
|
||||||
self.logging.template Warning<"In handler with default name {} uncaught exception of type {}: {}">(T::kName, typeName, err.what());
|
self.logging.template Warning<"In handler with default name {} uncaught exception of type {}: {}">(T::kName, typeName, err.what());
|
||||||
|
};
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
auto typeName = boost::core::demangle(__cxxabiv1::__cxa_current_exception_type()->name());
|
auto typeName = boost::core::demangle(__cxxabiv1::__cxa_current_exception_type()->name());
|
||||||
if(self.logging.level <= LoggingLevel::kWarning)
|
if(self.logging.level <= LoggingLevel::kWarning) {
|
||||||
self.logging.template Warning<"In handler with default name {} uncaught exception of type {}">(T::kName, typeName);
|
self.logging.template Warning<"In handler with default name {} uncaught exception of type {}">(T::kName, typeName);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
co_return http::HttpResponse{.statusCode = 500, .statusMessage = "Internal Server Error", .body = "Internal Server Error"};
|
co_return http::HttpResponse{.statusCode = 500, .statusMessage = "Internal Server Error", .body = "Internal Server Error"}; // NOLINT
|
||||||
};
|
};
|
||||||
template <typename Self>
|
template <typename Self>
|
||||||
inline auto HandleRequestStream(this Self&& self, cserver::server::http::HttpRequest&& request,
|
inline auto HandleRequestStream(this Self&& self,
|
||||||
cserver::server::http::HttpStream& stream) -> Task<void> requires requires{self.HandleRequestStreamThrow(std::move(request), stream);} {
|
cserver::server::http::HttpRequest&& request,
|
||||||
|
cserver::server::http::HttpStream& stream) -> Task<void>
|
||||||
|
requires requires { self.HandleRequestStreamThrow(std::move(request), stream); }
|
||||||
|
{
|
||||||
using T = std::remove_cvref_t<Self>;
|
using T = std::remove_cvref_t<Self>;
|
||||||
try {
|
try {
|
||||||
co_await std::forward<Self>(self).HandleRequestStreamThrow(std::move(request), stream);
|
co_await std::forward<Self>(self).HandleRequestStreamThrow(std::move(request), stream);
|
||||||
|
@ -46,8 +51,7 @@ struct HttpHandlerBase : ComponentBase {
|
||||||
};
|
};
|
||||||
co_await stream.Close();
|
co_await stream.Close();
|
||||||
};
|
};
|
||||||
inline constexpr HttpHandlerBase(auto& context) :
|
explicit constexpr HttpHandlerBase(auto& context) : ComponentBase(context) {};
|
||||||
ComponentBase(context) {};
|
|
||||||
};
|
};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct HttpHandlerAdderType {
|
struct HttpHandlerAdderType {
|
||||||
|
@ -58,9 +62,7 @@ struct HttpHandlerAdderType {
|
||||||
};
|
};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct HttpHandlerBaseWithAdder : HttpHandlerBase, HttpHandlerAdderType<T> {
|
struct HttpHandlerBaseWithAdder : HttpHandlerBase, HttpHandlerAdderType<T> {
|
||||||
inline constexpr HttpHandlerBaseWithAdder(auto& context) :
|
explicit constexpr HttpHandlerBaseWithAdder(auto& context) : HttpHandlerBase(context), HttpHandlerAdderType<T>{} {};
|
||||||
HttpHandlerBase(context),
|
|
||||||
HttpHandlerAdderType<T>{} {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cserver::server::handlers
|
} // namespace cserver::server::handlers
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <unordered_map>
|
|
||||||
#include <sstream>
|
|
||||||
#include <boost/url.hpp>
|
#include <boost/url.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace cserver::server::http {
|
namespace cserver::server::http {
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ struct HttpRequest {
|
||||||
boost::urls::url url = {};
|
boost::urls::url url = {};
|
||||||
std::unordered_map<std::string, std::string> headers = {};
|
std::unordered_map<std::string, std::string> headers = {};
|
||||||
std::string body = {};
|
std::string body = {};
|
||||||
inline auto ToString() const -> std::string {
|
[[nodiscard]] inline auto ToString() const -> std::string {
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
stream << fmt::format("{} {} Http/1.1\r\n", this->method, this->url.path());
|
stream << fmt::format("{} {} Http/1.1\r\n", this->method, this->url.path());
|
||||||
for(const auto& header : this->headers) {
|
for(const auto& header : this->headers) {
|
||||||
|
@ -22,4 +23,4 @@ struct HttpRequest {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cserver::server::http
|
} // namespace cserver::server::http
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cserver/server/http/http_request.hpp>
|
|
||||||
#include <llhttp.h>
|
#include <llhttp.h>
|
||||||
|
|
||||||
|
#include <cserver/server/http/http_request.hpp>
|
||||||
|
|
||||||
namespace cserver::server::http {
|
namespace cserver::server::http {
|
||||||
|
|
||||||
struct HttpRequestParser : private llhttp_t, public HttpRequest {
|
struct HttpRequestParser : private llhttp_t, public HttpRequest {
|
||||||
|
@ -10,7 +11,7 @@ struct HttpRequestParser : private llhttp_t, public HttpRequest {
|
||||||
std::string headerField = {};
|
std::string headerField = {};
|
||||||
std::string headerValue = {};
|
std::string headerValue = {};
|
||||||
std::string urlString = {};
|
std::string urlString = {};
|
||||||
inline HttpRequestParser(std::string_view data) {
|
inline HttpRequestParser(std::string_view data) { // NOLINT
|
||||||
llhttp_settings_t settings;
|
llhttp_settings_t settings;
|
||||||
llhttp_settings_init(&settings);
|
llhttp_settings_init(&settings);
|
||||||
settings.on_method = HttpRequestParser::OnMethod;
|
settings.on_method = HttpRequestParser::OnMethod;
|
||||||
|
@ -25,44 +26,44 @@ struct HttpRequestParser : private llhttp_t, public HttpRequest {
|
||||||
llhttp_execute(this, data.data(), data.size());
|
llhttp_execute(this, data.data(), data.size());
|
||||||
};
|
};
|
||||||
static inline auto OnMethod(llhttp_t* parser, const char* data, std::size_t size) -> int {
|
static inline auto OnMethod(llhttp_t* parser, const char* data, std::size_t size) -> int {
|
||||||
auto* self = static_cast<HttpRequest*>(static_cast<HttpRequestParser*>(parser));
|
auto* self = static_cast<HttpRequest*>(static_cast<HttpRequestParser*>(parser)); // NOLINT
|
||||||
self->method.append(data, size);
|
self->method.append(data, size);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
static inline auto OnUrl(llhttp_t* parser, const char* data, std::size_t size) -> int {
|
static inline auto OnUrl(llhttp_t* parser, const char* data, std::size_t size) -> int {
|
||||||
auto* self = static_cast<HttpRequestParser*>(parser);
|
auto* self = static_cast<HttpRequestParser*>(parser); // NOLINT
|
||||||
self->urlString.append(data, size);
|
self->urlString.append(data, size);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
static inline auto OnUrlComplete(llhttp_t* parser) -> int {
|
static inline auto OnUrlComplete(llhttp_t* parser) -> int {
|
||||||
auto* self = static_cast<HttpRequestParser*>(parser);
|
auto* self = static_cast<HttpRequestParser*>(parser); // NOLINT
|
||||||
self->url = boost::urls::url(self->urlString);
|
self->url = boost::urls::url(self->urlString);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
static inline auto OnHeaderField(llhttp_t* parser, const char* data, std::size_t size) -> int {
|
static inline auto OnHeaderField(llhttp_t* parser, const char* data, std::size_t size) -> int {
|
||||||
auto* self = static_cast<HttpRequestParser*>(parser);
|
auto* self = static_cast<HttpRequestParser*>(parser); // NOLINT
|
||||||
self->headerField.append(data, size);
|
self->headerField.append(data, size);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
static inline auto OnHeaderValue(llhttp_t* parser, const char* data, std::size_t size) -> int {
|
static inline auto OnHeaderValue(llhttp_t* parser, const char* data, std::size_t size) -> int {
|
||||||
auto* self = static_cast<HttpRequestParser*>(parser);
|
auto* self = static_cast<HttpRequestParser*>(parser); // NOLINT
|
||||||
self->headerValue.append(data, size);
|
self->headerValue.append(data, size);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
static inline auto OnHeaderComplete(llhttp_t* parser) -> int {
|
static inline auto OnHeaderComplete(llhttp_t* parser) -> int {
|
||||||
auto* self = static_cast<HttpRequestParser*>(parser);
|
auto* self = static_cast<HttpRequestParser*>(parser); // NOLINT
|
||||||
self->headers.emplace(std::move(self->headerField), std::move(self->headerValue));
|
self->headers.emplace(std::move(self->headerField), std::move(self->headerValue));
|
||||||
self->headerValue.clear();
|
self->headerValue.clear();
|
||||||
self->headerField.clear();
|
self->headerField.clear();
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
static inline auto OnBody(llhttp_t* parser, const char* data, std::size_t size) -> int {
|
static inline auto OnBody(llhttp_t* parser, const char* data, std::size_t size) -> int {
|
||||||
auto* self = static_cast<HttpRequestParser*>(parser);
|
auto* self = static_cast<HttpRequestParser*>(parser); // NOLINT
|
||||||
self->body.append(data, size);
|
self->body.append(data, size);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
static inline auto OnMessageComplete(llhttp_t* parser) -> int {
|
static inline auto OnMessageComplete(llhttp_t* parser) -> int {
|
||||||
auto* self = static_cast<HttpRequestParser*>(parser);
|
auto* self = static_cast<HttpRequestParser*>(parser); // NOLINT
|
||||||
self->done = true;
|
self->done = true;
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <unordered_map>
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace cserver::server::http {
|
namespace cserver::server::http {
|
||||||
|
|
||||||
struct HttpResponse {
|
struct HttpResponse {
|
||||||
unsigned short statusCode = 200;
|
std::uint16_t statusCode = 200; // NOLINT
|
||||||
std::string statusMessage = "OK";
|
std::string statusMessage = "OK";
|
||||||
std::unordered_map<std::string, std::string> headers = {};
|
std::unordered_map<std::string, std::string> headers = {};
|
||||||
std::string body = {};
|
std::string body = {};
|
||||||
inline auto ToString() const -> std::string {
|
[[nodiscard]] inline auto ToString() const -> std::string {
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
stream << fmt::format("Http/1.1 {} {}\r\n", this->statusCode, this->statusMessage);
|
stream << fmt::format("Http/1.1 {} {}\r\n", this->statusCode, this->statusMessage);
|
||||||
for(const auto& header : this->headers) {
|
for(const auto& header : this->headers) {
|
||||||
|
@ -23,4 +24,4 @@ struct HttpResponse {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cserver::server::http
|
} // namespace cserver::server::http
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cserver/engine/coroutine.hpp>
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <cserver/engine/coroutine.hpp>
|
||||||
|
|
||||||
namespace cserver::server::http {
|
namespace cserver::server::http {
|
||||||
|
|
||||||
|
@ -10,13 +11,15 @@ struct HttpStream {
|
||||||
std::stringstream stream = {};
|
std::stringstream stream = {};
|
||||||
inline auto SetMethod(std::string method) -> Task<void> {
|
inline auto SetMethod(std::string method) -> Task<void> {
|
||||||
method += " ";
|
method += " ";
|
||||||
co_await boost::asio::async_write(this->socket, boost::asio::buffer(method.data(), method.size()), boost::asio::transfer_all(), boost::asio::use_awaitable);
|
co_await boost::asio::async_write(
|
||||||
|
this->socket, boost::asio::buffer(method.data(), method.size()), boost::asio::transfer_all(), boost::asio::use_awaitable);
|
||||||
};
|
};
|
||||||
inline auto SetStatus(std::string status) -> Task<void> {
|
inline auto SetStatus(std::string status) -> Task<void> {
|
||||||
status = fmt::format("Http/1.1 {}\r\n", std::move(status));
|
status = fmt::format("Http/1.1 {}\r\n", std::move(status));
|
||||||
co_await boost::asio::async_write(this->socket, boost::asio::buffer(status.data(), status.size()), boost::asio::transfer_all(), boost::asio::use_awaitable);
|
co_await boost::asio::async_write(
|
||||||
|
this->socket, boost::asio::buffer(status.data(), status.size()), boost::asio::transfer_all(), boost::asio::use_awaitable);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto SetHeader(std::string first, std::string second) -> Task<void> {
|
inline auto SetHeader(std::string first, std::string second) -> Task<void> {
|
||||||
this->stream << fmt::format("{}: {}\r\n", std::move(first), std::move(second));
|
this->stream << fmt::format("{}: {}\r\n", std::move(first), std::move(second));
|
||||||
co_return;
|
co_return;
|
||||||
|
@ -24,10 +27,12 @@ struct HttpStream {
|
||||||
inline auto SetEndOfHeaders() -> Task<void> {
|
inline auto SetEndOfHeaders() -> Task<void> {
|
||||||
this->stream << "\r\n";
|
this->stream << "\r\n";
|
||||||
auto str = this->stream.str();
|
auto str = this->stream.str();
|
||||||
co_await boost::asio::async_write(this->socket, boost::asio::buffer(str.data(), str.size()), boost::asio::transfer_all(), boost::asio::use_awaitable);
|
co_await boost::asio::async_write(
|
||||||
|
this->socket, boost::asio::buffer(str.data(), str.size()), boost::asio::transfer_all(), boost::asio::use_awaitable);
|
||||||
};
|
};
|
||||||
inline auto PushBodyChunk(std::string_view chunk) -> Task<void> {
|
inline auto PushBodyChunk(std::string_view chunk) -> Task<void> {
|
||||||
co_await boost::asio::async_write(this->socket, boost::asio::buffer(chunk.data(), chunk.size()), boost::asio::transfer_all(), boost::asio::use_awaitable);
|
co_await boost::asio::async_write(
|
||||||
|
this->socket, boost::asio::buffer(chunk.data(), chunk.size()), boost::asio::transfer_all(), boost::asio::use_awaitable);
|
||||||
};
|
};
|
||||||
inline auto Close() -> Task<void> {
|
inline auto Close() -> Task<void> {
|
||||||
this->socket.close();
|
this->socket.close();
|
||||||
|
@ -35,4 +40,4 @@ struct HttpStream {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cserver::server::http
|
} // namespace cserver::server::http
|
||||||
|
|
|
@ -1,55 +1,49 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <cserver/components/work_guard.hpp>
|
||||||
#include <cserver/engine/components.hpp>
|
#include <cserver/engine/components.hpp>
|
||||||
|
#include <cserver/engine/coroutine.hpp>
|
||||||
#include <cserver/server/http/http_request_parser.hpp>
|
#include <cserver/server/http/http_request_parser.hpp>
|
||||||
#include <cserver/server/http/http_response.hpp>
|
#include <cserver/server/http/http_response.hpp>
|
||||||
#include <cserver/engine/coroutine.hpp>
|
|
||||||
#include <cserver/server/http/http_stream.hpp>
|
#include <cserver/server/http/http_stream.hpp>
|
||||||
#include <cserver/components/work_guard.hpp>
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
namespace cserver::server::server {
|
namespace cserver::server::server {
|
||||||
|
|
||||||
|
|
||||||
template <utempl::ConstexprString TPName = "basicTaskProcessor", typename TaskProcessor = int, typename... Ts>
|
template <utempl::ConstexprString TPName = "basicTaskProcessor", typename TaskProcessor = int, typename... Ts>
|
||||||
struct Server : StopBlocker {
|
struct Server : StopBlocker {
|
||||||
TaskProcessor& taskProcessor;
|
TaskProcessor& taskProcessor;
|
||||||
utempl::Tuple<impl::GetTypeFromComponentConfig<Ts>&...> handlers;
|
utempl::Tuple<impl::GetTypeFromComponentConfig<Ts>&...> handlers;
|
||||||
static constexpr utempl::ConstexprString kName = "server";
|
static constexpr utempl::ConstexprString kName = "server";
|
||||||
unsigned short port;
|
std::uint16_t port;
|
||||||
static constexpr utempl::Tuple kNames = {impl::kNameFromComponentConfig<Ts>...};
|
static constexpr utempl::Tuple kNames = {impl::kNameFromComponentConfig<Ts>...};
|
||||||
static constexpr utempl::Tuple kPaths = {impl::GetTypeFromComponentConfig<Ts>::kPath...};
|
static constexpr utempl::Tuple kPaths = {impl::GetTypeFromComponentConfig<Ts>::kPath...};
|
||||||
template <utempl::ConstexprString name, Options Options, typename T>
|
template <utempl::ConstexprString name, Options Options, typename T>
|
||||||
static consteval auto Adder(const T& context) {
|
static consteval auto Adder(const T& context) {
|
||||||
constexpr utempl::ConstexprString tpName = [&]{
|
constexpr utempl::ConstexprString tpName = [&] {
|
||||||
if constexpr(requires{T::kConfig.template Get<name>().template Get<"taskProcessor">();}) {
|
if constexpr(requires { T::kConfig.template Get<name>().template Get<"taskProcessor">(); }) {
|
||||||
return T::kConfig.template Get<name>().template Get<"taskProcessor">();
|
return T::kConfig.template Get<name>().template Get<"taskProcessor">();
|
||||||
} else {
|
} else {
|
||||||
return TPName;
|
return TPName;
|
||||||
};
|
};
|
||||||
}();
|
}();
|
||||||
using TP = decltype(context.template FindComponent<tpName>());
|
using TP = decltype(context.template FindComponent<tpName>());
|
||||||
return context.TransformComponents(
|
return context.TransformComponents([&](const ComponentConfig<name, Server<TPName, int, Ts...>, Options>&)
|
||||||
[&](const ComponentConfig<name, Server<TPName, int, Ts...>, Options>&) -> ComponentConfig<name, Server<tpName, TP, Ts...>, Options> {
|
-> ComponentConfig<name, Server<tpName, TP, Ts...>, Options> {
|
||||||
return {};
|
return {};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
template <
|
template <typename T, std::size_t... Is>
|
||||||
typename T,
|
constexpr Server(std::index_sequence<Is...>, T& context) :
|
||||||
std::size_t... Is>
|
|
||||||
inline constexpr Server(std::index_sequence<Is...>, T& context) :
|
|
||||||
StopBlocker(context),
|
StopBlocker(context),
|
||||||
taskProcessor(context.template FindComponent<TPName>()),
|
taskProcessor(context.template FindComponent<TPName>()),
|
||||||
handlers{context.template FindComponent<Get<Is>(kNames)>()...},
|
handlers{context.template FindComponent<Get<Is>(kNames)>()...},
|
||||||
port(T::kConfig.template Get<T::kName>().template Get<"port">()) {
|
port(T::kConfig.template Get<T::kName>().template Get<"port">()){
|
||||||
|
|
||||||
};
|
};
|
||||||
inline constexpr Server(auto& context) :
|
explicit constexpr Server(auto& context) : Server(std::index_sequence_for<Ts...>{}, context) {};
|
||||||
Server(std::index_sequence_for<Ts...>{}, context) {
|
template <auto I, typename Socket>
|
||||||
};
|
inline auto ProcessHandler(Socket&& socket, http::HttpRequest request) -> Task<void> {
|
||||||
template<auto I, typename Socket>
|
if constexpr(requires(http::HttpStream& stream) { Get<I>(this->handlers).HandleRequestStream(std::move(request), stream); }) {
|
||||||
auto ProcessHandler(Socket&& socket, http::HttpRequest request) -> Task<void> {
|
|
||||||
if constexpr(requires(http::HttpStream& stream){Get<I>(this->handlers).HandleRequestStream(std::move(request), stream);}) {
|
|
||||||
http::HttpStream stream{std::move(socket)};
|
http::HttpStream stream{std::move(socket)};
|
||||||
co_await Get<I>(this->handlers).HandleRequestStream(std::move(request), stream);
|
co_await Get<I>(this->handlers).HandleRequestStream(std::move(request), stream);
|
||||||
co_return;
|
co_return;
|
||||||
|
@ -66,23 +60,26 @@ struct Server : StopBlocker {
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
buffer.reserve(socket.available());
|
buffer.reserve(socket.available());
|
||||||
co_await boost::asio::async_read_until(socket, boost::asio::dynamic_buffer(buffer), "\r\n\r\n", boost::asio::use_awaitable);
|
co_await boost::asio::async_read_until(socket, boost::asio::dynamic_buffer(buffer), "\r\n\r\n", boost::asio::use_awaitable);
|
||||||
http::HttpRequest request = http::HttpRequestParser{buffer};
|
http::HttpRequest request = http::HttpRequestParser{buffer}; // NOLINT
|
||||||
bool flag = false;
|
bool flag = false;
|
||||||
co_await [&]<auto... Is>(std::index_sequence<Is...>) -> cserver::Task<void> {
|
co_await [&]<auto... Is>(std::index_sequence<Is...>) -> cserver::Task<void> {
|
||||||
(co_await [&] -> cserver::Task<void> {
|
(
|
||||||
if(request.url.path().substr(0, Get<Is>(kPaths).size()) == Get<Is>(kPaths)) {
|
co_await [&] -> cserver::Task<void> {
|
||||||
co_await this->ProcessHandler<Is>(std::move(socket), std::move(request));
|
if(request.url.path().substr(0, Get<Is>(kPaths).size()) == Get<Is>(kPaths)) {
|
||||||
};
|
co_await this->ProcessHandler<Is>(std::move(socket), std::move(request));
|
||||||
}(), ...);
|
};
|
||||||
|
}(),
|
||||||
|
...);
|
||||||
}(std::index_sequence_for<Ts...>());
|
}(std::index_sequence_for<Ts...>());
|
||||||
constexpr std::string_view error404 = "Http/1.1 404 Not Found\r\n"
|
constexpr std::string_view error404 =
|
||||||
"Content-Length: 0\r\n"
|
"Http/1.1 404 Not Found\r\n"
|
||||||
"\r\n";
|
"Content-Length: 0\r\n"
|
||||||
|
"\r\n";
|
||||||
if(!flag) {
|
if(!flag) {
|
||||||
co_await boost::asio::async_write(socket, boost::asio::buffer(error404.data(), error404.size()), boost::asio::use_awaitable);
|
co_await boost::asio::async_write(socket, boost::asio::buffer(error404.data(), error404.size()), boost::asio::use_awaitable);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
auto Task() -> Task<void> {
|
inline auto Task() -> Task<void> {
|
||||||
auto executor = co_await boost::asio::this_coro::executor;
|
auto executor = co_await boost::asio::this_coro::executor;
|
||||||
boost::asio::ip::tcp::acceptor acceptor{executor, {boost::asio::ip::tcp::v6(), this->port}};
|
boost::asio::ip::tcp::acceptor acceptor{executor, {boost::asio::ip::tcp::v6(), this->port}};
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
@ -93,9 +90,8 @@ struct Server : StopBlocker {
|
||||||
inline constexpr auto Run() -> void {
|
inline constexpr auto Run() -> void {
|
||||||
boost::asio::co_spawn(this->taskProcessor.ioContext, this->Task(), boost::asio::detached);
|
boost::asio::co_spawn(this->taskProcessor.ioContext, this->Task(), boost::asio::detached);
|
||||||
};
|
};
|
||||||
inline ~Server() {
|
inline ~Server() = default;
|
||||||
};
|
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
using AddHandler = Server<TPName, TaskProcessor, Ts..., Handler>;
|
using AddHandler = Server<TPName, TaskProcessor, Ts..., Handler>;
|
||||||
};
|
};
|
||||||
} // namespace cserver::server::server
|
} // namespace cserver::server::server
|
||||||
|
|
Loading…
Reference in a new issue