From 91171b8831920c3c10d8271df1c99391cbf49011 Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Mon, 23 Mar 2026 16:03:21 +0500 Subject: [PATCH 1/8] fix lint issues or result, add bool operator, fix const get value --- aether/types/result.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/aether/types/result.h b/aether/types/result.h index d3a01ca1..0dbafbc3 100644 --- a/aether/types/result.h +++ b/aether/types/result.h @@ -23,8 +23,6 @@ #include #include -#include "aether/meta/as_type.h" - namespace ae { template class Result; @@ -70,14 +68,17 @@ class Result { explicit Result(EU&& error) : storage_{std::forward(error)} {} // made implicit intentionally - Result(Ok&& ok) : storage_{std::move(ok.value)} {} + constexpr Result(Ok&& ok) // NOLINT(*explicit-constructor) + : storage_{std::move(ok).value} {} // made implicit intentionally - Result(Error&& error) : storage_{std::move(error.error)} {} - - // TODO: add monadic operations + constexpr Result(Error&& error) // NOLINT(*explicit-constructor) + : storage_{std::move(error).error} {} - bool IsOk() const noexcept { return storage_.index() == 0; } - bool IsErr() const noexcept { return storage_.index() == 1; } + constexpr bool IsOk() const noexcept { return storage_.index() == 0; } + constexpr bool IsErr() const noexcept { return storage_.index() == 1; } + constexpr explicit operator bool() const noexcept { + return storage_.index() == 0; + } auto& value() & noexcept { assert(IsOk()); @@ -159,9 +160,9 @@ class Result { private: value_type* get_value() & { return std::get_if<0>(&storage_); } - value_type* get_value() const& { return std::get_if<0>(&storage_); } + value_type const* get_value() const& { return std::get_if<0>(&storage_); } error_type* get_error() & { return std::get_if<1>(&storage_); } - error_type* get_error() const& { return std::get_if<1>(&storage_); } + error_type const* get_error() const& { return std::get_if<1>(&storage_); } std::variant storage_; }; From 0ef13dc40455af66c8c710ee221f86d13a032909 Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Mon, 23 Mar 2026 16:11:30 +0500 Subject: [PATCH 2/8] change api promise to simple object with SetValue and Subscribe methods --- aether/api_protocol/api_method.h | 46 ++++++------ aether/api_protocol/api_promise.h | 92 ++++++++++++++++++++++++ aether/api_protocol/api_promise_action.h | 84 ---------------------- aether/api_protocol/api_protocol.h | 2 +- 4 files changed, 116 insertions(+), 108 deletions(-) create mode 100644 aether/api_protocol/api_promise.h delete mode 100644 aether/api_protocol/api_promise_action.h diff --git a/aether/api_protocol/api_method.h b/aether/api_protocol/api_method.h index e60c94bc..6cf5f194 100644 --- a/aether/api_protocol/api_method.h +++ b/aether/api_protocol/api_method.h @@ -17,12 +17,11 @@ #ifndef AETHER_API_PROTOCOL_API_METHOD_H_ #define AETHER_API_PROTOCOL_API_METHOD_H_ -#include "aether/actions/action_context.h" #include "aether/api_protocol/api_message.h" #include "aether/api_protocol/api_context.h" #include "aether/api_protocol/api_pack_parser.h" #include "aether/api_protocol/protocol_context.h" -#include "aether/api_protocol/api_promise_action.h" +#include "aether/api_protocol/api_promise.h" namespace ae { class DefaultArgProc { @@ -74,39 +73,40 @@ struct Method { * return PromiseView for waiting the result or error. */ template -struct Method(Args...), ArgProc> { - explicit Method(ProtocolContext& protocol_context, - ActionContext action_context, ArgProc arg_proc = {}) - : protocol_context_{&protocol_context}, - action_context_{std::move(action_context)}, - arg_proc_{std::move(arg_proc)} {} +struct Method(Args...), ArgProc> { + explicit Method(ProtocolContext& protocol_context, ArgProc arg_proc = {}) + : protocol_context_{&protocol_context}, arg_proc_{std::move(arg_proc)} {} - ApiPromisePtr operator()(Args... args) { + ApiPromise& operator()(Args... args) { auto request_id = RequestId::GenRequestId(); auto* packet_stack = protocol_context_->packet_stack(); assert(packet_stack); packet_stack->Push(*this, arg_proc_(request_id, std::forward(args)...)); - - auto promise_ptr = ApiPromisePtr{action_context_, request_id}; + api_promise_.emplace(request_id); if constexpr (!std::is_same_v) { - protocol_context_->AddSendResultCallback( - request_id, - [p_ptr{promise_ptr}, context{protocol_context_}]() mutable { - p_ptr->SetValue(context->parser()->template Extract()); - }); + protocol_context_->AddSendResultCallback(request_id, [this]() { + assert(api_promise_); + api_promise_->SetValue( + protocol_context_->parser()->template Extract()); + api_promise_.reset(); + }); } else { - protocol_context_->AddSendResultCallback( - request_id, [p_ptr{promise_ptr}]() mutable { p_ptr->SetValue(); }); + protocol_context_->AddSendResultCallback(request_id, [this]() { + assert(api_promise_); + api_promise_->SetValue(); + api_promise_.reset(); + }); } protocol_context_->AddSendErrorCallback( - request_id, [p_ptr{promise_ptr}](auto, auto) mutable { - assert(p_ptr); - p_ptr->Reject(); + request_id, [this](auto, std::uint32_t err) { + assert(api_promise_); + api_promise_->SetError(std::move(err)); + api_promise_.reset(); }); - return promise_ptr; + return *api_promise_; } template @@ -116,7 +116,7 @@ struct Method(Args...), ArgProc> { private: ProtocolContext* protocol_context_; - ActionContext action_context_; + std::optional> api_promise_; ArgProc arg_proc_; }; diff --git a/aether/api_protocol/api_promise.h b/aether/api_protocol/api_promise.h new file mode 100644 index 00000000..bf672302 --- /dev/null +++ b/aether/api_protocol/api_promise.h @@ -0,0 +1,92 @@ +/* + * Copyright 2025 Aethernet Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AETHER_API_PROTOCOL_API_PROMISE_H_ +#define AETHER_API_PROTOCOL_API_PROMISE_H_ + +#include + +#include "aether/types/result.h" +#include "aether/events/events.h" +#include "aether/api_protocol/request_id.h" + +namespace ae { +namespace api_promise_action_internal { +struct Empty {}; +}; // namespace api_promise_action_internal + +template +class ApiPromise { + public: + using value_type = Value; + using error_type = Error; + using result_type = Result; + + constexpr explicit ApiPromise(RequestId req_id) noexcept + : request_id_{req_id} {} + + constexpr void SetValue(value_type&& val) noexcept { + event_.Emit(result_type{Ok{std::move(val)}}); + } + + constexpr void SetError(error_type&& err) noexcept { + event_.Emit(result_type{Error{std::move(err)}}); + } + + constexpr RequestId request_id() const { return request_id_; } + + template + constexpr decltype(auto) Subscribe(Fn&& fn) noexcept { + return EventSubscriber{event_}.Subscribe(std::forward(fn)); + } + + private: + RequestId request_id_; + Event event_; +}; + +template +class ApiPromise { + public: + using value_type = api_promise_action_internal::Empty; + using error_type = Error; + using result_type = Result; + + constexpr explicit ApiPromise(RequestId req_id) noexcept + : request_id_{req_id} {} + + constexpr void SetValue() noexcept { + event_.Emit(result_type{api_promise_action_internal::Empty{}}); + } + + constexpr void SetError(error_type&& err) noexcept { + event_.Emit(result_type{Error{std::move(err)}}); + } + + constexpr RequestId request_id() const { return request_id_; } + + template + [[nodiscard]] constexpr decltype(auto) Subscribe(Fn&& fn) noexcept { + return EventSubscriber{event_}.Subscribe(std::forward(fn)); + } + + private: + RequestId request_id_; + Event event_; +}; + +} // namespace ae +#endif // AETHER_API_PROTOCOL_API_PROMISE_H_ diff --git a/aether/api_protocol/api_promise_action.h b/aether/api_protocol/api_promise_action.h deleted file mode 100644 index fafcd0ef..00000000 --- a/aether/api_protocol/api_promise_action.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2025 Aethernet Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AETHER_API_PROTOCOL_API_PROMISE_ACTION_H_ -#define AETHER_API_PROTOCOL_API_PROMISE_ACTION_H_ - -#include "aether/actions/action_ptr.h" -#include "aether/actions/promise_action.h" -#include "aether/actions/action_context.h" - -#include "aether/api_protocol/request_id.h" - -namespace ae { -template -class ApiPromiseAction : public Action> { - public: - using BaseAction = Action>; - - ApiPromiseAction(ActionContext action_context, RequestId req_id) - : BaseAction{action_context}, - promise_{action_context}, - request_id_{req_id} {} - - AE_CLASS_MOVE_ONLY(ApiPromiseAction); - - UpdateStatus Update() { return promise_.Update(); } - - RequestId const& request_id() const { return request_id_; } - - void SetValue(TValue&& value) { promise_.SetValue(std::move(value)); } - - void Reject() { promise_.Reject(); } - - TValue& value() { return promise_.value(); } - - TValue const& value() const { return promise_.value(); } - - private: - PromiseAction promise_; - RequestId request_id_; -}; - -template <> -class ApiPromiseAction : public Action> { - public: - using BaseAction = Action>; - - ApiPromiseAction(ActionContext action_context, RequestId req_id) - : BaseAction{action_context}, - promise_{action_context}, - request_id_{req_id} {} - - AE_CLASS_MOVE_ONLY(ApiPromiseAction); - - UpdateStatus Update() { return promise_.Update(); } - - RequestId const& request_id() const { return request_id_; } - - void SetValue() { promise_.SetValue(); } - - void Reject() { promise_.Reject(); } - - private: - PromiseAction promise_; - RequestId request_id_; -}; - -template -using ApiPromisePtr = ActionPtr>; -} // namespace ae -#endif // AETHER_API_PROTOCOL_API_PROMISE_ACTION_H_ diff --git a/aether/api_protocol/api_protocol.h b/aether/api_protocol/api_protocol.h index 434b3fed..55a21e83 100644 --- a/aether/api_protocol/api_protocol.h +++ b/aether/api_protocol/api_protocol.h @@ -27,7 +27,7 @@ #include "aether/api_protocol/api_class_impl.h" #include "aether/api_protocol/api_pack_parser.h" #include "aether/api_protocol/protocol_context.h" -#include "aether/api_protocol/api_promise_action.h" +#include "aether/api_protocol/api_promise.h" #include "aether/api_protocol/return_result_api.h" // IWYU pragma: end_exports From 5783d837870b0838758b9b5b7acce73e4c663d66 Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Mon, 23 Mar 2026 16:11:49 +0500 Subject: [PATCH 3/8] fix use new api promise --- .../check_access_for_send_message.cpp | 22 ++- aether/ae_actions/ping.cpp | 9 +- aether/ae_actions/time_sync.cpp | 8 +- .../api/global_reg_server_api.cpp | 5 +- .../registration/api/global_reg_server_api.h | 5 +- .../api/registration_root_api.cpp | 6 +- .../registration/api/registration_root_api.h | 3 +- .../api/server_registration_api.cpp | 7 +- .../api/server_registration_api.h | 5 +- aether/registration/registration.cpp | 147 +++++++++--------- .../client_server_connection.cpp | 3 +- .../work_server_api/authorized_api.cpp | 7 +- .../work_server_api/authorized_api.h | 7 +- .../work_server_api/login_api.cpp | 5 +- .../work_server_api/login_api.h | 3 +- .../common/bandwidth_api.cpp | 9 +- .../common/bandwidth_api.h | 8 +- .../receiver/receiver.cpp | 2 +- .../send_messages_bandwidth/sender/sender.cpp | 47 +++--- tests/test-api-protocol/test-method-call.cpp | 30 ++-- 20 files changed, 165 insertions(+), 173 deletions(-) diff --git a/aether/ae_actions/check_access_for_send_message.cpp b/aether/ae_actions/check_access_for_send_message.cpp index bfaf3174..ec81dfac 100644 --- a/aether/ae_actions/check_access_for_send_message.cpp +++ b/aether/ae_actions/check_access_for_send_message.cpp @@ -30,19 +30,17 @@ CheckAccessForSendMessage::CheckAccessForSendMessage( action_context, AuthApiRequest{[this](ApiContext& auth_api, auto*, auto* request) { - auto check_promise = - auth_api->check_access_for_send_message(destination_); wait_check_sub_ = - check_promise->StatusEvent().Subscribe(ActionHandler{ - OnResult{[&]() { - ResponseReceived(); - request->Succeeded(); - }}, - OnError{[&]() { - ErrorReceived(); - request->Failed(); - }}, - }); + auth_api->check_access_for_send_message(destination_) + .Subscribe([&](auto const& res) { + if (res) { + ResponseReceived(); + request->Succeeded(); + } else { + ErrorReceived(); + request->Failed(); + } + }); }}, cloud_connection, request_policy, diff --git a/aether/ae_actions/ping.cpp b/aether/ae_actions/ping.cpp index 7c4ef6d2..e8832c91 100644 --- a/aether/ae_actions/ping.cpp +++ b/aether/ae_actions/ping.cpp @@ -71,7 +71,7 @@ void Ping::SendPing() { auto write_action = client_server_connection_->AuthorizedApiCall( SubApi{[this](ApiContext& auth_api) { - auto pong_promise = auth_api->ping(static_cast( + auto& pong_promise = auth_api->ping(static_cast( std::chrono::duration_cast( ping_interval_) .count())); @@ -85,11 +85,12 @@ void Ping::SendPing() { ping_requests_.push(PingRequest{ current_time, current_time + expected_ping_time, - pong_promise->request_id(), + pong_promise.request_id(), }); // Wait for response - wait_responses_.Push(pong_promise->StatusEvent().Subscribe(OnResult{ - [&](auto const& promise) { PingResponse(promise.request_id()); }})); + wait_responses_.Push( + pong_promise.Subscribe([&, req_id{pong_promise.request_id()}]( + auto&&) { PingResponse(req_id); })); }}); write_subscription_ = write_action->StatusEvent().Subscribe(OnError{[this]() { diff --git a/aether/ae_actions/time_sync.cpp b/aether/ae_actions/time_sync.cpp index 15fdb0cc..ffaa148e 100644 --- a/aether/ae_actions/time_sync.cpp +++ b/aether/ae_actions/time_sync.cpp @@ -143,16 +143,16 @@ class TimeSyncRequest : public Action { auto write_action = cc->LoginApiCall(SubApi{[this](auto& api) { AE_TELED_DEBUG("Make time sync request"); - ApiPromisePtr promise = api->get_time_utc(); - response_sub_ = promise->StatusEvent().Subscribe( - OnResult{[this, request_time{Now()}](auto& p) { + response_sub_ = api->get_time_utc().Subscribe( + [this, request_time{Now()}](auto const& p) { + assert(p.IsOk()); HandleResponse( std::chrono::milliseconds{ static_cast(p.value())}, request_time, Now()); // time synced state_ = State::kResult; - }}); + }); }}); write_action_sub_ = write_action->StatusEvent().Subscribe(OnError{[this]() { diff --git a/aether/registration/api/global_reg_server_api.cpp b/aether/registration/api/global_reg_server_api.cpp index 5e2cfce2..79a4859a 100644 --- a/aether/registration/api/global_reg_server_api.cpp +++ b/aether/registration/api/global_reg_server_api.cpp @@ -18,10 +18,9 @@ #if AE_SUPPORT_REGISTRATION namespace ae { -GlobalRegServerApi::GlobalRegServerApi(ProtocolContext& protocol_context, - ActionContext action_context) +GlobalRegServerApi::GlobalRegServerApi(ProtocolContext& protocol_context) : ApiClass{protocol_context}, set_master_key{protocol_context}, - finish{protocol_context, action_context} {} + finish{protocol_context} {} } // namespace ae #endif diff --git a/aether/registration/api/global_reg_server_api.h b/aether/registration/api/global_reg_server_api.h index a1f03d5f..718f948e 100644 --- a/aether/registration/api/global_reg_server_api.h +++ b/aether/registration/api/global_reg_server_api.h @@ -39,11 +39,10 @@ struct RegistrationResponse { class GlobalRegServerApi : public ApiClass { public: - GlobalRegServerApi(ProtocolContext& protocol_context, - ActionContext action_context); + explicit GlobalRegServerApi(ProtocolContext& protocol_context); Method<03, void(Key key)> set_master_key; - Method<04, ApiPromisePtr()> finish; + Method<04, ApiPromise()> finish; }; } // namespace ae diff --git a/aether/registration/api/registration_root_api.cpp b/aether/registration/api/registration_root_api.cpp index ebe4b716..b11cd545 100644 --- a/aether/registration/api/registration_root_api.cpp +++ b/aether/registration/api/registration_root_api.cpp @@ -19,15 +19,13 @@ #if AE_SUPPORT_REGISTRATION namespace ae { RegistrationRootApi::RegistrationRootApi(ProtocolContext& protocol_context, - ActionContext action_context, IEncryptProvider& root_encrypt, IEncryptProvider& global_encrypt) : ApiClass{protocol_context}, - get_asymmetric_public_key{protocol_context, action_context}, + get_asymmetric_public_key{protocol_context}, enter{protocol_context, EnterProc{*this}}, enc_provider_{&root_encrypt}, - server_registration_api_{protocol_context, action_context, - global_encrypt} {} + server_registration_api_{protocol_context, global_encrypt} {} DataBuffer RegistrationRootApi::Encrypt(DataBuffer const& data) const { return enc_provider_->Encrypt(data); diff --git a/aether/registration/api/registration_root_api.h b/aether/registration/api/registration_root_api.h index 289d5121..b541aae4 100644 --- a/aether/registration/api/registration_root_api.h +++ b/aether/registration/api/registration_root_api.h @@ -49,11 +49,10 @@ class RegistrationRootApi : public ApiClass { public: RegistrationRootApi(ProtocolContext& protocol_context, - ActionContext action_context, IEncryptProvider& root_encrypt, IEncryptProvider& global_encrypt); - Method<03, ApiPromisePtr(CryptoLib crypto_lib)> + Method<03, ApiPromise(CryptoLib crypto_lib)> get_asymmetric_public_key; Method<04, void(CryptoLib crypto_lib, SubApi sub_api), EnterProc> diff --git a/aether/registration/api/server_registration_api.cpp b/aether/registration/api/server_registration_api.cpp index fb89b7ef..e494d47d 100644 --- a/aether/registration/api/server_registration_api.cpp +++ b/aether/registration/api/server_registration_api.cpp @@ -20,15 +20,14 @@ namespace ae { ServerRegistrationApi::ServerRegistrationApi(ProtocolContext& protocol_context, - ActionContext action_context, IEncryptProvider& encrypt_provider) : ApiClass{protocol_context}, registration{protocol_context, RegistrationProc{*this}}, - request_proof_of_work_data{protocol_context, action_context}, - resolve_servers{protocol_context, action_context}, + request_proof_of_work_data{protocol_context}, + resolve_servers{protocol_context}, set_return_key{protocol_context}, encrypt_provider_{&encrypt_provider}, - global_reg_server_api_{protocol_context, action_context} {} + global_reg_server_api_{protocol_context} {} DataBuffer ServerRegistrationApi::Encrypt(DataBuffer const& data) const { return encrypt_provider_->Encrypt(data); diff --git a/aether/registration/api/server_registration_api.h b/aether/registration/api/server_registration_api.h index 0304f9d2..02e76e9c 100644 --- a/aether/registration/api/server_registration_api.h +++ b/aether/registration/api/server_registration_api.h @@ -70,7 +70,6 @@ class ServerRegistrationApi : public ApiClass { public: ServerRegistrationApi(ProtocolContext& protocol_context, - ActionContext action_context, IEncryptProvider& encrypt_provider); Method<3, @@ -80,10 +79,10 @@ class ServerRegistrationApi : public ApiClass { RegistrationProc> registration; - Method<4, ApiPromisePtr(Uid parent_id, PowMethod pow_method)> + Method<4, ApiPromise(Uid parent_id, PowMethod pow_method)> request_proof_of_work_data; - Method<5, ApiPromisePtr>( + Method<5, ApiPromise>( std::vector servers)> resolve_servers; diff --git a/aether/registration/registration.cpp b/aether/registration/registration.cpp index 7d9da8f6..028b7429 100644 --- a/aether/registration/registration.cpp +++ b/aether/registration/registration.cpp @@ -44,7 +44,7 @@ Registration::Registration(ActionContext action_context, Aether& aether, global_crypto_provider_{std::make_unique()}, client_root_api_{protocol_context_, *root_crypto_provider_->decryptor(), *global_crypto_provider_->decryptor()}, - server_reg_root_api_{protocol_context_, action_context_, + server_reg_root_api_{protocol_context_, *root_crypto_provider_->encryptor(), *global_crypto_provider_->encryptor()}, root_server_select_stream_{aether, reg_cloud}, @@ -144,24 +144,25 @@ void Registration::GetKeys() { auto api_call = ApiCallAdapter{ApiContext{server_reg_root_api_}, root_server_select_stream_}; - auto get_key_promise = + auto& get_key_promise = api_call->get_asymmetric_public_key(kDefaultCryptoLibProfile); - response_sub_ = get_key_promise->StatusEvent().Subscribe(ActionHandler{ - OnResult{[&](auto& promise) { - auto& signed_key = promise.value(); - auto r = CryptoSignVerify(signed_key.sign, signed_key.key, sign_pk_); - if (!r) { - AE_TELE_ERROR(RegisterGetKeysVerificationFailed, - "Sign verification failed"); - state_ = State::kRegistrationFailed; - return; - } - - server_pub_key_ = std::move(signed_key.key); - state_ = State::kGetPowParams; - }}, - OnError{[&]() { state_ = State::kRegistrationFailed; }}, + response_sub_ = get_key_promise.Subscribe([&](auto res) { + if (res.IsOk()) { + auto& signed_key = res.value(); + auto r = CryptoSignVerify(signed_key.sign, signed_key.key, sign_pk_); + if (!r) { + AE_TELE_ERROR(RegisterGetKeysVerificationFailed, + "Sign verification failed"); + state_ = State::kRegistrationFailed; + return; + } + + server_pub_key_ = std::move(signed_key.key); + state_ = State::kGetPowParams; + } else { + state_ = State::kRegistrationFailed; + } }); packet_write_action_ = api_call.Flush(); @@ -199,33 +200,36 @@ void Registration::RequestPowParams() { kDefaultCryptoLibProfile, SubApi{[this, &ret_key](ApiContext& server_api) { server_api->set_return_key(std::move(ret_key)); - auto pow_params_promise = server_api->request_proof_of_work_data( - parent_uid_, PowMethod::kBCryptCrc32); response_sub_ = - pow_params_promise->StatusEvent().Subscribe(ActionHandler{ - OnResult{[&](auto& promise) { - auto& pow_params = promise.value(); - [[maybe_unused]] auto res = - CryptoSignVerify(pow_params.global_key.sign, - pow_params.global_key.key, sign_pk_); - if (!res) { - AE_TELE_ERROR( - RegisterPowParamsVerificationFailed, - "Proof of work params sign verification failed"); + server_api + ->request_proof_of_work_data(parent_uid_, + PowMethod::kBCryptCrc32) + .Subscribe([&](auto&& res) { + if (res.IsOk()) { + auto& pow_params = res.value(); + [[maybe_unused]] auto res = + CryptoSignVerify(pow_params.global_key.sign, + pow_params.global_key.key, sign_pk_); + if (!res) { + AE_TELE_ERROR( + RegisterPowParamsVerificationFailed, + "Proof of work params sign verification failed"); + state_ = State::kRegistrationFailed; + return; + } + + aether_global_key_ = pow_params.global_key.key; + + pow_params_.salt = pow_params.salt; + pow_params_.max_hash_value = pow_params.max_hash_value; + pow_params_.password_suffix = pow_params.password_suffix; + pow_params_.pool_size = pow_params.pool_size; + + state_ = State::kMakeRegistration; + } else { state_ = State::kRegistrationFailed; - return; } - - aether_global_key_ = pow_params.global_key.key; - - pow_params_.salt = pow_params.salt; - pow_params_.max_hash_value = pow_params.max_hash_value; - pow_params_.password_suffix = pow_params.password_suffix; - pow_params_.pool_size = pow_params.pool_size; - - state_ = State::kMakeRegistration; - }}, - OnError{[&]() { state_ = State::kRegistrationFailed; }}}); + }); }}); packet_write_action_ = api_call.Flush(); @@ -265,27 +269,25 @@ void Registration::MakeRegistration() { SubApi{[this](ApiContext& global_api) { // set master key and wait for confirmation global_api->set_master_key(client_config_.master_key); - auto confirm_promise = global_api->finish(); - - response_sub_ = - confirm_promise->StatusEvent().Subscribe(ActionHandler{ - OnResult{[&](auto& promise) { - auto& reg_response = promise.value(); - AE_TELE_INFO(RegisterRegistrationConfirmed, - "Registration confirmed"); - - client_config_.uid = reg_response.uid; - client_config_.ephemeral_uid = - reg_response.ephemeral_uid; - client_config_.parent_uid = parent_uid_; - - // use client cloud_ for cloud resolve request - client_cloud_ = reg_response.cloud; - assert((client_cloud_.size() > 0) && - "Client's cloud is empty"); - state_ = State::kRequestCloudResolving; - }}, - OnError{[&]() { state_ = State::kRegistrationFailed; }}}); + response_sub_ = global_api->finish().Subscribe([&](auto res) { + if (res.IsOk()) { + auto& reg_response = res.value(); + AE_TELE_INFO(RegisterRegistrationConfirmed, + "Registration confirmed"); + + client_config_.uid = reg_response.uid; + client_config_.ephemeral_uid = reg_response.ephemeral_uid; + client_config_.parent_uid = parent_uid_; + + // use client cloud_ for cloud resolve request + client_cloud_ = reg_response.cloud; + assert((client_cloud_.size() > 0) && + "Client's cloud is empty"); + state_ = State::kRequestCloudResolving; + } else { + state_ = State::kRegistrationFailed; + } + }); }}); }}); @@ -303,16 +305,17 @@ void Registration::ResolveCloud() { auto api_call = ApiCallAdapter{ApiContext{server_reg_root_api_}, root_server_select_stream_}; - api_call->enter( - kDefaultCryptoLibProfile, - SubApi{[this](ApiContext& server_api) { - auto resolve_cloud_promise = server_api->resolve_servers(client_cloud_); - response_sub_ = - resolve_cloud_promise->StatusEvent().Subscribe(ActionHandler{ - OnResult{ - [&](auto& promise) { OnCloudResolved(promise.value()); }}, - OnError{[&]() { state_ = State::kRegistrationFailed; }}}); - }}); + api_call->enter(kDefaultCryptoLibProfile, + SubApi{[this](ApiContext& server_api) { + response_sub_ = server_api->resolve_servers(client_cloud_) + .Subscribe([&](auto&& res) { + if (res.IsOk()) { + OnCloudResolved(res.value()); + } else { + state_ = State::kRegistrationFailed; + } + }); + }}); packet_write_action_ = api_call.Flush(); diff --git a/aether/server_connections/client_server_connection.cpp b/aether/server_connections/client_server_connection.cpp index 343d94bc..fd16d2d5 100644 --- a/aether/server_connections/client_server_connection.cpp +++ b/aether/server_connections/client_server_connection.cpp @@ -102,8 +102,7 @@ ClientServerConnection::ClientServerConnection(AeContext const& ae_context, crypto_provider_{std::make_unique<_internal::ClientCryptoProvider>( client, server->server_id)}, client_api_unsafe_{protocol_context_, *crypto_provider_->decryptor()}, - login_api_{protocol_context_, ae_context_.aether(), - *crypto_provider_->encryptor()}, + login_api_{protocol_context_, *crypto_provider_->encryptor()}, server_connection_{ae_context_, server} { AE_TELED_DEBUG("Client server connection from {} to {}", ephemeral_uid_, server->server_id); diff --git a/aether/work_cloud_api/work_server_api/authorized_api.cpp b/aether/work_cloud_api/work_server_api/authorized_api.cpp index 5768be8a..2c35cd74 100644 --- a/aether/work_cloud_api/work_server_api/authorized_api.cpp +++ b/aether/work_cloud_api/work_server_api/authorized_api.cpp @@ -17,13 +17,12 @@ #include "aether/work_cloud_api/work_server_api/authorized_api.h" namespace ae { -AuthorizedApi::AuthorizedApi(ProtocolContext& protocol_context, - ActionContext action_context) +AuthorizedApi::AuthorizedApi(ProtocolContext& protocol_context) : ApiClass{protocol_context}, - ping{protocol_context, action_context}, + ping{protocol_context}, send_message{protocol_context}, send_messages{protocol_context}, - check_access_for_send_message{protocol_context, action_context}, + check_access_for_send_message{protocol_context}, resolver_servers{protocol_context}, resolver_clouds{protocol_context}, send_telemetry{protocol_context} {} diff --git a/aether/work_cloud_api/work_server_api/authorized_api.h b/aether/work_cloud_api/work_server_api/authorized_api.h index b7960f76..bd744377 100644 --- a/aether/work_cloud_api/work_server_api/authorized_api.h +++ b/aether/work_cloud_api/work_server_api/authorized_api.h @@ -30,13 +30,12 @@ namespace ae { class AuthorizedApi : public ApiClass { public: - AuthorizedApi(ProtocolContext& protocol_context, - ActionContext action_context); + explicit AuthorizedApi(ProtocolContext& protocol_context); - Method<4, ApiPromisePtr(std::uint64_t next_connect_ms_duration)> ping; + Method<4, ApiPromise(std::uint64_t next_connect_ms_duration)> ping; Method<6, void(AeMessage message)> send_message; Method<7, void(std::vector messages)> send_messages; - Method<11, ApiPromisePtr(Uid uid)> check_access_for_send_message; + Method<11, ApiPromise(Uid uid)> check_access_for_send_message; Method<12, void(std::vector sids)> resolver_servers; Method<13, void(std::vector uids)> resolver_clouds; diff --git a/aether/work_cloud_api/work_server_api/login_api.cpp b/aether/work_cloud_api/work_server_api/login_api.cpp index 8ba3c55b..ea60f705 100644 --- a/aether/work_cloud_api/work_server_api/login_api.cpp +++ b/aether/work_cloud_api/work_server_api/login_api.cpp @@ -20,14 +20,13 @@ namespace ae { LoginApi::LoginApi(ProtocolContext& protocol_context, - ActionContext action_context, IEncryptProvider& encrypt_provider) : ApiClass{protocol_context}, - get_time_utc{protocol_context, action_context}, + get_time_utc{protocol_context}, login_by_uid{protocol_context, LoginProc{*this}}, login_by_alias{protocol_context, LoginProc{*this}}, encrypt_provider_{&encrypt_provider}, - auth_api_{protocol_context, action_context} {} + auth_api_{protocol_context} {} DataBuffer LoginApi::Encrypt(DataBuffer const& data) { AE_TELED_DEBUG("Login api data {}", data); diff --git a/aether/work_cloud_api/work_server_api/login_api.h b/aether/work_cloud_api/work_server_api/login_api.h index ef1c79e2..2554705d 100644 --- a/aether/work_cloud_api/work_server_api/login_api.h +++ b/aether/work_cloud_api/work_server_api/login_api.h @@ -41,10 +41,9 @@ class LoginApi : public ApiClass { public: explicit LoginApi(ProtocolContext& protocol_context, - ActionContext action_context, IEncryptProvider& encrypt_provider); - Method<3, ApiPromisePtr()> get_time_utc; + Method<3, ApiPromise()> get_time_utc; Method<4, void(Uid uid, SubApi sub_api), LoginProc> login_by_uid; Method<5, void(Uid alias, SubApi sub_api), LoginProc> diff --git a/examples/benches/send_messages_bandwidth/common/bandwidth_api.cpp b/examples/benches/send_messages_bandwidth/common/bandwidth_api.cpp index ea4f504d..67abc320 100644 --- a/examples/benches/send_messages_bandwidth/common/bandwidth_api.cpp +++ b/examples/benches/send_messages_bandwidth/common/bandwidth_api.cpp @@ -17,12 +17,11 @@ #include "send_messages_bandwidth/common/bandwidth_api.h" namespace ae::bench { -BandwidthApi::BandwidthApi(ActionContext action_context, - ProtocolContext& protocol_context) +BandwidthApi::BandwidthApi(ProtocolContext& protocol_context) : ApiClassImpl{protocol_context}, - handshake{protocol_context, action_context}, - start_test{protocol_context, action_context}, - stop_test{protocol_context, action_context}, + handshake{protocol_context}, + start_test{protocol_context}, + stop_test{protocol_context}, message{protocol_context}, return_result{protocol_context} {} diff --git a/examples/benches/send_messages_bandwidth/common/bandwidth_api.h b/examples/benches/send_messages_bandwidth/common/bandwidth_api.h index dbb04161..3487285f 100644 --- a/examples/benches/send_messages_bandwidth/common/bandwidth_api.h +++ b/examples/benches/send_messages_bandwidth/common/bandwidth_api.h @@ -28,14 +28,14 @@ class BandwidthApi : public ApiClassImpl { public: using PayloadData = DataBuffer; - BandwidthApi(ActionContext action_context, ProtocolContext& protocol_context); + explicit BandwidthApi(ProtocolContext& protocol_context); // sender sends handshake until receiver doesn't answers true - Method<0x03, ApiPromisePtr()> handshake; + Method<0x03, ApiPromise()> handshake; // sender sends start or stop test and wait for receiver's response true to // continue/stop tests - Method<0x04, ApiPromisePtr()> start_test; - Method<0x05, ApiPromisePtr()> stop_test; + Method<0x04, ApiPromise()> start_test; + Method<0x05, ApiPromise()> stop_test; Method<0x06, void(std::uint16_t id, PayloadData data)> message; diff --git a/examples/benches/send_messages_bandwidth/receiver/receiver.cpp b/examples/benches/send_messages_bandwidth/receiver/receiver.cpp index 8071d170..72f652f1 100644 --- a/examples/benches/send_messages_bandwidth/receiver/receiver.cpp +++ b/examples/benches/send_messages_bandwidth/receiver/receiver.cpp @@ -25,7 +25,7 @@ namespace ae::bench { Receiver::Receiver(ActionContext action_context, Client::ptr client) : action_context_{action_context}, client_{std::move(client)}, - bandwidth_api_{action_context, protocol_context_} {} + bandwidth_api_{protocol_context_} {} EventSubscriber Receiver::error_event() { return error_event_; } diff --git a/examples/benches/send_messages_bandwidth/sender/sender.cpp b/examples/benches/send_messages_bandwidth/sender/sender.cpp index 928cad41..5f972473 100644 --- a/examples/benches/send_messages_bandwidth/sender/sender.cpp +++ b/examples/benches/send_messages_bandwidth/sender/sender.cpp @@ -28,7 +28,7 @@ Sender::Sender(ActionContext action_context, Client::ptr client, : action_context_{action_context}, client_{std::move(client)}, destination_{destination}, - bandwidth_api_{action_context_, protocol_context_} {} + bandwidth_api_{protocol_context_} {} EventSubscriber Sender::error_event() { return error_event_; } @@ -45,18 +45,17 @@ void Sender::Disconnect() { message_stream_.Reset(); } EventSubscriber Sender::Handshake() { auto api = ApiCallAdapter{ApiContext{bandwidth_api_}, *message_stream_}; - auto res = api->handshake(); - handshake_sub_ = - res->StatusEvent().Subscribe(OnResult{[this](auto const& promise) { - AE_TELED_DEBUG("Handshake received"); - if (promise.value()) { - handshake_made_.Emit(); - } else { - error_event_.Emit(); - } - }}); - - AE_TELED_DEBUG("Sending handshake request {}", res->request_id()); + auto& res = api->handshake(); + handshake_sub_ = res.Subscribe([this](auto const& res) { + AE_TELED_DEBUG("Handshake received"); + if (res && res.value()) { + handshake_made_.Emit(); + } else { + error_event_.Emit(); + } + }); + + AE_TELED_DEBUG("Sending handshake request {}", res.request_id()); api.Flush(); return handshake_made_; @@ -103,11 +102,12 @@ EventSubscriber Sender::StartTest() { AE_TELED_DEBUG("Sending start test request"); auto api = ApiCallAdapter{ApiContext{bandwidth_api_}, *message_stream_}; - auto res = api->start_test(); - sync_subs_.Push(res->StatusEvent().Subscribe(OnResult{[this]() { - start_test_action_->Stop(); - test_started_event_.Emit(); - }})); + sync_subs_ += api->start_test().Subscribe([this](auto const& res) { + if (res.IsOk()) { + start_test_action_->Stop(); + test_started_event_.Emit(); + } + }); api.Flush(); }, std::chrono::seconds{1}, 5}; @@ -125,11 +125,12 @@ EventSubscriber Sender::StopTest() { AE_TELED_DEBUG("Sending stop test request"); auto api = ApiCallAdapter{ApiContext{bandwidth_api_}, *message_stream_}; - auto res = api->stop_test(); - sync_subs_.Push(res->StatusEvent().Subscribe(OnResult{[this]() { - stop_test_action_->Stop(); - test_stopped_event_.Emit(); - }})); + sync_subs_ += api->stop_test().Subscribe([this](auto const& res) { + if (res.IsOk()) { + stop_test_action_->Stop(); + test_stopped_event_.Emit(); + } + }); api.Flush(); }, std::chrono::seconds{1}, 5}; diff --git a/tests/test-api-protocol/test-method-call.cpp b/tests/test-api-protocol/test-method-call.cpp index 86f464a1..952b3886 100644 --- a/tests/test-api-protocol/test-method-call.cpp +++ b/tests/test-api-protocol/test-method-call.cpp @@ -56,11 +56,11 @@ class ApiLevel0 : public ApiClassImpl { }; public: - ApiLevel0(ProtocolContext& protocol_context, ActionContext action_context) + explicit ApiLevel0(ProtocolContext& protocol_context) : ApiClassImpl{protocol_context}, api_level1{protocol_context}, method_3{protocol_context}, - method_4{protocol_context, action_context}, + method_4{protocol_context}, method_5{protocol_context, api_level1}, method_6{protocol_context, Method6Proc{api_level1}}, return_result_api{protocol_context} {} @@ -87,7 +87,7 @@ class ApiLevel0 : public ApiClassImpl { // call methods to make packet Method<03, void(int a, std::string b)> method_3; - Method<04, ApiPromisePtr(int a)> method_4; + Method<04, ApiPromise(int a)> method_4; Method<05, SubContext(int a)> method_5; Method<06, void(int a, SubApi sub), Method6Proc> method_6; @@ -102,7 +102,7 @@ void test_ApiMethodInvoke() { ActionProcessor ap; ProtocolContext pc; - auto api_level0 = ApiLevel0{pc, ActionContext{ap}}; + auto api_level0 = ApiLevel0{pc}; auto call_context = ApiContext{api_level0}; call_context->method_3(12, "asd"); @@ -139,17 +139,19 @@ void test_ReturnResult() { bool promise_get_value = false; - auto api_level0 = ApiLevel0{pc, ActionContext{ap}}; + auto api_level0 = ApiLevel0{pc}; auto call_context = ApiContext{api_level0}; - auto promise = call_context->method_4(42); - promise->StatusEvent().Subscribe( - ActionHandler{OnResult{[&](auto const& promise) { - auto value = promise.value(); - TEST_ASSERT_EQUAL(78, value); - promise_get_value = true; - }}, - OnError{[]() { TEST_FAIL(); }}}); + auto& promise = call_context->method_4(42); + promise.Subscribe([&](auto const& res) { + if (res.IsOk()) { + auto value = res.value(); + TEST_ASSERT_EQUAL(78, value); + promise_get_value = true; + } else { + TEST_FAIL(); + } + }); DataBuffer packet = std::move(call_context); @@ -182,7 +184,7 @@ void test_MethodWithSubApi() { ActionProcessor ap; ProtocolContext pc; - auto api_level0 = ApiLevel0{pc, ActionContext{ap}}; + auto api_level0 = ApiLevel0{pc}; auto call_context = ApiContext{api_level0}; call_context->method_6( From 1b3202d322f7407d0a9a4a6ee62b797d50c3cc7e Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Wed, 25 Mar 2026 21:39:56 +0500 Subject: [PATCH 4/8] temporary make create action both with ae_context and action_context --- aether/access_points/wifi_access_point.cpp | 2 +- aether/actions/action_ptr.h | 7 +++++++ aether/client.cpp | 2 +- aether/connection_manager/client_cloud_manager.cpp | 4 ++-- aether/uap/uap.cpp | 2 +- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/aether/access_points/wifi_access_point.cpp b/aether/access_points/wifi_access_point.cpp index dc3f9cd9..af98e6aa 100644 --- a/aether/access_points/wifi_access_point.cpp +++ b/aether/access_points/wifi_access_point.cpp @@ -118,7 +118,7 @@ ActionPtr WifiAccessPoint::Connect() { assert(driver.has_value()); connect_action_ = ActionPtr{ - *aether_.Load().as(), **driver, wifi_ap_, psp_, base_station_}; + ActionContext{*aether_.Load().as()}, **driver, wifi_ap_, psp_, base_station_}; connect_sub_ = connect_action_->FinishedEvent().Subscribe( [this]() { connect_action_.reset(); }); } diff --git a/aether/actions/action_ptr.h b/aether/actions/action_ptr.h index 7440f437..5d37d1c9 100644 --- a/aether/actions/action_ptr.h +++ b/aether/actions/action_ptr.h @@ -22,6 +22,7 @@ #include #include "aether/common.h" +#include "aether/ae_context.h" #include "aether/actions/action_context.h" namespace ae { @@ -50,6 +51,12 @@ class ActionPtr { action_context.get_registry().PushBack(ptr_); } + template + explicit ActionPtr(AeContext ae_context, TArgs&&... args) + : ptr_{std::make_shared(ae_context, + std::forward(args)...)} { + } + template ))> ActionPtr(ActionPtr const& other) : ptr_(other.ptr_) {} diff --git a/aether/client.cpp b/aether/client.cpp index 7327d436..7ca66229 100644 --- a/aether/client.cpp +++ b/aether/client.cpp @@ -76,7 +76,7 @@ CloudServerConnections& Client::cloud_connection() { #if AE_TELE_ENABLED // also create telemetry telemetry_ = - ActionPtr(*aether_.Load().as(), + ActionPtr(ActionContext{*aether_.Load().as()}, Aether::ptr{aether_}.Load(), *cloud_connection_); #endif } diff --git a/aether/connection_manager/client_cloud_manager.cpp b/aether/connection_manager/client_cloud_manager.cpp index e7d7b111..8f78faff 100644 --- a/aether/connection_manager/client_cloud_manager.cpp +++ b/aether/connection_manager/client_cloud_manager.cpp @@ -205,7 +205,7 @@ ActionPtr ClientCloudManager::GetCloud(Uid client_uid) { if (cached != cloud_cache_.end()) { assert(cached->second.is_valid()); return ActionPtr{ - *aether, cached->second}; + ActionContext{*aether}, cached->second}; } // get from aethernet @@ -213,7 +213,7 @@ ActionPtr ClientCloudManager::GetCloud(Uid client_uid) { assert(client); return ActionPtr{ - *aether, *aether, *this, client->cloud_connection(), client_uid}; + ActionContext{*aether}, *aether, *this, client->cloud_connection(), client_uid}; } Cloud::ptr ClientCloudManager::RegisterCloud(Uid uid, diff --git a/aether/uap/uap.cpp b/aether/uap/uap.cpp index 3311d9e3..0d188f60 100644 --- a/aether/uap/uap.cpp +++ b/aether/uap/uap.cpp @@ -174,7 +174,7 @@ void Uap::WindowWatcher() { } aether_.WithLoaded([this, w{current.window}](auto const& a) { - auto timer_action = ActionPtr{*a, w}; + auto timer_action = ActionPtr{ActionContext{*a}, w}; RegisterAction(*timer_action); }); } From 1dd3c3d9dd7cbb3cb5d3d398cbc46f1617981d03 Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Wed, 25 Mar 2026 21:40:15 +0500 Subject: [PATCH 5/8] add override for override func pattern and ignore_t as an empty type --- aether/meta/ignore_t.h | 37 +++++++++++++++++++++++++++++++++++++ aether/misc/override.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 aether/meta/ignore_t.h create mode 100644 aether/misc/override.h diff --git a/aether/meta/ignore_t.h b/aether/meta/ignore_t.h new file mode 100644 index 00000000..19c18b8a --- /dev/null +++ b/aether/meta/ignore_t.h @@ -0,0 +1,37 @@ +/* + * Copyright 2026 Aethernet Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AETHER_META_IGNORE_T_H_ +#define AETHER_META_IGNORE_T_H_ + +#include + +namespace ae { +struct Ignore { + template + constexpr explicit Ignore(Us&&...) noexcept {} +}; + +template +struct IsIgnore : std::false_type {}; + +template <> +struct IsIgnore : std::true_type {}; +template +static constexpr inline bool IsIgnore_v = IsIgnore::value; +} // namespace ae + +#endif // AETHER_META_IGNORE_T_H_ diff --git a/aether/misc/override.h b/aether/misc/override.h new file mode 100644 index 00000000..fbf30ab8 --- /dev/null +++ b/aether/misc/override.h @@ -0,0 +1,37 @@ +/* + * Copyright 2026 Aethernet Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AETHER_MISC_OVERRIDE_H_ +#define AETHER_MISC_OVERRIDE_H_ + +#include + +namespace ae { +/** + * \brief Functor overridable with many other functors. + * Has a cumulative operator() of all Fs functors. + */ +template +struct Override : Fs... { + explicit Override(Fs... funcs) : Fs{std::forward(funcs)}... {} + + using Fs::operator()...; +}; +template +Override(U&&...) -> Override; +} // namespace ae + +#endif // AETHER_MISC_OVERRIDE_H_ From 612e25564443308fc71b19a028128bdca09097d3 Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Wed, 25 Mar 2026 21:41:00 +0500 Subject: [PATCH 6/8] add with timer and make fixes to executors --- aether/executors/async_wait.h | 150 ++++++++++++++++++++++++---- aether/executors/executors.h | 3 +- aether/executors/for_range.h | 17 ++-- aether/executors/with_timeout.h | 169 ++++++++++++++++++++++++++++++++ 4 files changed, 313 insertions(+), 26 deletions(-) create mode 100644 aether/executors/with_timeout.h diff --git a/aether/executors/async_wait.h b/aether/executors/async_wait.h index 79237941..00d0e838 100644 --- a/aether/executors/async_wait.h +++ b/aether/executors/async_wait.h @@ -26,6 +26,7 @@ #include #include "aether/types/result.h" +#include "aether/meta/ignore_t.h" #include "aether/meta/type_list.h" #include "aether/executors/scheduler_on_tasks.h" @@ -34,6 +35,8 @@ namespace ae::ex { namespace async_wait_internal { +namespace { + template