mirror of
https://github.com/XRPLF/clio.git
synced 2026-07-23 15:10:23 +00:00
ci: Use Nix-based images for all workflows except pre-commit (#3098)
This commit is contained in:
@@ -3,21 +3,9 @@ add_executable(clio_server)
|
||||
target_sources(clio_server PRIVATE Main.cpp)
|
||||
target_link_libraries(clio_server PRIVATE clio_app)
|
||||
|
||||
if(static)
|
||||
if(san)
|
||||
message(FATAL_ERROR "Static linkage not allowed when using sanitizers")
|
||||
elseif(is_appleclang)
|
||||
message(FATAL_ERROR "Static linkage not supported on AppleClang")
|
||||
else()
|
||||
target_link_options(
|
||||
# Note: -static-libstdc++ can statically link both libstdc++ and libc++
|
||||
clio_server
|
||||
PRIVATE -static-libstdc++ -static-libgcc
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_target_properties(
|
||||
clio_server
|
||||
PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
patch_nix_binary(clio_server)
|
||||
|
||||
@@ -58,4 +58,4 @@ target_sources(
|
||||
handlers/VaultInfo.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(clio_rpc PRIVATE clio_util)
|
||||
target_link_libraries(clio_rpc PUBLIC clio_util clio_data)
|
||||
|
||||
@@ -45,7 +45,7 @@ target_sources(
|
||||
)
|
||||
|
||||
# This must be above the target_link_libraries call otherwise backtrace doesn't work
|
||||
if("${san}" STREQUAL "")
|
||||
if(NOT SANITIZERS_ENABLED)
|
||||
target_link_libraries(clio_util PUBLIC Boost::stacktrace_backtrace)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "util/async/AnyStopToken.hpp"
|
||||
#include "util/async/AnyStrand.hpp"
|
||||
#include "util/async/Concepts.hpp"
|
||||
#include "util/async/impl/Any.hpp"
|
||||
#include "util/async/impl/ErasedOperation.hpp"
|
||||
|
||||
#include <any>
|
||||
@@ -68,10 +69,10 @@ public:
|
||||
execute(SomeHandlerWithoutStopToken auto&& fn)
|
||||
{
|
||||
using RetType = std::decay_t<std::invoke_result_t<decltype(fn)>>;
|
||||
static_assert(not std::is_same_v<RetType, std::any>);
|
||||
static_assert(not std::is_same_v<RetType, impl::Any>);
|
||||
|
||||
return AnyOperation<RetType>(
|
||||
pimpl_->execute([fn = std::forward<decltype(fn)>(fn)] mutable -> std::any {
|
||||
pimpl_->execute([fn = std::forward<decltype(fn)>(fn)] mutable -> impl::Any {
|
||||
if constexpr (std::is_void_v<RetType>) {
|
||||
std::invoke(std::forward<decltype(fn)>(fn));
|
||||
return {};
|
||||
@@ -94,10 +95,10 @@ public:
|
||||
execute(SomeHandlerWith<AnyStopToken> auto&& fn)
|
||||
{
|
||||
using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
|
||||
static_assert(not std::is_same_v<RetType, std::any>);
|
||||
static_assert(not std::is_same_v<RetType, impl::Any>);
|
||||
|
||||
return AnyOperation<RetType>(pimpl_->execute(
|
||||
[fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
|
||||
[fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> impl::Any {
|
||||
if constexpr (std::is_void_v<RetType>) {
|
||||
std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
|
||||
return {};
|
||||
@@ -123,10 +124,10 @@ public:
|
||||
execute(SomeHandlerWith<AnyStopToken> auto&& fn, SomeStdDuration auto timeout)
|
||||
{
|
||||
using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
|
||||
static_assert(not std::is_same_v<RetType, std::any>);
|
||||
static_assert(not std::is_same_v<RetType, impl::Any>);
|
||||
|
||||
return AnyOperation<RetType>(pimpl_->execute(
|
||||
[fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
|
||||
[fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> impl::Any {
|
||||
if constexpr (std::is_void_v<RetType>) {
|
||||
std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
|
||||
return {};
|
||||
@@ -153,11 +154,11 @@ public:
|
||||
scheduleAfter(SomeStdDuration auto delay, SomeHandlerWith<AnyStopToken> auto&& fn)
|
||||
{
|
||||
using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
|
||||
static_assert(not std::is_same_v<RetType, std::any>);
|
||||
static_assert(not std::is_same_v<RetType, impl::Any>);
|
||||
|
||||
auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(delay);
|
||||
return AnyOperation<RetType>(pimpl_->scheduleAfter(
|
||||
millis, [fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
|
||||
millis, [fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> impl::Any {
|
||||
if constexpr (std::is_void_v<RetType>) {
|
||||
std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
|
||||
return {};
|
||||
@@ -184,13 +185,13 @@ public:
|
||||
scheduleAfter(SomeStdDuration auto delay, SomeHandlerWith<AnyStopToken, bool> auto&& fn)
|
||||
{
|
||||
using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken, bool>>;
|
||||
static_assert(not std::is_same_v<RetType, std::any>);
|
||||
static_assert(not std::is_same_v<RetType, impl::Any>);
|
||||
|
||||
auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(delay);
|
||||
return AnyOperation<RetType>(pimpl_->scheduleAfter(
|
||||
millis,
|
||||
[fn = std::forward<decltype(fn)>(fn)](auto stopToken, auto cancelled) mutable
|
||||
-> std::any {
|
||||
-> impl::Any {
|
||||
if constexpr (std::is_void_v<RetType>) {
|
||||
std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken), cancelled);
|
||||
return {};
|
||||
@@ -214,12 +215,12 @@ public:
|
||||
executeRepeatedly(SomeStdDuration auto interval, SomeHandlerWithoutStopToken auto&& fn)
|
||||
{
|
||||
using RetType = std::decay_t<std::invoke_result_t<decltype(fn)>>;
|
||||
static_assert(not std::is_same_v<RetType, std::any>);
|
||||
static_assert(not std::is_same_v<RetType, impl::Any>);
|
||||
|
||||
auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(interval);
|
||||
return AnyOperation<RetType>( //
|
||||
pimpl_->executeRepeatedly(
|
||||
millis, [fn = std::forward<decltype(fn)>(fn)] mutable -> std::any {
|
||||
millis, [fn = std::forward<decltype(fn)>(fn)] mutable -> impl::Any {
|
||||
std::invoke(std::forward<decltype(fn)>(fn));
|
||||
return {};
|
||||
}
|
||||
@@ -277,18 +278,18 @@ private:
|
||||
|
||||
virtual impl::ErasedOperation
|
||||
execute(
|
||||
std::function<std::any(AnyStopToken)>,
|
||||
std::function<impl::Any(AnyStopToken)>,
|
||||
std::optional<std::chrono::milliseconds> timeout = std::nullopt
|
||||
) = 0;
|
||||
virtual impl::ErasedOperation execute(std::function<std::any()>) = 0;
|
||||
virtual impl::ErasedOperation execute(std::function<impl::Any()>) = 0;
|
||||
virtual impl::ErasedOperation
|
||||
scheduleAfter(std::chrono::milliseconds, std::function<std::any(AnyStopToken)>) = 0;
|
||||
scheduleAfter(std::chrono::milliseconds, std::function<impl::Any(AnyStopToken)>) = 0;
|
||||
virtual impl::ErasedOperation scheduleAfter(
|
||||
std::chrono::milliseconds,
|
||||
std::function<std::any(AnyStopToken, bool)>
|
||||
std::function<impl::Any(AnyStopToken, bool)>
|
||||
) = 0;
|
||||
virtual impl::ErasedOperation
|
||||
executeRepeatedly(std::chrono::milliseconds, std::function<std::any()>) = 0;
|
||||
executeRepeatedly(std::chrono::milliseconds, std::function<impl::Any()>) = 0;
|
||||
virtual void submit(std::function<void()>) = 0;
|
||||
virtual AnyStrand
|
||||
makeStrand() = 0;
|
||||
@@ -309,7 +310,7 @@ private:
|
||||
|
||||
impl::ErasedOperation
|
||||
execute(
|
||||
std::function<std::any(AnyStopToken)> fn,
|
||||
std::function<impl::Any(AnyStopToken)> fn,
|
||||
std::optional<std::chrono::milliseconds> timeout
|
||||
) override
|
||||
{
|
||||
@@ -317,7 +318,7 @@ private:
|
||||
}
|
||||
|
||||
impl::ErasedOperation
|
||||
execute(std::function<std::any()> fn) override
|
||||
execute(std::function<impl::Any()> fn) override
|
||||
{
|
||||
return ctx.execute(std::move(fn));
|
||||
}
|
||||
@@ -325,7 +326,7 @@ private:
|
||||
impl::ErasedOperation
|
||||
scheduleAfter(
|
||||
std::chrono::milliseconds delay,
|
||||
std::function<std::any(AnyStopToken)> fn
|
||||
std::function<impl::Any(AnyStopToken)> fn
|
||||
) override
|
||||
{
|
||||
return ctx.scheduleAfter(delay, std::move(fn));
|
||||
@@ -334,14 +335,17 @@ private:
|
||||
impl::ErasedOperation
|
||||
scheduleAfter(
|
||||
std::chrono::milliseconds delay,
|
||||
std::function<std::any(AnyStopToken, bool)> fn
|
||||
std::function<impl::Any(AnyStopToken, bool)> fn
|
||||
) override
|
||||
{
|
||||
return ctx.scheduleAfter(delay, std::move(fn));
|
||||
}
|
||||
|
||||
impl::ErasedOperation
|
||||
executeRepeatedly(std::chrono::milliseconds interval, std::function<std::any()> fn) override
|
||||
executeRepeatedly(
|
||||
std::chrono::milliseconds interval,
|
||||
std::function<impl::Any()> fn
|
||||
) override
|
||||
{
|
||||
return ctx.executeRepeatedly(interval, std::move(fn));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/async/Error.hpp"
|
||||
#include "util/async/impl/Any.hpp"
|
||||
#include "util/async/impl/ErasedOperation.hpp"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "util/async/AnyOperation.hpp"
|
||||
#include "util/async/AnyStopToken.hpp"
|
||||
#include "util/async/Concepts.hpp"
|
||||
#include "util/async/impl/Any.hpp"
|
||||
#include "util/async/impl/ErasedOperation.hpp"
|
||||
|
||||
#include <any>
|
||||
@@ -46,10 +47,10 @@ public:
|
||||
execute(SomeHandlerWithoutStopToken auto&& fn)
|
||||
{
|
||||
using RetType = std::decay_t<std::invoke_result_t<decltype(fn)>>;
|
||||
static_assert(not std::is_same_v<RetType, std::any>);
|
||||
static_assert(not std::is_same_v<RetType, impl::Any>);
|
||||
|
||||
return AnyOperation<RetType>( //
|
||||
pimpl_->execute([fn = std::forward<decltype(fn)>(fn)] mutable -> std::any {
|
||||
pimpl_->execute([fn = std::forward<decltype(fn)>(fn)] mutable -> impl::Any {
|
||||
if constexpr (std::is_void_v<RetType>) {
|
||||
std::invoke(std::forward<decltype(fn)>(fn));
|
||||
return {};
|
||||
@@ -70,11 +71,11 @@ public:
|
||||
execute(SomeHandlerWith<AnyStopToken> auto&& fn)
|
||||
{
|
||||
using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
|
||||
static_assert(not std::is_same_v<RetType, std::any>);
|
||||
static_assert(not std::is_same_v<RetType, impl::Any>);
|
||||
|
||||
return AnyOperation<RetType>( //
|
||||
pimpl_->execute(
|
||||
[fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
|
||||
[fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> impl::Any {
|
||||
if constexpr (std::is_void_v<RetType>) {
|
||||
std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
|
||||
return {};
|
||||
@@ -99,11 +100,11 @@ public:
|
||||
execute(SomeHandlerWith<AnyStopToken> auto&& fn, SomeStdDuration auto timeout)
|
||||
{
|
||||
using RetType = std::decay_t<std::invoke_result_t<decltype(fn), AnyStopToken>>;
|
||||
static_assert(not std::is_same_v<RetType, std::any>);
|
||||
static_assert(not std::is_same_v<RetType, impl::Any>);
|
||||
|
||||
return AnyOperation<RetType>( //
|
||||
pimpl_->execute(
|
||||
[fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> std::any {
|
||||
[fn = std::forward<decltype(fn)>(fn)](auto stopToken) mutable -> impl::Any {
|
||||
if constexpr (std::is_void_v<RetType>) {
|
||||
std::invoke(std::forward<decltype(fn)>(fn), std::move(stopToken));
|
||||
return {};
|
||||
@@ -129,12 +130,12 @@ public:
|
||||
executeRepeatedly(SomeStdDuration auto interval, SomeHandlerWithoutStopToken auto&& fn)
|
||||
{
|
||||
using RetType = std::decay_t<std::invoke_result_t<decltype(fn)>>;
|
||||
static_assert(not std::is_same_v<RetType, std::any>);
|
||||
static_assert(not std::is_same_v<RetType, impl::Any>);
|
||||
|
||||
auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(interval);
|
||||
return AnyOperation<RetType>( //
|
||||
pimpl_->executeRepeatedly(
|
||||
millis, [fn = std::forward<decltype(fn)>(fn)] mutable -> std::any {
|
||||
millis, [fn = std::forward<decltype(fn)>(fn)] mutable -> impl::Any {
|
||||
std::invoke(std::forward<decltype(fn)>(fn));
|
||||
return {};
|
||||
}
|
||||
@@ -160,12 +161,12 @@ private:
|
||||
|
||||
[[nodiscard]] virtual impl::ErasedOperation
|
||||
execute(
|
||||
std::function<std::any(AnyStopToken)>,
|
||||
std::function<impl::Any(AnyStopToken)>,
|
||||
std::optional<std::chrono::milliseconds> timeout = std::nullopt
|
||||
) = 0;
|
||||
[[nodiscard]] virtual impl::ErasedOperation execute(std::function<std::any()>) = 0;
|
||||
[[nodiscard]] virtual impl::ErasedOperation execute(std::function<impl::Any()>) = 0;
|
||||
[[nodiscard]] virtual impl::ErasedOperation
|
||||
executeRepeatedly(std::chrono::milliseconds, std::function<std::any()>) = 0;
|
||||
executeRepeatedly(std::chrono::milliseconds, std::function<impl::Any()>) = 0;
|
||||
virtual void submit(std::function<void()>) = 0;
|
||||
};
|
||||
|
||||
@@ -181,7 +182,7 @@ private:
|
||||
|
||||
[[nodiscard]] impl::ErasedOperation
|
||||
execute(
|
||||
std::function<std::any(AnyStopToken)> fn,
|
||||
std::function<impl::Any(AnyStopToken)> fn,
|
||||
std::optional<std::chrono::milliseconds> timeout
|
||||
) override
|
||||
{
|
||||
@@ -189,13 +190,16 @@ private:
|
||||
}
|
||||
|
||||
[[nodiscard]] impl::ErasedOperation
|
||||
execute(std::function<std::any()> fn) override
|
||||
execute(std::function<impl::Any()> fn) override
|
||||
{
|
||||
return strand.execute(std::move(fn));
|
||||
}
|
||||
|
||||
impl::ErasedOperation
|
||||
executeRepeatedly(std::chrono::milliseconds interval, std::function<std::any()> fn) override
|
||||
executeRepeatedly(
|
||||
std::chrono::milliseconds interval,
|
||||
std::function<impl::Any()> fn
|
||||
) override
|
||||
{
|
||||
return strand.executeRepeatedly(interval, std::move(fn));
|
||||
}
|
||||
|
||||
@@ -6,11 +6,6 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
// for the static_assert at the bottom which fixes clang compilation:
|
||||
// see: https://godbolt.org/z/fzTjMd7G1 vs https://godbolt.org/z/jhKG7deen
|
||||
#include <any>
|
||||
#include <expected>
|
||||
|
||||
namespace util::async {
|
||||
|
||||
/**
|
||||
@@ -49,7 +44,4 @@ struct ExecutionError {
|
||||
std::string message;
|
||||
};
|
||||
|
||||
// these are not the droids you are looking for...
|
||||
static_assert(std::is_copy_constructible_v<std::expected<std::any, ExecutionError>>);
|
||||
|
||||
} // namespace util::async
|
||||
|
||||
41
src/util/async/impl/Any.hpp
Normal file
41
src/util/async/impl/Any.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <any>
|
||||
#include <type_traits>
|
||||
|
||||
namespace util::async::impl {
|
||||
|
||||
/**
|
||||
* @brief A wrapper for std::any used as the type-erased transport for async operation results.
|
||||
*
|
||||
* It exists to work around a recursive-constraint failure in libstdc++'s `<expected>` when the
|
||||
* value type is a raw `std::any`: `std::any`'s greedy templated constructor makes
|
||||
* `std::expected<std::any, E>` ask whether `std::any` is constructible from
|
||||
* `std::expected<std::any, E>`, which re-enters the same constraint. Newer Clang rejects this as
|
||||
* self-referential.
|
||||
*
|
||||
* `Any` only allows construction from `std::any` (never from an `expected`), which breaks the cycle
|
||||
* while still allowing transparent unwrapping back to `std::any&`.
|
||||
*/
|
||||
class Any {
|
||||
std::any value_;
|
||||
|
||||
public:
|
||||
Any() = default;
|
||||
Any(Any const&) = default;
|
||||
|
||||
Any(Any&&) = default;
|
||||
// note: this needs to be `auto` instead of `std::any` because of a bug in gcc 11.4
|
||||
Any(auto&& v)
|
||||
requires(std::is_same_v<std::decay_t<decltype(v)>, std::any>)
|
||||
: value_{std::forward<decltype(v)>(v)}
|
||||
{
|
||||
}
|
||||
|
||||
operator std::any&() noexcept
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace util::async::impl
|
||||
@@ -3,8 +3,8 @@
|
||||
#include "util/Assert.hpp"
|
||||
#include "util/async/Concepts.hpp"
|
||||
#include "util/async/Error.hpp"
|
||||
#include "util/async/impl/Any.hpp"
|
||||
|
||||
#include <any>
|
||||
#include <expected>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
pimpl_->wait();
|
||||
}
|
||||
|
||||
std::expected<std::any, ExecutionError>
|
||||
std::expected<Any, ExecutionError>
|
||||
get()
|
||||
{
|
||||
return pimpl_->get();
|
||||
@@ -64,7 +64,7 @@ private:
|
||||
|
||||
virtual void
|
||||
wait() noexcept = 0;
|
||||
virtual std::expected<std::any, ExecutionError>
|
||||
virtual std::expected<Any, ExecutionError>
|
||||
get() = 0;
|
||||
virtual void
|
||||
abort() = 0;
|
||||
@@ -93,14 +93,14 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
std::expected<std::any, ExecutionError>
|
||||
std::expected<Any, ExecutionError>
|
||||
get() override
|
||||
{
|
||||
if constexpr (not SomeOperationWithData<OpType>) {
|
||||
ASSERT(false, "Called get() on an operation that does not support it");
|
||||
std::unreachable();
|
||||
} else {
|
||||
// Note: return type of the operation was already wrapped to std::any by
|
||||
// Note: return type of the operation was already wrapped to impl::Any by
|
||||
// AnyExecutionContext
|
||||
return operation.get();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <expected>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
@@ -43,18 +44,36 @@ constexpr std::array kCertFilePaths{
|
||||
"/system/etc/security/cacerts", // Android
|
||||
};
|
||||
|
||||
std::optional<std::string>
|
||||
readCertificateFile(std::filesystem::path const& path)
|
||||
{
|
||||
if (not std::filesystem::exists(path)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::ifstream const fileStream{path, std::ios::in};
|
||||
if (not fileStream.is_open()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::stringstream buffer;
|
||||
buffer << fileStream.rdbuf();
|
||||
return std::move(buffer).str();
|
||||
}
|
||||
|
||||
std::expected<std::string, RequestError>
|
||||
getRootCertificate()
|
||||
{
|
||||
// Honor the OpenSSL-standard SSL_CERT_FILE environment variable first. Some
|
||||
// environments (e.g. the Nix-based CI/runtime image) point it at their CA
|
||||
// bundle instead of installing certificates at the well-known system paths.
|
||||
if (char const* const certFile = std::getenv("SSL_CERT_FILE"); certFile != nullptr) {
|
||||
if (auto contents = readCertificateFile(certFile); contents.has_value()) {
|
||||
return *std::move(contents);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& path : kCertFilePaths) {
|
||||
if (std::filesystem::exists(path)) {
|
||||
std::ifstream const fileStream{path, std::ios::in};
|
||||
if (not fileStream.is_open()) {
|
||||
continue;
|
||||
}
|
||||
std::stringstream buffer;
|
||||
buffer << fileStream.rdbuf();
|
||||
return std::move(buffer).str();
|
||||
if (auto contents = readCertificateFile(path); contents.has_value()) {
|
||||
return *std::move(contents);
|
||||
}
|
||||
}
|
||||
return std::unexpected{RequestError{"SSL setup failed: could not find root certificate"}};
|
||||
|
||||
Reference in New Issue
Block a user