From b38f42c6398a6041f420f80d962d68c8d7f92af4 Mon Sep 17 00:00:00 2001 From: Michael de Lang Date: Mon, 29 Apr 2024 10:52:45 +0200 Subject: [PATCH] With latest glaze, do not send optional values to Etcd anymore --- external/Catch2 | 2 +- external/glaze | 2 +- include/ichor/services/etcd/IEtcdV3.h | 68 +++-- src/services/etcd/EtcdV3Service.cpp | 347 +++++++++++++++++-------- test/TestServices/Etcdv3UsingService.h | 6 +- 5 files changed, 283 insertions(+), 142 deletions(-) diff --git a/external/Catch2 b/external/Catch2 index 05e10dfc..b5373dad 160000 --- a/external/Catch2 +++ b/external/Catch2 @@ -1 +1 @@ -Subproject commit 05e10dfccc28c7f973727c54f850237d07d5e10f +Subproject commit b5373dadca40b7edc8570cf9470b9b1cb1934d40 diff --git a/external/glaze b/external/glaze index 031db00e..957d39c3 160000 --- a/external/glaze +++ b/external/glaze @@ -1 +1 @@ -Subproject commit 031db00e852fb36e6a8f3125276860b890395fe1 +Subproject commit 957d39c3c5a0c9fa06128374080faeade0e0d470 diff --git a/include/ichor/services/etcd/IEtcdV3.h b/include/ichor/services/etcd/IEtcdV3.h index dffef868..15985e88 100644 --- a/include/ichor/services/etcd/IEtcdV3.h +++ b/include/ichor/services/etcd/IEtcdV3.h @@ -3,7 +3,6 @@ #include #include #include -#include // Glaze does not support tl::optional #include #include #include @@ -85,46 +84,45 @@ namespace Ichor::Etcd::v3 { struct EtcdRangeRequest final { std::string key; - std::optional range_end; - int64_t limit{}; - int64_t revision{}; - EtcdSortOrder sort_order{}; - EtcdSortTarget sort_target{}; - bool serializable{}; - bool keys_only{}; - bool count_only{}; - std::optional min_mod_revision; - std::optional max_mod_revision; - std::optional min_create_revision; - std::optional max_create_revision; + tl::optional range_end; + tl::optional limit{}; + tl::optional revision{}; + tl::optional sort_order{}; + tl::optional sort_target{}; + tl::optional serializable{}; + tl::optional keys_only{}; + tl::optional count_only{}; + tl::optional min_mod_revision; + tl::optional max_mod_revision; + tl::optional min_create_revision; + tl::optional max_create_revision; }; struct EtcdRangeResponse final { EtcdResponseHeader header; std::vector kvs; int64_t count{}; - bool more{}; + tl::optional more{}; }; struct EtcdPutRequest final { std::string key; std::string value; int64_t lease{}; - std::optional prev_kv; - std::optional ignore_value; - std::optional ignore_lease; + tl::optional prev_kv; + tl::optional ignore_value; + tl::optional ignore_lease; }; struct EtcdPutResponse final { EtcdResponseHeader header; - std::optional prev_kv; - + tl::optional prev_kv; }; struct EtcdDeleteRangeRequest final { std::string key; - std::optional range_end; - std::optional prev_kv; + tl::optional range_end; + tl::optional prev_kv; }; @@ -139,14 +137,14 @@ namespace Ichor::Etcd::v3 { EtcdCompareResult result{}; EtcdCompareTarget target{}; std::string key; - std::optional range_end; + tl::optional range_end; // one of: // { - std::optional version; - std::optional create_revision; - std::optional mod_revision; - std::optional value; - std::optional lease; + tl::optional version; + tl::optional create_revision; + tl::optional mod_revision; + tl::optional value; + tl::optional lease; // } }; @@ -168,20 +166,20 @@ namespace Ichor::Etcd::v3 { struct EtcdRequestOp final { // one of: // { - std::optional request_range; - std::optional request_put; - std::optional request_delete; - std::optional request_txn; + tl::optional request_range; + tl::optional request_put; + tl::optional request_delete; + tl::optional request_txn; // } }; struct EtcdResponseOp final { // one of: // { - std::optional response_range; - std::optional response_put; - std::optional response_delete_range; - std::optional response_txn; + tl::optional response_range; + tl::optional response_put; + tl::optional response_delete_range; + tl::optional response_txn; // } }; diff --git a/src/services/etcd/EtcdV3Service.cpp b/src/services/etcd/EtcdV3Service.cpp index ff277d58..2b915477 100644 --- a/src/services/etcd/EtcdV3Service.cpp +++ b/src/services/etcd/EtcdV3Service.cpp @@ -33,8 +33,138 @@ namespace { struct EtcdEnableAuthReply final { bool enabled; }; + + // treat a value as base64 + template + struct Base64StringType final { + static constexpr bool glaze_wrapper = true; + using value_type = T; + T& val; + }; + + // treat a value as an optional base64 + template + struct OptionalBase64StringType final { + static constexpr bool glaze_wrapper = true; + using value_type = T; + T& val; + }; +} + +namespace glz::detail { + template <> + struct from_json> { + template + static void op(tl::optional& value, auto&&... args) { + bool val; + read::op(val, args...); + value = val; + } + }; + + template <> + struct to_json> { + template + static void op(tl::optional const & value, auto&&... args) noexcept { + if(value) { + write::op(*value, args...); + } + } + }; + + template <> + struct from_json> { + template + static void op(tl::optional& value, auto&&... args) { + int64_t val; + read::op(val, args...); + value = val; + } + }; + + template <> + struct to_json> { + template + static void op(tl::optional const & value, auto&&... args) noexcept { + if(value) { + write::op(*value, args...); + } + } + }; + + template <> + struct from_json> { + template + static void op(tl::optional& value, auto&&... args) { + std::string val; + read::op(val, args...); + value = val; + } + }; + + template <> + struct to_json> { + template + static void op(tl::optional const & value, auto&&... args) noexcept { + if(value) { + write::op(*value, args...); + } + } + }; + + template + struct from_json> { + template + static void op(auto&& value, auto&&... args) { + read::op(value.val, args...); + value.val = base64_decode(value.val); + } + }; + + template + struct to_json> { + template + static void op(Base64StringType const & value, auto&&... args) noexcept { + write::op(base64_encode(reinterpret_cast(value.val.c_str()), value.val.size()), args...); + } + }; + + template + struct from_json> { + template + static void op(OptionalBase64StringType& value, auto&&... args) { + read::op(*value.val, args...); + value.val = base64_decode(*value.val); + } + }; + + template + struct to_json> { + template + static void op(OptionalBase64StringType const & value, auto&&... args) noexcept { + if(value.val) { + write::op(base64_encode(reinterpret_cast(value.val->c_str()), value.val->size()), args...); + } + } + }; + + template + inline constexpr decltype(auto) Base64StringImpl() noexcept { + return [](auto&& val) { return Base64StringType>{val.*MemPtr}; }; + } + + template + inline constexpr decltype(auto) OptionalBase64StringImpl() noexcept { + return [](auto&& val) { return OptionalBase64StringType>{val.*MemPtr}; }; + } } +template +constexpr auto Base64String = glz::detail::Base64StringImpl(); + +template +constexpr auto OptionalBase64String = glz::detail::OptionalBase64StringImpl(); + template <> struct glz::meta { using T = EtcdResponseHeader; @@ -48,23 +178,10 @@ struct glz::meta { template <> struct glz::meta { - static constexpr auto read_key = [](EtcdPutRequest &req, std::string const &s) { - req.key = base64_decode(s); - }; - static constexpr auto write_key = [](EtcdPutRequest const &req) -> std::string { - return base64_encode(reinterpret_cast(req.key.c_str()), req.key.size()); - }; - static constexpr auto read_value = [](EtcdPutRequest &req, std::string const &s) { - req.value = base64_decode(s); - }; - static constexpr auto write_value = [](EtcdPutRequest const &req) -> std::string { - return base64_encode(reinterpret_cast(req.value.c_str()), req.value.size()); - }; - using T = EtcdPutRequest; static constexpr auto value = object( - "key", custom, - "value", custom, + "key", Base64String<&T::key>, + "value", Base64String<&T::value>, "lease", quoted_num<&T::lease>, "prev_kv", &T::prev_kv, "ignore_value", &T::ignore_value, @@ -83,28 +200,10 @@ struct glz::meta { template <> struct glz::meta { - static constexpr auto read_key = [](EtcdRangeRequest &req, std::string const &s) { - req.key = base64_decode(s); - }; - static constexpr auto write_key = [](EtcdRangeRequest const &req) -> std::string { - return base64_encode(reinterpret_cast(req.key.c_str()), req.key.size()); - }; - static constexpr auto read_range_end = [](EtcdRangeRequest &req, std::optional const &s) { - if(s) { - req.range_end = base64_decode(*s); - } - }; - static constexpr auto write_range_end = [](EtcdRangeRequest const &req) -> std::optional { - if(!req.range_end) { - return std::nullopt; - } - return base64_encode(reinterpret_cast(req.range_end->c_str()), req.range_end->size()); - }; - using T = EtcdRangeRequest; static constexpr auto value = object( - "key", custom, - "range_end", custom, + "key", Base64String<&T::key>, + "range_end", OptionalBase64String<&T::range_end>, "limit", quoted_num<&T::limit>, "revision", quoted_num<&T::revision>, "sort_order", &T::sort_order, @@ -132,28 +231,10 @@ struct glz::meta { template <> struct glz::meta { - static constexpr auto read_key = [](EtcdDeleteRangeRequest &req, std::string const &s) { - req.key = base64_decode(s); - }; - static constexpr auto write_key = [](EtcdDeleteRangeRequest const &req) -> std::string { - return base64_encode(reinterpret_cast(req.key.c_str()), req.key.size()); - }; - static constexpr auto read_range_end = [](EtcdDeleteRangeRequest &req, std::optional const &s) { - if(s) { - req.range_end = base64_decode(*s); - } - }; - static constexpr auto write_range_end = [](EtcdDeleteRangeRequest const &req) -> std::optional { - if(!req.range_end) { - return std::nullopt; - } - return base64_encode(reinterpret_cast(req.range_end->c_str()), req.range_end->size()); - }; - using T = EtcdDeleteRangeRequest; static constexpr auto value = object( - "key", custom, - "range_end", custom, + "key", Base64String<&T::key>, + "range_end", OptionalBase64String<&T::range_end>, "prev_kv", &T::prev_kv ); }; @@ -177,23 +258,10 @@ struct glz::meta { template <> struct glz::meta { - static constexpr auto read_key = [](EtcdKeyValue &req, std::string const &s) { - req.key = base64_decode(s); - }; - static constexpr auto write_key = [](EtcdKeyValue const &req) -> std::string { - return base64_encode(reinterpret_cast(req.key.c_str()), req.key.size()); - }; - static constexpr auto read_value = [](EtcdKeyValue &req, std::string const &s) { - req.value = base64_decode(s); - }; - static constexpr auto write_value = [](EtcdKeyValue const &req) -> std::string { - return base64_encode(reinterpret_cast(req.value.c_str()), req.value.size()); - }; - using T = EtcdKeyValue; static constexpr auto value = object( - "key", custom, - "value", custom, + "key", Base64String<&T::key>, + "value", Base64String<&T::value>, "create_revision", quoted_num<&T::create_revision>, "mod_revision", quoted_num<&T::mod_revision>, "version", quoted_num<&T::version>, @@ -203,45 +271,16 @@ struct glz::meta { template <> struct glz::meta { - static constexpr auto read_key = [](EtcdCompare &req, std::string const &s) { - req.key = base64_decode(s); - }; - static constexpr auto write_key = [](EtcdCompare const &req) -> std::string { - return base64_encode(reinterpret_cast(req.key.c_str()), req.key.size()); - }; - static constexpr auto read_range_end = [](EtcdCompare &req, std::optional const &s) { - if(s) { - req.range_end = base64_decode(*s); - } - }; - static constexpr auto write_range_end = [](EtcdCompare const &req) -> std::optional { - if(!req.range_end) { - return std::nullopt; - } - return base64_encode(reinterpret_cast(req.range_end->c_str()), req.range_end->size()); - }; - static constexpr auto read_value = [](EtcdCompare &req, std::optional const &s) { - if(s) { - req.value = base64_decode(*s); - } - }; - static constexpr auto write_value = [](EtcdCompare const &req) -> std::optional { - if(!req.value) { - return std::nullopt; - } - return base64_encode(reinterpret_cast(req.value->c_str()), req.value->size()); - }; - using T = EtcdCompare; static constexpr auto value = object( "result", &T::result, "target", &T::target, - "key", custom, - "range_end", custom, + "key", Base64String<&T::key>, + "range_end", OptionalBase64String<&T::range_end>, "version", quoted_num<&T::version>, "create_revision", quoted_num<&T::create_revision>, "mod_revision", quoted_num<&T::mod_revision>, - "value", custom, + "value", OptionalBase64String<&T::value>, "lease", quoted_num<&T::lease> ); }; @@ -315,6 +354,110 @@ struct glz::meta { ); }; +namespace glz::detail { + template <> + struct from_json> { + template + static void op(tl::optional& value, auto&&... args) { + EtcdKeyValue val; + read::op(val, args...); + value = val; + } + }; + + template <> + struct to_json> { + template + static void op(tl::optional const & value, auto&&... args) noexcept { + if(value) { + write::op(*value, args...); + } + } + }; + + template <> + struct from_json> { + template + static void op(tl::optional& value, auto&&... args) { + fmt::print("EtcdRangeResponse read\n"); + EtcdRangeResponse val; + read::op(val, args...); + value = val; + } + }; + + template <> + struct to_json> { + template + static void op(tl::optional const & value, auto&&... args) noexcept { + fmt::print("EtcdRangeResponse write\n"); + if(value) { + write::op(*value, args...); + } + } + }; + + template <> + struct from_json> { + template + static void op(tl::optional& value, auto&&... args) { + EtcdPutResponse val; + read::op(val, args...); + value = val; + } + }; + + template <> + struct to_json> { + template + static void op(tl::optional const & value, auto&&... args) noexcept { + if(value) { + write::op(*value, args...); + } + } + }; + + template <> + struct from_json> { + template + static void op(tl::optional& value, auto&&... args) { + EtcdDeleteRangeResponse val; + read::op(val, args...); + value = val; + } + }; + + template <> + struct to_json> { + template + static void op(tl::optional const & value, auto&&... args) noexcept { + if(value) { + write::op(*value, args...); + } + } + }; + + template <> + struct from_json> { + template + static void op(tl::optional& value, auto&&... args) { + EtcdTxnResponse val; + read::op(val, args...); + value = val; + } + }; + + template <> + struct to_json> { + template + static void op(tl::optional const & value, auto&&... args) noexcept { + if(value) { + write::op(*value, args...); + } + } + }; +} + EtcdService::EtcdService(DependencyRegister ®, Properties props) : AdvancedService(std::move(props)) { reg.registerDependency(this, DependencyFlags::NONE, getProperties()); reg.registerDependency(this, DependencyFlags::REQUIRED | DependencyFlags::ALLOW_MULTIPLE, getProperties()); diff --git a/test/TestServices/Etcdv3UsingService.h b/test/TestServices/Etcdv3UsingService.h index cb3d028c..bda46d6a 100644 --- a/test/TestServices/Etcdv3UsingService.h +++ b/test/TestServices/Etcdv3UsingService.h @@ -39,7 +39,7 @@ namespace Ichor { Task put_get_delete_test() const { ICHOR_LOG_INFO(_logger, "running test"); int64_t revision{}; - Etcd::v3::EtcdPutRequest putReq{"v3_test_key", "test_value", 0, std::nullopt, std::nullopt, std::nullopt}; + Etcd::v3::EtcdPutRequest putReq{"v3_test_key", "test_value", 0, tl::nullopt, tl::nullopt, tl::nullopt}; auto putReply = co_await _etcd->put(putReq); if (!putReply) { @@ -84,7 +84,7 @@ namespace Ichor { Task txn_test() const { ICHOR_LOG_INFO(_logger, "running test"); int64_t revision{}; - Etcd::v3::EtcdPutRequest putReq{"v3_txn_key", "txn_value", 0, std::nullopt, std::nullopt, std::nullopt}; + Etcd::v3::EtcdPutRequest putReq{"v3_txn_key", "txn_value", 0, tl::nullopt, tl::nullopt, tl::nullopt}; auto putReply = co_await _etcd->put(putReq); if (!putReply) { @@ -105,7 +105,7 @@ namespace Ichor { Etcd::v3::EtcdTxnRequest txnReq{}; txnReq.compare.emplace_back(Etcd::v3::EtcdCompare{.target = Etcd::v3::EtcdCompareTarget::CREATE,.key = "v3_txn_key", .create_revision = revision}); txnReq.success.emplace_back(Etcd::v3::EtcdRequestOp{.request_range = Etcd::v3::EtcdRangeRequest{.key = "v3_txn_key"}}); - txnReq.failure.emplace_back(Etcd::v3::EtcdRequestOp{.request_range = Etcd::v3::EtcdRangeRequest{.key = "v3_txn_key"}}); + //txnReq.failure.emplace_back(Etcd::v3::EtcdRequestOp{.request_range = Etcd::v3::EtcdRangeRequest{.key = "v3_txn_key"}}); auto txnReply = co_await _etcd->txn(txnReq); if (!txnReply) { throw std::runtime_error("txn");