From d3e49b08e558d9b0b72e913a9263684827f38520 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Fri, 11 Apr 2025 13:55:28 -0700 Subject: [PATCH 01/56] Initial resolution attempt --- .builder/actions/sdk-ci-test.py | 21 +++++++++++++++++++ builder.json | 3 +++ .../aws/eventstreamrpc/EventStreamClient.h | 4 ++-- eventstream_rpc/source/EventStreamClient.cpp | 18 ++++++++-------- eventstream_rpc/tests/CMakeLists.txt | 6 +++--- 5 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 .builder/actions/sdk-ci-test.py diff --git a/.builder/actions/sdk-ci-test.py b/.builder/actions/sdk-ci-test.py new file mode 100644 index 000000000..fc95230ff --- /dev/null +++ b/.builder/actions/sdk-ci-test.py @@ -0,0 +1,21 @@ +import Builder + +class SdkCiTest(Builder.Action): + + def run(self, env): + + actions = [] + java_sdk_dir = None + + try: + java_sdk_dir = Builder.SetupEventStreamEchoServer().run(env) + Builder.SetupCrossCICrtEnvironment().run(env) + env.shell.exec(["make", "test"], check=True) + except: + print(f'Failure while running tests') + actions.append("exit 1") + finally: + if java_sdk_dir: + env.shell.rm(java_sdk_dir) + + return Builder.Script(actions, name='sdk-ci-test') diff --git a/builder.json b/builder.json index f1b1b3787..9a3423938 100644 --- a/builder.json +++ b/builder.json @@ -23,6 +23,9 @@ "build", "build-samples" ], + "test_steps": [ + "sdk-ci-test" + ], "variants" : { "skip_sample": { "!build_steps": [ diff --git a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h index 4b4904729..706b94fdf 100644 --- a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h +++ b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h @@ -717,8 +717,8 @@ namespace Aws std::mutex m_continuationMutex; bool m_resultReceived; std::promise m_initialResponsePromise; - std::atomic_int m_expectedCloses; - std::atomic_bool m_streamClosedCalled; + bool m_expectingClose; + bool m_streamClosedCalled; std::condition_variable m_closeReady; }; diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index d5e816702..ddf1d1c99 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -1134,7 +1134,7 @@ namespace Aws Crt::Allocator *allocator) noexcept : m_operationModelContext(operationModelContext), m_asyncLaunchMode(std::launch::deferred), m_messageCount(0), m_allocator(allocator), m_streamHandler(streamHandler), - m_clientContinuation(connection.NewStream(*this)), m_expectedCloses(0), m_streamClosedCalled(false) + m_clientContinuation(connection.NewStream(*this)), m_expectingClose(false), m_streamClosedCalled(false) { } @@ -1142,7 +1142,7 @@ namespace Aws { Close().wait(); std::unique_lock lock(m_continuationMutex); - m_closeReady.wait(lock, [this] { return m_expectedCloses.load() == 0; }); + m_closeReady.wait(lock, [this] { return m_expectingClose == false; }); } TaggedResult::TaggedResult(Crt::ScopedResource operationResponse) noexcept @@ -1390,7 +1390,7 @@ namespace Aws if (messageFlags & AWS_EVENT_STREAM_RPC_MESSAGE_FLAG_TERMINATE_STREAM) { const std::lock_guard lock(m_continuationMutex); - m_expectedCloses.fetch_add(1); + m_expectingClose = true; } m_messageCount += 1; @@ -1528,13 +1528,13 @@ namespace Aws m_resultReceived = true; } - if (m_expectedCloses.load() > 0) + if (m_expectingClose) { - m_expectedCloses.fetch_sub(1); - if (!m_streamClosedCalled.load() && m_streamHandler) + m_expectingClose = false; + if (!m_streamClosedCalled && m_streamHandler) { m_streamHandler->OnStreamClosed(); - m_streamClosedCalled.store(true); + m_streamClosedCalled = true; } m_closeReady.notify_one(); } @@ -1545,7 +1545,7 @@ namespace Aws std::future ClientOperation::Close(OnMessageFlushCallback onMessageFlushCallback) noexcept { const std::lock_guard lock(m_continuationMutex); - if (m_expectedCloses.load() > 0 || m_clientContinuation.IsClosed()) + if (m_expectingClose || m_clientContinuation.IsClosed()) { std::promise errorPromise; errorPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); @@ -1592,7 +1592,7 @@ namespace Aws } else { - m_expectedCloses.fetch_add(1); + m_expectingClose = true; return callbackContainer->onFlushPromise.get_future(); } diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index 53ac62dc1..f048ac8e0 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -32,9 +32,9 @@ set(TEST_BINARY_NAME ${PROJECT_NAME}-tests) add_test_case(OperateWhileDisconnected) # The tests below can be commented out when an EchoRPC Server is running on 127.0.0.1:8033 -#add_test_case(EventStreamConnect) -#add_test_case(EchoOperation) -#add_test_case(StressTestClient) +add_test_case(EventStreamConnect) +add_test_case(EchoOperation) +add_test_case(StressTestClient) generate_cpp_test_driver(${TEST_BINARY_NAME}) aws_add_sanitizers(${TEST_BINARY_NAME}) target_include_directories(${TEST_BINARY_NAME} PUBLIC From a99cd1e5e13d227ae13ebbe039a9eec766376f70 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Fri, 11 Apr 2025 14:24:21 -0700 Subject: [PATCH 02/56] Update --- .builder/actions/{sdk-ci-test.py => sdk-ci-test-setup.py} | 7 +++---- builder.json | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) rename .builder/actions/{sdk-ci-test.py => sdk-ci-test-setup.py} (65%) diff --git a/.builder/actions/sdk-ci-test.py b/.builder/actions/sdk-ci-test-setup.py similarity index 65% rename from .builder/actions/sdk-ci-test.py rename to .builder/actions/sdk-ci-test-setup.py index fc95230ff..a9aaf6dc1 100644 --- a/.builder/actions/sdk-ci-test.py +++ b/.builder/actions/sdk-ci-test-setup.py @@ -1,6 +1,6 @@ import Builder -class SdkCiTest(Builder.Action): +class SdkCiTestSetup(Builder.Action): def run(self, env): @@ -10,12 +10,11 @@ def run(self, env): try: java_sdk_dir = Builder.SetupEventStreamEchoServer().run(env) Builder.SetupCrossCICrtEnvironment().run(env) - env.shell.exec(["make", "test"], check=True) except: - print(f'Failure while running tests') + print(f'Failure while setting up tests') actions.append("exit 1") finally: if java_sdk_dir: env.shell.rm(java_sdk_dir) - return Builder.Script(actions, name='sdk-ci-test') + return Builder.Script(actions, name='sdk-ci-test-setup') diff --git a/builder.json b/builder.json index 9a3423938..4f1256ac0 100644 --- a/builder.json +++ b/builder.json @@ -24,7 +24,8 @@ "build-samples" ], "test_steps": [ - "sdk-ci-test" + "sdk-ci-test-setup", + "test" ], "variants" : { "skip_sample": { From 904651a180746df8e683b34c462ad7fba15c1263 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Mon, 14 Apr 2025 08:41:46 -0700 Subject: [PATCH 03/56] Testing --- .builder/actions/sdk-ci-test-setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.builder/actions/sdk-ci-test-setup.py b/.builder/actions/sdk-ci-test-setup.py index a9aaf6dc1..344815e13 100644 --- a/.builder/actions/sdk-ci-test-setup.py +++ b/.builder/actions/sdk-ci-test-setup.py @@ -13,8 +13,8 @@ def run(self, env): except: print(f'Failure while setting up tests') actions.append("exit 1") - finally: - if java_sdk_dir: - env.shell.rm(java_sdk_dir) + #finally: + # if java_sdk_dir: + # env.shell.rm(java_sdk_dir) return Builder.Script(actions, name='sdk-ci-test-setup') From bb948aacb169202e9efc9823991bf1d933f5bbb4 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Mon, 14 Apr 2025 10:52:54 -0700 Subject: [PATCH 04/56] Pre-format sync --- .builder/actions/sdk-ci-test-setup.py | 10 +-- .../tests/EventStreamClientTest.cpp | 75 ++++++++++++++++++- 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/.builder/actions/sdk-ci-test-setup.py b/.builder/actions/sdk-ci-test-setup.py index 344815e13..1ffbca9ef 100644 --- a/.builder/actions/sdk-ci-test-setup.py +++ b/.builder/actions/sdk-ci-test-setup.py @@ -10,11 +10,11 @@ def run(self, env): try: java_sdk_dir = Builder.SetupEventStreamEchoServer().run(env) Builder.SetupCrossCICrtEnvironment().run(env) - except: - print(f'Failure while setting up tests') + except Exception as ex: + print(f'Failure while setting up tests: {ex}') actions.append("exit 1") - #finally: - # if java_sdk_dir: - # env.shell.rm(java_sdk_dir) + finally: + if java_sdk_dir: + env.shell.rm(java_sdk_dir) return Builder.Script(actions, name='sdk-ci-test-setup') diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 232afc202..8ecbc0239 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -14,6 +14,7 @@ # undef GetMessage #endif +#include #include #include #include @@ -24,14 +25,45 @@ using namespace Awstest; struct EventStreamClientTestContext { + EventStreamClientTestContext(); + ~EventStreamClientTestContext(); + std::unique_ptr apiHandle; std::unique_ptr elGroup; std::unique_ptr resolver; std::unique_ptr clientBootstrap; + + Aws::Crt::String echoServerHostName; + uint16_t echoServerPort; + + struct aws_string *echoServerHostNameValue; + struct aws_string *echoServerPortValue; }; +EventStreamClientTestContext::EventStreamClientTestContext() : + echoServerPort(0), + echoServerHostNameValue(nullptr), + echoServerPortValue(nullptr) +{ +} + +EventStreamClientTestContext::~EventStreamClientTestContext() +{ + aws_string_destroy(echoServerHostNameValue); + aws_string_destroy(echoServerPortValue); +} + static EventStreamClientTestContext s_testContext; +static bool s_isEchoserverSetup(const EventStreamClientTestContext &context) +{ + return !context.echoServerHostName.empty() && context.echoServerPort > 0; +} + +AWS_STATIC_STRING_FROM_LITERAL(s_env_name_echo_server_host, "AWS_TEST_EVENT_STREAM_ECHO_SERVER_HOST"); +AWS_STATIC_STRING_FROM_LITERAL(s_env_name_echo_server_port, "AWS_TEST_EVENT_STREAM_ECHO_SERVER_PORT"); + + static int s_testSetup(struct aws_allocator *allocator, void *ctx) { auto *testContext = static_cast(ctx); @@ -43,6 +75,19 @@ static int s_testSetup(struct aws_allocator *allocator, void *ctx) testContext->clientBootstrap = std::unique_ptr( new Io::ClientBootstrap(*testContext->elGroup, *testContext->resolver, allocator)); + testContext->echoServerPort = 0; + testContext->echoServerHostName = ""; + + if (!aws_get_environment_value(allocator, s_env_name_echo_server_host, &testContext->echoServerHostNameValue) && testContext->echoServerHostNameValue != nullptr) + { + testContext->echoServerHostName = aws_string_c_str(testContext->echoServerHostNameValue); + } + + if (!aws_get_environment_value(allocator, s_env_name_echo_server_port, &testContext->echoServerPortValue) && testContext->echoServerPortValue != nullptr) + { + testContext->echoServerPort = static_cast(atoi(aws_string_c_str(testContext->echoServerPortValue))); + } + return AWS_ERROR_SUCCESS; } @@ -110,15 +155,21 @@ static void s_onMessageFlush(int errorCode) AWS_TEST_CASE_FIXTURE(EventStreamConnect, s_testSetup, s_TestEventStreamConnect, s_testTeardown, &s_testContext); static int s_TestEventStreamConnect(struct aws_allocator *allocator, void *ctx) { - auto *testContext = static_cast(ctx); + auto *testContext = static_cast(ctx); { + if (!s_isEchoserverSetup(*testContext)) + { + printf("Environment Variables are not set for the test, skip the test"); + return AWS_OP_SKIP; + } + MessageAmendment connectionAmendment; auto messageAmender = [&](void) -> const MessageAmendment & { return connectionAmendment; }; ConnectionConfig accessDeniedConfig; - accessDeniedConfig.SetHostName(Aws::Crt::String("127.0.0.1")); - accessDeniedConfig.SetPort(8033U); + accessDeniedConfig.SetHostName(testContext->echoServerHostName); + accessDeniedConfig.SetPort(testContext->echoServerPort); /* Happy path case. */ { @@ -173,6 +224,12 @@ static int s_TestOperationWhileDisconnected(struct aws_allocator *allocator, voi /* Don't connect at all and try running operations as normal. */ { + if (!s_isEchoserverSetup(*testContext)) + { + printf("Environment Variables are not set for the test, skip the test"); + return AWS_OP_SKIP; + } + ConnectionLifecycleHandler lifecycleHandler; Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); auto echoMessage = client.NewEchoMessage(); @@ -204,6 +261,12 @@ AWS_TEST_CASE_FIXTURE(EchoOperation, s_testSetup, s_TestEchoOperation, s_testTea static int s_TestEchoOperation(struct aws_allocator *allocator, void *ctx) { auto *testContext = static_cast(ctx); + if (!s_isEchoserverSetup(*testContext)) + { + printf("Environment Variables are not set for the test, skip the test"); + return AWS_OP_SKIP; + } + ConnectionLifecycleHandler lifecycleHandler; Aws::Crt::String expectedMessage("Async I0 FTW"); EchoMessageRequest echoMessageRequest; @@ -495,6 +558,12 @@ AWS_TEST_CASE_FIXTURE(StressTestClient, s_testSetup, s_TestStressClient, s_testT static int s_TestStressClient(struct aws_allocator *allocator, void *ctx) { auto *testContext = static_cast(ctx); + if (!s_isEchoserverSetup(*testContext)) + { + printf("Environment Variables are not set for the test, skip the test"); + return AWS_OP_SKIP; + } + ThreadPool threadPool; ConnectionLifecycleHandler lifecycleHandler; Aws::Crt::String expectedMessage("Async I0 FTW"); From 8403ed4bce32cb37969d8c336431b0b64c91d0d4 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Mon, 14 Apr 2025 10:53:28 -0700 Subject: [PATCH 05/56] Updated format script --- format-check.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ format-check.sh | 24 ------------------------ 2 files changed, 46 insertions(+), 24 deletions(-) create mode 100755 format-check.py delete mode 100755 format-check.sh diff --git a/format-check.py b/format-check.py new file mode 100755 index 000000000..e3c69fcd5 --- /dev/null +++ b/format-check.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +import argparse +import os +from pathlib import Path +import re +from subprocess import list2cmdline, run +from tempfile import NamedTemporaryFile + +CLANG_FORMAT_VERSION = '18.1.6' + +INCLUDE_REGEX = re.compile(r'^(include|source|tests)/.*\.(cpp|h)$') +EXCLUDE_REGEX = re.compile(r'^$') + +arg_parser = argparse.ArgumentParser(description="Check with clang-format") +arg_parser.add_argument('-i', '--inplace-edit', action='store_true', + help="Edit files inplace") +args = arg_parser.parse_args() + +os.chdir(Path(__file__).parent) + +# create file containing list of all files to format +filepaths_file = NamedTemporaryFile(delete=False) +for dirpath, dirnames, filenames in os.walk('.'): + for filename in filenames: + # our regexes expect filepath to use forward slash + filepath = Path(dirpath, filename).as_posix() + if not INCLUDE_REGEX.match(filepath): + continue + if EXCLUDE_REGEX.match(filepath): + continue + + filepaths_file.write(f"{filepath}\n".encode()) +filepaths_file.close() + +# use pipx to run clang-format from PyPI +# this is a simple way to run the same clang-format version regardless of OS +cmd = ['pipx', 'run', f'clang-format=={CLANG_FORMAT_VERSION}', + f'--files={filepaths_file.name}'] +if args.inplace_edit: + cmd += ['-i'] +else: + cmd += ['--Werror', '--dry-run'] + +print(f"{Path.cwd()}$ {list2cmdline(cmd)}") +if run(cmd).returncode: + exit(1) diff --git a/format-check.sh b/format-check.sh deleted file mode 100755 index 0899f8975..000000000 --- a/format-check.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -if [[ -z $CLANG_FORMAT ]] ; then - CLANG_FORMAT=clang-format -fi - -if NOT type $CLANG_FORMAT 2> /dev/null ; then - echo "No appropriate clang-format found." - exit 1 -fi - -FAIL=0 -SOURCE_FILES=`find deviceadvisor devicedefender discovery eventstream_rpc greengrass_ipc identity iotdevicecommon jobs shadow samples secure_tunneling -type f \( -name '*.h' -o -name '*.cpp' \)` -for i in $SOURCE_FILES -do - $CLANG_FORMAT -output-replacements-xml $i | grep -c " /dev/null - if [ $? -ne 1 ] - then - echo "$i failed clang-format check." - FAIL=1 - fi -done - -exit $FAIL From 1160d10e6cd93f93a8ccec210bdee6b8a1922159 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 15 Apr 2025 09:00:34 -0700 Subject: [PATCH 06/56] Update formatting to python-based with clang version control --- format-check.py | 33 ++-- .../source/IotSecureTunnelingClient.cpp | 27 ++-- secure_tunneling/source/SecureTunnel.cpp | 145 ++++++++++++++---- .../SubscribeToTunnelsNotifyRequest.cpp | 5 +- secure_tunneling/tests/main.cpp | 138 +++++++++-------- 5 files changed, 232 insertions(+), 116 deletions(-) diff --git a/format-check.py b/format-check.py index e3c69fcd5..b2678b8a4 100755 --- a/format-check.py +++ b/format-check.py @@ -8,7 +8,7 @@ CLANG_FORMAT_VERSION = '18.1.6' -INCLUDE_REGEX = re.compile(r'^(include|source|tests)/.*\.(cpp|h)$') +INCLUDE_REGEX = re.compile(r'.*(include|source|tests)/.*\.(cpp|h)$') EXCLUDE_REGEX = re.compile(r'^$') arg_parser = argparse.ArgumentParser(description="Check with clang-format") @@ -18,19 +18,24 @@ os.chdir(Path(__file__).parent) -# create file containing list of all files to format -filepaths_file = NamedTemporaryFile(delete=False) -for dirpath, dirnames, filenames in os.walk('.'): - for filename in filenames: - # our regexes expect filepath to use forward slash - filepath = Path(dirpath, filename).as_posix() - if not INCLUDE_REGEX.match(filepath): - continue - if EXCLUDE_REGEX.match(filepath): - continue - - filepaths_file.write(f"{filepath}\n".encode()) -filepaths_file.close() +check_dirs = ['deviceadvisor', 'devicedefender', 'discovery', 'eventstream_rpc', 'greengrass_ipc', 'identity', 'iotdevicecommon', 'jobs', 'shadow', 'samples', 'secure_tunneling'] + +for check_dir in check_dirs: + # create file containing list of all files to format + filepaths_file = NamedTemporaryFile(delete=False) + for dirpath, dirnames, filenames in os.walk(check_dir): + for filename in filenames: + + # our regexes expect filepath to use forward slash + filepath = Path(dirpath, filename).as_posix() + + if not INCLUDE_REGEX.match(filepath): + continue + if EXCLUDE_REGEX.match(filepath): + continue + + filepaths_file.write(f"{filepath}\n".encode()) + filepaths_file.close() # use pipx to run clang-format from PyPI # this is a simple way to run the same clang-format version regardless of OS diff --git a/secure_tunneling/source/IotSecureTunnelingClient.cpp b/secure_tunneling/source/IotSecureTunnelingClient.cpp index ec569de27..303294511 100644 --- a/secure_tunneling/source/IotSecureTunnelingClient.cpp +++ b/secure_tunneling/source/IotSecureTunnelingClient.cpp @@ -29,9 +29,15 @@ namespace Aws { } - IotSecureTunnelingClient::operator bool() const noexcept { return m_connection && *m_connection; } + IotSecureTunnelingClient::operator bool() const noexcept + { + return m_connection && *m_connection; + } - int IotSecureTunnelingClient::GetLastError() const noexcept { return aws_last_error(); } + int IotSecureTunnelingClient::GetLastError() const noexcept + { + return aws_last_error(); + } bool IotSecureTunnelingClient::SubscribeToTunnelsNotify( const Aws::Iotsecuretunneling::SubscribeToTunnelsNotifyRequest &request, @@ -45,7 +51,8 @@ namespace Aws uint16_t, const Aws::Crt::String &topic, Aws::Crt::Mqtt::QOS, - int errorCode) { + int errorCode) + { (void)topic; if (errorCode) { @@ -59,13 +66,13 @@ namespace Aws }; auto onSubscribePublish = - [handler]( - Aws::Crt::Mqtt::MqttConnection &, const Aws::Crt::String &, const Aws::Crt::ByteBuf &payload) { - Aws::Crt::String objectStr(reinterpret_cast(payload.buffer), payload.len); - Aws::Crt::JsonObject jsonObject(objectStr); - Aws::Iotsecuretunneling::SecureTunnelingNotifyResponse response(jsonObject); - handler(&response, AWS_ERROR_SUCCESS); - }; + [handler](Aws::Crt::Mqtt::MqttConnection &, const Aws::Crt::String &, const Aws::Crt::ByteBuf &payload) + { + Aws::Crt::String objectStr(reinterpret_cast(payload.buffer), payload.len); + Aws::Crt::JsonObject jsonObject(objectStr); + Aws::Iotsecuretunneling::SecureTunnelingNotifyResponse response(jsonObject); + handler(&response, AWS_ERROR_SUCCESS); + }; Aws::Crt::StringStream subscribeTopicSStr; subscribeTopicSStr << "$aws" diff --git a/secure_tunneling/source/SecureTunnel.cpp b/secure_tunneling/source/SecureTunnel.cpp index d2101bc94..c5f02267d 100644 --- a/secure_tunneling/source/SecureTunnel.cpp +++ b/secure_tunneling/source/SecureTunnel.cpp @@ -164,11 +164,20 @@ namespace Aws return true; } - const Crt::Optional &Message::getPayload() const noexcept { return m_payload; } + const Crt::Optional &Message::getPayload() const noexcept + { + return m_payload; + } - const Crt::Optional &Message::getServiceId() const noexcept { return m_serviceId; } + const Crt::Optional &Message::getServiceId() const noexcept + { + return m_serviceId; + } - const uint32_t &Message::getConnectionId() const noexcept { return m_connectionId; } + const uint32_t &Message::getConnectionId() const noexcept + { + return m_connectionId; + } Message::~Message() { @@ -193,9 +202,15 @@ namespace Aws m_messageType = aws_byte_cursor_from_buf(&m_messageTypeStorage); } - const Crt::ByteCursor &SendMessageCompleteData::getMessageType() const noexcept { return m_messageType; } + const Crt::ByteCursor &SendMessageCompleteData::getMessageType() const noexcept + { + return m_messageType; + } - SendMessageCompleteData::~SendMessageCompleteData() { aws_byte_buf_clean_up(&m_messageTypeStorage); } + SendMessageCompleteData::~SendMessageCompleteData() + { + aws_byte_buf_clean_up(&m_messageTypeStorage); + } //*********************************************************************************************************************** /* ConnectionData */ @@ -215,9 +230,18 @@ namespace Aws setPacketByteBufOptional(m_serviceId3, m_serviceId3Storage, m_allocator, connection.service_id_3); } - const Crt::Optional &ConnectionData::getServiceId1() const noexcept { return m_serviceId1; } - const Crt::Optional &ConnectionData::getServiceId2() const noexcept { return m_serviceId2; } - const Crt::Optional &ConnectionData::getServiceId3() const noexcept { return m_serviceId3; } + const Crt::Optional &ConnectionData::getServiceId1() const noexcept + { + return m_serviceId1; + } + const Crt::Optional &ConnectionData::getServiceId2() const noexcept + { + return m_serviceId2; + } + const Crt::Optional &ConnectionData::getServiceId3() const noexcept + { + return m_serviceId3; + } ConnectionData::~ConnectionData() { @@ -241,11 +265,20 @@ namespace Aws m_connectionId = message.connection_id; } - const Crt::Optional &StreamStartedData::getServiceId() const noexcept { return m_serviceId; } + const Crt::Optional &StreamStartedData::getServiceId() const noexcept + { + return m_serviceId; + } - const uint32_t &StreamStartedData::getConnectionId() const noexcept { return m_connectionId; } + const uint32_t &StreamStartedData::getConnectionId() const noexcept + { + return m_connectionId; + } - StreamStartedData::~StreamStartedData() { aws_byte_buf_clean_up(&m_serviceIdStorage); } + StreamStartedData::~StreamStartedData() + { + aws_byte_buf_clean_up(&m_serviceIdStorage); + } //*********************************************************************************************************************** /* StreamStoppedData */ @@ -261,9 +294,15 @@ namespace Aws setPacketByteBufOptional(m_serviceId, m_serviceIdStorage, m_allocator, message.service_id); } - const Crt::Optional &StreamStoppedData::getServiceId() const noexcept { return m_serviceId; } + const Crt::Optional &StreamStoppedData::getServiceId() const noexcept + { + return m_serviceId; + } - StreamStoppedData::~StreamStoppedData() { aws_byte_buf_clean_up(&m_serviceIdStorage); } + StreamStoppedData::~StreamStoppedData() + { + aws_byte_buf_clean_up(&m_serviceIdStorage); + } //*********************************************************************************************************************** /* ConnectionStartedData */ @@ -285,9 +324,15 @@ namespace Aws return m_serviceId; } - const uint32_t &ConnectionStartedData::getConnectionId() const noexcept { return m_connectionId; } + const uint32_t &ConnectionStartedData::getConnectionId() const noexcept + { + return m_connectionId; + } - ConnectionStartedData::~ConnectionStartedData() { aws_byte_buf_clean_up(&m_serviceIdStorage); } + ConnectionStartedData::~ConnectionStartedData() + { + aws_byte_buf_clean_up(&m_serviceIdStorage); + } //*********************************************************************************************************************** /* ConnectionResetData */ @@ -304,11 +349,20 @@ namespace Aws m_connectionId = message.connection_id; } - const Crt::Optional &ConnectionResetData::getServiceId() const noexcept { return m_serviceId; } + const Crt::Optional &ConnectionResetData::getServiceId() const noexcept + { + return m_serviceId; + } - const uint32_t &ConnectionResetData::getConnectionId() const noexcept { return m_connectionId; } + const uint32_t &ConnectionResetData::getConnectionId() const noexcept + { + return m_connectionId; + } - ConnectionResetData::~ConnectionResetData() { aws_byte_buf_clean_up(&m_serviceIdStorage); } + ConnectionResetData::~ConnectionResetData() + { + aws_byte_buf_clean_up(&m_serviceIdStorage); + } //*********************************************************************************************************************** /* SecureTunnelBuilder */ @@ -786,7 +840,10 @@ namespace Aws return *this; } - bool SecureTunnel::IsValid() { return m_secure_tunnel ? true : false; } + bool SecureTunnel::IsValid() + { + return m_secure_tunnel ? true : false; + } int SecureTunnel::Start() { @@ -797,13 +854,22 @@ namespace Aws return aws_secure_tunnel_start(m_secure_tunnel); } - int SecureTunnel::Stop() { return aws_secure_tunnel_stop(m_secure_tunnel); } + int SecureTunnel::Stop() + { + return aws_secure_tunnel_stop(m_secure_tunnel); + } /* Deprecated - Use Start() */ - int SecureTunnel::Connect() { return Start(); } + int SecureTunnel::Connect() + { + return Start(); + } /* Deprecated - Use Stop() */ - int SecureTunnel::Close() { return Stop(); } + int SecureTunnel::Close() + { + return Stop(); + } /* Deprecated - Use SendMessage() */ int SecureTunnel::SendData(const Crt::ByteCursor &data) @@ -825,9 +891,18 @@ namespace Aws return aws_secure_tunnel_send_message(m_secure_tunnel, &message); } - int SecureTunnel::SendStreamStart() { return SendStreamStart(""); } - int SecureTunnel::SendStreamStart(std::string serviceId) { return SendStreamStart(serviceId, 0); } - int SecureTunnel::SendStreamStart(Crt::ByteCursor serviceId) { return SendStreamStart(serviceId, 0); } + int SecureTunnel::SendStreamStart() + { + return SendStreamStart(""); + } + int SecureTunnel::SendStreamStart(std::string serviceId) + { + return SendStreamStart(serviceId, 0); + } + int SecureTunnel::SendStreamStart(Crt::ByteCursor serviceId) + { + return SendStreamStart(serviceId, 0); + } int SecureTunnel::SendStreamStart(std::string serviceId, uint32_t connectionId) { struct aws_byte_cursor service_id_cur; @@ -851,7 +926,10 @@ namespace Aws return aws_secure_tunnel_stream_start(m_secure_tunnel, &messageView); } - int SecureTunnel::SendConnectionStart(uint32_t connectionId) { return SendConnectionStart("", connectionId); } + int SecureTunnel::SendConnectionStart(uint32_t connectionId) + { + return SendConnectionStart("", connectionId); + } int SecureTunnel::SendConnectionStart(std::string serviceId, uint32_t connectionId) { @@ -873,9 +951,15 @@ namespace Aws return aws_secure_tunnel_connection_start(m_secure_tunnel, &messageView); } - int SecureTunnel::SendStreamReset() { return aws_secure_tunnel_stream_reset(m_secure_tunnel, NULL); } + int SecureTunnel::SendStreamReset() + { + return aws_secure_tunnel_stream_reset(m_secure_tunnel, NULL); + } - aws_secure_tunnel *SecureTunnel::GetUnderlyingHandle() { return m_secure_tunnel; } + aws_secure_tunnel *SecureTunnel::GetUnderlyingHandle() + { + return m_secure_tunnel; + } void SecureTunnel::s_OnConnectionComplete( const struct aws_secure_tunnel_connection_view *connection, @@ -1097,6 +1181,9 @@ namespace Aws } } - void SecureTunnel::Shutdown() { Stop(); } + void SecureTunnel::Shutdown() + { + Stop(); + } } // namespace Iotsecuretunneling } // namespace Aws diff --git a/secure_tunneling/source/SubscribeToTunnelsNotifyRequest.cpp b/secure_tunneling/source/SubscribeToTunnelsNotifyRequest.cpp index 62c9608c9..011a83de1 100644 --- a/secure_tunneling/source/SubscribeToTunnelsNotifyRequest.cpp +++ b/secure_tunneling/source/SubscribeToTunnelsNotifyRequest.cpp @@ -28,7 +28,10 @@ namespace Aws (void)doc; } - void SubscribeToTunnelsNotifyRequest::SerializeToObject(Aws::Crt::JsonObject &object) const { (void)object; } + void SubscribeToTunnelsNotifyRequest::SerializeToObject(Aws::Crt::JsonObject &object) const + { + (void)object; + } SubscribeToTunnelsNotifyRequest::SubscribeToTunnelsNotifyRequest(const Crt::JsonView &doc) { diff --git a/secure_tunneling/tests/main.cpp b/secure_tunneling/tests/main.cpp index bd6606e19..93427786d 100644 --- a/secure_tunneling/tests/main.cpp +++ b/secure_tunneling/tests/main.cpp @@ -99,7 +99,8 @@ int main(int argc, char *argv[]) } builderDestination.WithOnMessageReceived( - [&](SecureTunnel *secureTunnel, const MessageReceivedEventData &eventData) { + [&](SecureTunnel *secureTunnel, const MessageReceivedEventData &eventData) + { { (void)secureTunnel; (void)eventData; @@ -108,17 +109,20 @@ int main(int argc, char *argv[]) } }); - builderSource.WithOnMessageReceived([&](SecureTunnel *secureTunnel, const MessageReceivedEventData &eventData) { + builderSource.WithOnMessageReceived( + [&](SecureTunnel *secureTunnel, const MessageReceivedEventData &eventData) { - (void)secureTunnel; - (void)eventData; - fprintf(stdout, "Source Client Received Message\n"); - promiseSourceReceivedMessage.set_value(); - } - }); + { + (void)secureTunnel; + (void)eventData; + fprintf(stdout, "Source Client Received Message\n"); + promiseSourceReceivedMessage.set_value(); + } + }); builderDestination.WithOnSendMessageComplete( - [&](SecureTunnel *secureTunnel, int errorCode, const SendMessageCompleteEventData &eventData) { + [&](SecureTunnel *secureTunnel, int errorCode, const SendMessageCompleteEventData &eventData) + { (void)secureTunnel; (void)eventData; @@ -138,7 +142,8 @@ int main(int argc, char *argv[]) }); builderSource.WithOnSendMessageComplete( - [&](SecureTunnel *secureTunnel, int errorCode, const SendMessageCompleteEventData &eventData) { + [&](SecureTunnel *secureTunnel, int errorCode, const SendMessageCompleteEventData &eventData) + { (void)secureTunnel; (void)eventData; @@ -158,42 +163,46 @@ int main(int argc, char *argv[]) }); builderDestination.WithOnConnectionSuccess( - [&](SecureTunnel *secureTunnel, const ConnectionSuccessEventData &eventData) { + [&](SecureTunnel *secureTunnel, const ConnectionSuccessEventData &eventData) + { (void)secureTunnel; (void)eventData; fprintf(stdout, "Destination Client Connection Success\n"); promiseDestinationConnected.set_value(); }); - builderSource.WithOnConnectionSuccess([&](SecureTunnel *secureTunnel, const ConnectionSuccessEventData &eventData) { - (void)secureTunnel; - (void)eventData; + builderSource.WithOnConnectionSuccess( + [&](SecureTunnel *secureTunnel, const ConnectionSuccessEventData &eventData) + { + (void)secureTunnel; + (void)eventData; - fprintf(stdout, "Source Client Connection Success\n"); + fprintf(stdout, "Source Client Connection Success\n"); - /* Use a Multiplexing (Service Id) if available on this Secure Tunnel */ - if (eventData.connectionData->getServiceId1().has_value()) - { - /* Store the service id for future use */ - aws_byte_buf_clean_up(&m_serviceIdStorage); - AWS_ZERO_STRUCT(m_serviceIdStorage); - aws_byte_buf_init_copy_from_cursor( - &m_serviceIdStorage, allocator, eventData.connectionData->getServiceId1().value()); - m_serviceId = aws_byte_cursor_from_buf(&m_serviceIdStorage); - secureTunnel->SendStreamStart(m_serviceId.value(), connectionId); - fprintf(stdout, "Stream Start sent from Source Client.\n"); - } - else - { - fprintf(stdout, "Secure Tunnel should have service ids set for proper testing\n"); - exit(-1); - } + /* Use a Multiplexing (Service Id) if available on this Secure Tunnel */ + if (eventData.connectionData->getServiceId1().has_value()) + { + /* Store the service id for future use */ + aws_byte_buf_clean_up(&m_serviceIdStorage); + AWS_ZERO_STRUCT(m_serviceIdStorage); + aws_byte_buf_init_copy_from_cursor( + &m_serviceIdStorage, allocator, eventData.connectionData->getServiceId1().value()); + m_serviceId = aws_byte_cursor_from_buf(&m_serviceIdStorage); + secureTunnel->SendStreamStart(m_serviceId.value(), connectionId); + fprintf(stdout, "Stream Start sent from Source Client.\n"); + } + else + { + fprintf(stdout, "Secure Tunnel should have service ids set for proper testing\n"); + exit(-1); + } - promiseSourceConnected.set_value(); - }); + promiseSourceConnected.set_value(); + }); builderDestination.WithOnStreamStarted( - [&](SecureTunnel *secureTunnel, int errorCode, const StreamStartedEventData &eventData) { + [&](SecureTunnel *secureTunnel, int errorCode, const StreamStartedEventData &eventData) + { (void)secureTunnel; (void)eventData; if (!errorCode) @@ -209,39 +218,44 @@ int main(int argc, char *argv[]) } }); - builderDestination.WithOnConnectionStarted([&](SecureTunnel *secureTunnel, - int errorCode, - const ConnectionStartedEventData &eventData) { - (void)secureTunnel; - (void)eventData; - if (!errorCode) - { - fprintf(stdout, "Connection Started on Destination Client.\n"); - promiseDestinationConnectionStarted.set_value(); - } - else + builderDestination.WithOnConnectionStarted( + [&](SecureTunnel *secureTunnel, int errorCode, const ConnectionStartedEventData &eventData) { - fprintf(stdout, "Connection Start failed with error code %d(%s)\n", errorCode, ErrorDebugString(errorCode)); - aws_byte_buf_clean_up(&m_serviceIdStorage); - exit(-1); - } - }); + (void)secureTunnel; + (void)eventData; + if (!errorCode) + { + fprintf(stdout, "Connection Started on Destination Client.\n"); + promiseDestinationConnectionStarted.set_value(); + } + else + { + fprintf( + stdout, "Connection Start failed with error code %d(%s)\n", errorCode, ErrorDebugString(errorCode)); + aws_byte_buf_clean_up(&m_serviceIdStorage); + exit(-1); + } + }); builderDestination.WithOnConnectionShutdown([&]() { fprintf(stdout, "Destination Connection Shutdown\n"); }); builderSource.WithOnConnectionShutdown([&]() { fprintf(stdout, "Source Connection Shutdown\n"); }); - builderDestination.WithOnStopped([&](SecureTunnel *secureTunnel) { - (void)secureTunnel; - fprintf(stdout, "Destination entered Stopped State\n"); - promiseDestinationStopped.set_value(); - }); - - builderSource.WithOnStopped([&](SecureTunnel *secureTunnel) { - (void)secureTunnel; - fprintf(stdout, "Source has entered Stopped State\n"); - promiseSourceStopped.set_value(); - }); + builderDestination.WithOnStopped( + [&](SecureTunnel *secureTunnel) + { + (void)secureTunnel; + fprintf(stdout, "Destination entered Stopped State\n"); + promiseDestinationStopped.set_value(); + }); + + builderSource.WithOnStopped( + [&](SecureTunnel *secureTunnel) + { + (void)secureTunnel; + fprintf(stdout, "Source has entered Stopped State\n"); + promiseSourceStopped.set_value(); + }); /* Create Secure Tunnel using the options set with the builder */ std::shared_ptr secureTunnelDestination = builderDestination.Build(); From b4d3bcdf6613f1a4c380eb57e9d3dc1022644d81 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 15 Apr 2025 09:04:40 -0700 Subject: [PATCH 07/56] Update to builder version with eventstream server support --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3079dabea..571f33583 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: - 'docs' env: - BUILDER_VERSION: v0.9.56 + BUILDER_VERSION: v0.9.78 BUILDER_SOURCE: releases BUILDER_HOST: https://d19elf31gohf1l.cloudfront.net PACKAGE_NAME: aws-iot-device-sdk-cpp-v2 From 21abfcd25cc5fe91977b212c937a3c3518de22ef Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 15 Apr 2025 12:36:57 -0700 Subject: [PATCH 08/56] Credentials setup --- .github/workflows/ci.yml | 85 ++++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 571f33583..d61afd245 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: - 'docs' env: - BUILDER_VERSION: v0.9.78 + BUILDER_VERSION: v0.9.79 BUILDER_SOURCE: releases BUILDER_HOST: https://d19elf31gohf1l.cloudfront.net PACKAGE_NAME: aws-iot-device-sdk-cpp-v2 @@ -153,6 +153,11 @@ jobs: permissions: id-token: write # This is required for requesting the JWT steps: + - name: configure AWS credentials (containers) + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_IOT_CONTAINERS }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | md ${{ env.CI_FOLDER }} @@ -202,6 +207,11 @@ jobs: permissions: id-token: write # This is required for requesting the JWT steps: + - name: configure AWS credentials (containers) + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_IOT_CONTAINERS }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | md ${{ env.CI_FOLDER }} @@ -247,6 +257,11 @@ jobs: permissions: id-token: write # This is required for requesting the JWT steps: + - name: configure AWS credentials (containers) + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_IOT_CONTAINERS }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | md ${{ env.CI_FOLDER }} @@ -292,30 +307,40 @@ jobs: permissions: id-token: write # This is required for requesting the JWT steps: - - name: Build ${{ env.PACKAGE_NAME }} + consumers - run: | - md ${{ env.CI_FOLDER }} - cd ${{ env.CI_FOLDER }} - python -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz', 'builder.pyz')" - python builder.pyz build -p ${{ env.PACKAGE_NAME }} --cmake-extra=-DUSE_CPU_EXTENSIONS=OFF - - name: Running samples in CI setup - run: | - python -m pip install boto3 - - name: configure AWS credentials (CyclePubSub) - uses: aws-actions/configure-aws-credentials@v2 - with: - role-to-assume: ${{ env.CI_CYCLEPUBSUB_ROLE }} - aws-region: ${{ env.AWS_DEFAULT_REGION }} - - name: Run and check AppVerifier - run: | - cd ${{ env.CI_FOLDER }} - echo "Starting to run AppVerifier with cycle pub-sub sample" - python ${{ env.CI_UTILS_FOLDER }}/appverifier_launch_sample.py --sample_file ".\aws-iot-device-sdk-cpp-v2\build\samples\pub_sub\cycle_pub_sub\RelWithDebInfo\cycle-pub-sub.exe" --sample_secret_endpoint 'ci/endpoint' --sample_secret_certificate 'ci/CyclePubSub/cert' --sample_secret_private_key 'ci/CyclePubSub/key' + - name: configure AWS credentials (containers) + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_IOT_CONTAINERS }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: Build ${{ env.PACKAGE_NAME }} + consumers + run: | + md ${{ env.CI_FOLDER }} + cd ${{ env.CI_FOLDER }} + python -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz', 'builder.pyz')" + python builder.pyz build -p ${{ env.PACKAGE_NAME }} --cmake-extra=-DUSE_CPU_EXTENSIONS=OFF + - name: Running samples in CI setup + run: | + python -m pip install boto3 + - name: configure AWS credentials (CyclePubSub) + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_CYCLEPUBSUB_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: Run and check AppVerifier + run: | + cd ${{ env.CI_FOLDER }} + echo "Starting to run AppVerifier with cycle pub-sub sample" + python ${{ env.CI_UTILS_FOLDER }}/appverifier_launch_sample.py --sample_file ".\aws-iot-device-sdk-cpp-v2\build\samples\pub_sub\cycle_pub_sub\RelWithDebInfo\cycle-pub-sub.exe" --sample_secret_endpoint 'ci/endpoint' --sample_secret_certificate 'ci/CyclePubSub/cert' --sample_secret_private_key 'ci/CyclePubSub/key' windows-shared-lib: runs-on: windows-latest permissions: id-token: write # This is required for requesting the JWT steps: + - name: configure AWS credentials (containers) + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_IOT_CONTAINERS }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | md ${{ env.CI_FOLDER }} @@ -334,6 +359,11 @@ jobs: id-token: write # This is required for requesting the JWT security-events: write # This is required for pkcs12 sample to sign the key steps: + - name: configure AWS credentials (containers) + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_IOT_CONTAINERS }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz', 'builder')" @@ -398,6 +428,11 @@ jobs: permissions: id-token: write # This is required for requesting the JWT steps: + - name: configure AWS credentials (containers) + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_IOT_CONTAINERS }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | python -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder.pyz')" @@ -458,6 +493,11 @@ jobs: sudo apt install cmake gcc --version cmake --version + - name: configure AWS credentials (containers) + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_IOT_CONTAINERS }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | echo "Downloading source" @@ -694,6 +734,11 @@ jobs: permissions: id-token: write # This is required for requesting the JWT steps: + - name: configure AWS credentials (containers) + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ env.CI_IOT_CONTAINERS }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: Build ${{ env.PACKAGE_NAME }} + consumers run: | echo "Downloading source" From 4df20ffa02e970e079f17a011436189a09c32b3e Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 15 Apr 2025 12:58:36 -0700 Subject: [PATCH 09/56] Cleanup strings per fixture tear down --- eventstream_rpc/tests/EventStreamClientTest.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 8ecbc0239..5ff119f76 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -26,7 +26,6 @@ using namespace Awstest; struct EventStreamClientTestContext { EventStreamClientTestContext(); - ~EventStreamClientTestContext(); std::unique_ptr apiHandle; std::unique_ptr elGroup; @@ -47,12 +46,6 @@ EventStreamClientTestContext::EventStreamClientTestContext() : { } -EventStreamClientTestContext::~EventStreamClientTestContext() -{ - aws_string_destroy(echoServerHostNameValue); - aws_string_destroy(echoServerPortValue); -} - static EventStreamClientTestContext s_testContext; static bool s_isEchoserverSetup(const EventStreamClientTestContext &context) @@ -101,6 +94,12 @@ static int s_testTeardown(struct aws_allocator *allocator, int setup_result, voi /* The ApiHandle must be deallocated last or a deadlock occurs. */ testContext->apiHandle.reset(); + aws_string_destroy(testContext->echoServerHostNameValue); + testContext->echoServerHostNameValue = nullptr; + + aws_string_destroy(testContext->echoServerPortValue); + testContext->echoServerPortValue = nullptr; + return AWS_ERROR_SUCCESS; } From 6c0184c385bedf917793748193eb4a64ebfb2d18 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 15 Apr 2025 13:19:26 -0700 Subject: [PATCH 10/56] Try ubuntu 22 to see if maven is pre-installed --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d61afd245..faee4db88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -90,7 +90,7 @@ jobs: aws s3 cp s3://aws-crt-test-stuff/ci/${{ env.BUILDER_VERSION }}/linux-container-ci.sh ./linux-container-ci.sh && chmod a+x ./linux-container-ci.sh ./linux-container-ci.sh ${{ env.BUILDER_VERSION }} aws-crt-${{ matrix.image }} build -p ${{ env.PACKAGE_NAME }} linux-compiler-compat: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: matrix: compiler: From e6fbe72602280c42b0246fb15a970079ff432d8c Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Mon, 21 Apr 2025 14:28:54 -0700 Subject: [PATCH 11/56] No allocator exists during static initialization --- eventstream_rpc/tests/EventStreamClientTest.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 5ff119f76..15f52489c 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -32,7 +32,6 @@ struct EventStreamClientTestContext std::unique_ptr resolver; std::unique_ptr clientBootstrap; - Aws::Crt::String echoServerHostName; uint16_t echoServerPort; struct aws_string *echoServerHostNameValue; @@ -50,7 +49,7 @@ static EventStreamClientTestContext s_testContext; static bool s_isEchoserverSetup(const EventStreamClientTestContext &context) { - return !context.echoServerHostName.empty() && context.echoServerPort > 0; + return context.echoServerHostNameValue != nullptr && context.echoServerHostNameValue->len > 0 && context.echoServerPort > 0; } AWS_STATIC_STRING_FROM_LITERAL(s_env_name_echo_server_host, "AWS_TEST_EVENT_STREAM_ECHO_SERVER_HOST"); @@ -69,12 +68,8 @@ static int s_testSetup(struct aws_allocator *allocator, void *ctx) new Io::ClientBootstrap(*testContext->elGroup, *testContext->resolver, allocator)); testContext->echoServerPort = 0; - testContext->echoServerHostName = ""; - if (!aws_get_environment_value(allocator, s_env_name_echo_server_host, &testContext->echoServerHostNameValue) && testContext->echoServerHostNameValue != nullptr) - { - testContext->echoServerHostName = aws_string_c_str(testContext->echoServerHostNameValue); - } + aws_get_environment_value(allocator, s_env_name_echo_server_host, &testContext->echoServerHostNameValue); if (!aws_get_environment_value(allocator, s_env_name_echo_server_port, &testContext->echoServerPortValue) && testContext->echoServerPortValue != nullptr) { @@ -166,8 +161,9 @@ static int s_TestEventStreamConnect(struct aws_allocator *allocator, void *ctx) MessageAmendment connectionAmendment; auto messageAmender = [&](void) -> const MessageAmendment & { return connectionAmendment; }; + Aws::Crt::String hostname(aws_string_c_str(testContext->echoServerHostNameValue)); ConnectionConfig accessDeniedConfig; - accessDeniedConfig.SetHostName(testContext->echoServerHostName); + accessDeniedConfig.SetHostName(hostname); accessDeniedConfig.SetPort(testContext->echoServerPort); /* Happy path case. */ From 8f2417e42749c515479d4b9b950e5fa580640647 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 22 Apr 2025 13:54:29 -0700 Subject: [PATCH 12/56] Begin test rewrite; failures on other platforms should reveal other terminal status codes --- eventstream_rpc/tests/CMakeLists.txt | 13 +- .../tests/EventStreamClientTest.cpp | 346 ++++++++++++------ 2 files changed, 237 insertions(+), 122 deletions(-) diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index f048ac8e0..ddb0b2027 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -30,11 +30,16 @@ file(GLOB TESTS ${TEST_HDRS} ${TEST_SRC}) set(TEST_BINARY_NAME ${PROJECT_NAME}-tests) -add_test_case(OperateWhileDisconnected) +add_test_case(EventStreamConnectSuccess) +add_test_case(EventStreamConnectFailureNoAuthHeader) +add_test_case(EventStreamConnectFailureBadAuthHeader) +add_test_case(EchoClientConnectSuccess) + +#add_test_case(OperateWhileDisconnected) # The tests below can be commented out when an EchoRPC Server is running on 127.0.0.1:8033 -add_test_case(EventStreamConnect) -add_test_case(EchoOperation) -add_test_case(StressTestClient) +#add_test_case(EventStreamConnect) +#add_test_case(EchoOperation) +#add_test_case(StressTestClient) generate_cpp_test_driver(${TEST_BINARY_NAME}) aws_add_sanitizers(${TEST_BINARY_NAME}) target_include_directories(${TEST_BINARY_NAME} PUBLIC diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 15f52489c..6f2bf37f3 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -18,195 +18,304 @@ #include #include #include +#include using namespace Aws::Crt; using namespace Aws::Eventstreamrpc; using namespace Awstest; +AWS_STATIC_STRING_FROM_LITERAL(s_env_name_echo_server_host, "AWS_TEST_EVENT_STREAM_ECHO_SERVER_HOST"); +AWS_STATIC_STRING_FROM_LITERAL(s_env_name_echo_server_port, "AWS_TEST_EVENT_STREAM_ECHO_SERVER_PORT"); + struct EventStreamClientTestContext { - EventStreamClientTestContext(); + explicit EventStreamClientTestContext(struct aws_allocator *allocator); + ~EventStreamClientTestContext() = default; - std::unique_ptr apiHandle; - std::unique_ptr elGroup; - std::unique_ptr resolver; - std::unique_ptr clientBootstrap; + bool isValidEnvironment() const; - uint16_t echoServerPort; + std::shared_ptr elGroup; + std::shared_ptr resolver; + std::shared_ptr clientBootstrap; - struct aws_string *echoServerHostNameValue; - struct aws_string *echoServerPortValue; + uint16_t echoServerPort; + Aws::Crt::String echoServerHost; }; -EventStreamClientTestContext::EventStreamClientTestContext() : - echoServerPort(0), - echoServerHostNameValue(nullptr), - echoServerPortValue(nullptr) +EventStreamClientTestContext::EventStreamClientTestContext(struct aws_allocator *allocator) : + echoServerPort(0) { -} + elGroup = Aws::Crt::MakeShared(allocator, 0, allocator); + resolver = + Aws::Crt::MakeShared(allocator, *elGroup, 8, 30, allocator); + clientBootstrap = Aws::Crt::MakeShared( + allocator, *elGroup, *resolver, allocator); + + aws_string *host_env_value = nullptr; + aws_get_environment_value(allocator, s_env_name_echo_server_host, &host_env_value); + if (host_env_value) + { + echoServerHost = aws_string_c_str(host_env_value); + } -static EventStreamClientTestContext s_testContext; + struct aws_string *port_env_value = nullptr; + if (!aws_get_environment_value(allocator, s_env_name_echo_server_port, &port_env_value) && port_env_value != nullptr) + { + echoServerPort = static_cast(atoi(aws_string_c_str(port_env_value))); + } + + aws_string_destroy(host_env_value); + aws_string_destroy(port_env_value); +} -static bool s_isEchoserverSetup(const EventStreamClientTestContext &context) +bool EventStreamClientTestContext::isValidEnvironment() const { - return context.echoServerHostNameValue != nullptr && context.echoServerHostNameValue->len > 0 && context.echoServerPort > 0; + return !echoServerHost.empty() && echoServerPort > 0; } -AWS_STATIC_STRING_FROM_LITERAL(s_env_name_echo_server_host, "AWS_TEST_EVENT_STREAM_ECHO_SERVER_HOST"); -AWS_STATIC_STRING_FROM_LITERAL(s_env_name_echo_server_port, "AWS_TEST_EVENT_STREAM_ECHO_SERVER_PORT"); +class TestLifecycleHandler : public ConnectionLifecycleHandler +{ + public: + TestLifecycleHandler() : + isConnected(false), + disconnectCrtErrorCode(AWS_ERROR_SUCCESS), + disconnectRpcStatusCode(EVENT_STREAM_RPC_SUCCESS) + {} + void OnConnectCallback() override + { + std::lock_guard lockGuard(semaphoreLock); -static int s_testSetup(struct aws_allocator *allocator, void *ctx) -{ - auto *testContext = static_cast(ctx); + isConnected = true; + + semaphore.notify_one(); + } - testContext->apiHandle = std::unique_ptr(new ApiHandle(allocator)); - testContext->elGroup = std::unique_ptr(new Io::EventLoopGroup(0, allocator)); - testContext->resolver = - std::unique_ptr(new Io::DefaultHostResolver(*testContext->elGroup, 8, 30, allocator)); - testContext->clientBootstrap = std::unique_ptr( - new Io::ClientBootstrap(*testContext->elGroup, *testContext->resolver, allocator)); + void OnDisconnectCallback(RpcError error) override + { + std::lock_guard lockGuard(semaphoreLock); - testContext->echoServerPort = 0; + disconnectCrtErrorCode = error.crtError; + disconnectRpcStatusCode = error.baseStatus; - aws_get_environment_value(allocator, s_env_name_echo_server_host, &testContext->echoServerHostNameValue); + semaphore.notify_one(); + } - if (!aws_get_environment_value(allocator, s_env_name_echo_server_port, &testContext->echoServerPortValue) && testContext->echoServerPortValue != nullptr) + void WaitOnCondition(std::function condition) { - testContext->echoServerPort = static_cast(atoi(aws_string_c_str(testContext->echoServerPortValue))); + std::unique_lock semaphoreULock(semaphoreLock); + semaphore.wait(semaphoreULock, condition); } - return AWS_ERROR_SUCCESS; -} + private: -static int s_testTeardown(struct aws_allocator *allocator, int setup_result, void *ctx) + std::condition_variable semaphore; + std::mutex semaphoreLock; + + bool isConnected; + int disconnectCrtErrorCode; + EventStreamRpcStatusCode disconnectRpcStatusCode; +}; + +static int s_TestEventStreamConnectSuccess(struct aws_allocator *allocator, void *ctx) { - auto *testContext = static_cast(ctx); + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { + MessageAmendment connectionAmendment; + connectionAmendment.AddHeader(EventStreamHeader( + Aws::Crt::String("client-name"), Aws::Crt::String("accepted.testy_mc_testerson"), allocator)); - testContext->elGroup.reset(); - testContext->resolver.reset(); - testContext->clientBootstrap.reset(); - /* The ApiHandle must be deallocated last or a deadlock occurs. */ - testContext->apiHandle.reset(); + ConnectionConfig connectionConfig; + connectionConfig.SetHostName(testContext.echoServerHost); + connectionConfig.SetPort(testContext.echoServerPort); + connectionConfig.SetConnectAmendment(connectionAmendment); - aws_string_destroy(testContext->echoServerHostNameValue); - testContext->echoServerHostNameValue = nullptr; + TestLifecycleHandler lifecycleHandler; + ClientConnection connection(allocator); + auto future = connection.Connect(connectionConfig, &lifecycleHandler, *testContext.clientBootstrap); + EventStreamRpcStatusCode clientStatus = future.get().baseStatus; - aws_string_destroy(testContext->echoServerPortValue); - testContext->echoServerPortValue = nullptr; + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_SUCCESS, clientStatus); + } - return AWS_ERROR_SUCCESS; + return AWS_OP_SUCCESS; } -static int s_TestEventStreamConnect(struct aws_allocator *allocator, void *ctx); -static int s_TestEchoOperation(struct aws_allocator *allocator, void *ctx); -static int s_TestOperationWhileDisconnected(struct aws_allocator *allocator, void *ctx); +AWS_TEST_CASE(EventStreamConnectSuccess, s_TestEventStreamConnectSuccess); -class TestLifecycleHandler : public ConnectionLifecycleHandler +static int s_TestEventStreamConnectFailureNoAuthHeader(struct aws_allocator *allocator, void *ctx) { - public: - TestLifecycleHandler() + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) { - semaphoreULock = std::unique_lock(semaphoreLock); - isConnected = false; - lastErrorCode = AWS_OP_ERR; + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; } - void OnConnectCallback() override { - std::lock_guard lockGuard(semaphoreLock); + ConnectionConfig connectionConfig; + connectionConfig.SetHostName(testContext.echoServerHost); + connectionConfig.SetPort(testContext.echoServerPort); - isConnected = true; + TestLifecycleHandler lifecycleHandler; + ClientConnection connection(allocator); + auto future = connection.Connect(connectionConfig, &lifecycleHandler, *testContext.clientBootstrap); + EventStreamRpcStatusCode clientStatus = future.get().baseStatus; - semaphore.notify_one(); + // TOFIX: this isn't reliably true on Windows over TCP due to RSTs blocking final data reads + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, clientStatus); } - void OnDisconnectCallback(RpcError error) override + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(EventStreamConnectFailureNoAuthHeader, s_TestEventStreamConnectFailureNoAuthHeader); + +static int s_TestEventStreamConnectFailureBadAuthHeader(struct aws_allocator *allocator, void *ctx) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) { - std::lock_guard lockGuard(semaphoreLock); + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } - lastErrorCode = error.baseStatus; + { + MessageAmendment connectionAmendment; + connectionAmendment.AddHeader(EventStreamHeader( + Aws::Crt::String("client-name"), Aws::Crt::String("rejected.testy_mc_testerson"), allocator)); - semaphore.notify_one(); + ConnectionConfig connectionConfig; + connectionConfig.SetHostName(testContext.echoServerHost); + connectionConfig.SetPort(testContext.echoServerPort); + connectionConfig.SetConnectAmendment(connectionAmendment); + + TestLifecycleHandler lifecycleHandler; + ClientConnection connection(allocator); + auto future = connection.Connect(connectionConfig, &lifecycleHandler, *testContext.clientBootstrap); + EventStreamRpcStatusCode clientStatus = future.get().baseStatus; + + // TOFIX: this isn't reliably true on Windows over TCP due to RSTs blocking final data reads + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, clientStatus); } - void WaitOnCondition(std::function condition) { semaphore.wait(semaphoreULock, condition); } + return AWS_OP_SUCCESS; +} - private: - friend int s_TestEventStreamConnect(struct aws_allocator *allocator, void *ctx); - std::condition_variable semaphore; - std::mutex semaphoreLock; - std::unique_lock semaphoreULock; - int isConnected; - int lastErrorCode; -}; +AWS_TEST_CASE(EventStreamConnectFailureBadAuthHeader, s_TestEventStreamConnectFailureBadAuthHeader); -static void s_onMessageFlush(int errorCode) +static int s_TestEchoClientConnectSuccess(struct aws_allocator *allocator, void *ctx) { - (void)errorCode; + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { + ConnectionLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedStatus = client.Connect(lifecycleHandler); + EventStreamRpcStatusCode clientStatus = connectedStatus.get().baseStatus; + + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_SUCCESS, clientStatus); + client.Close(); + } + + return AWS_OP_SUCCESS; } -AWS_TEST_CASE_FIXTURE(EventStreamConnect, s_testSetup, s_TestEventStreamConnect, s_testTeardown, &s_testContext); +AWS_TEST_CASE(EchoClientConnectSuccess, s_TestEchoClientConnectSuccess); + +#ifdef NEVER + static int s_TestEventStreamConnect(struct aws_allocator *allocator, void *ctx) { - auto *testContext = static_cast(ctx); + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext; + s_testSetup(allocator, testContext); + if (!testContext.hasTestEnvironment()) { - if (!s_isEchoserverSetup(*testContext)) - { - printf("Environment Variables are not set for the test, skip the test"); - return AWS_OP_SKIP; - } + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } - MessageAmendment connectionAmendment; - auto messageAmender = [&](void) -> const MessageAmendment & { return connectionAmendment; }; + /* Happy path case. */ + { + ConnectionLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedStatus = client.Connect(lifecycleHandler); + EventStreamRpcStatusCode clientStatus = connectedStatus.get().baseStatus; + + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_SUCCESS, clientStatus); + client.Close(); + } - Aws::Crt::String hostname(aws_string_c_str(testContext->echoServerHostNameValue)); + /* Empty amendment headers. */ + { ConnectionConfig accessDeniedConfig; - accessDeniedConfig.SetHostName(hostname); - accessDeniedConfig.SetPort(testContext->echoServerPort); + accessDeniedConfig.SetHostName(testContext.echoServerHost); + accessDeniedConfig.SetPort(testContext.echoServerPort); - /* Happy path case. */ - { - ConnectionLifecycleHandler lifecycleHandler; - Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); - auto connectedStatus = client.Connect(lifecycleHandler); - ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); - client.Close(); - } + TestLifecycleHandler lifecycleHandler; + ClientConnection connection(allocator); + auto future = connection.Connect(accessDeniedConfig, &lifecycleHandler, *testContext.clientBootstrap); + EventStreamRpcStatusCode clientStatus = future.get().baseStatus; - /* Empty amendment headers. */ - { - TestLifecycleHandler lifecycleHandler; - ClientConnection connection(allocator); - auto future = connection.Connect(accessDeniedConfig, &lifecycleHandler, *testContext->clientBootstrap); - ASSERT_TRUE(future.get().baseStatus == EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED); - } + // TOFIX: this isn't reliably true on Windows over TCP due to RSTs blocking final data reads + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, clientStatus); + } - /* Rejected client-name header. */ - { - TestLifecycleHandler lifecycleHandler; - ClientConnection connection(allocator); - connectionAmendment.AddHeader(EventStreamHeader( - Aws::Crt::String("client-name"), Aws::Crt::String("rejected.testy_mc_testerson"), allocator)); - auto future = connection.Connect(accessDeniedConfig, &lifecycleHandler, *testContext->clientBootstrap); - ASSERT_TRUE(future.get().baseStatus == EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED); - } + /* Rejected client-name header. */ + { + ConnectionConfig accessDeniedConfig; + accessDeniedConfig.SetHostName(testContext.echoServerHost); + accessDeniedConfig.SetPort(testContext.echoServerPort); - /* Connect without taking its future then immediately close. */ - { - ConnectionLifecycleHandler lifecycleHandler; - Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); - auto connectedStatus = client.Connect(lifecycleHandler); - client.Close(); - client.Close(); - ASSERT_FALSE(client.IsConnected()); - } + MessageAmendment connectionAmendment; + connectionAmendment.AddHeader(EventStreamHeader( + Aws::Crt::String("client-name"), Aws::Crt::String("rejected.testy_mc_testerson"), allocator)); + + accessDeniedConfig.SetConnectAmendment(connectionAmendment); + + TestLifecycleHandler lifecycleHandler; + ClientConnection connection(allocator); + + auto future = connection.Connect(accessDeniedConfig, &lifecycleHandler, *testContext.clientBootstrap); + EventStreamRpcStatusCode clientStatus = future.get().baseStatus; + + // TOFIX: this isn't reliably true on Windows over TCP due to RSTs blocking final data reads + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, clientStatus); + } + + /* Connect without taking its future then immediately close. */ + { + ConnectionLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedStatus = client.Connect(lifecycleHandler); + client.Close(); + client.Close(); + ASSERT_FALSE(client.IsConnected()); } return AWS_OP_SUCCESS; } +AWS_TEST_CASE(EventStreamConnect, s_TestEventStreamConnect); + + AWS_TEST_CASE_FIXTURE( OperateWhileDisconnected, s_testSetup, @@ -603,3 +712,4 @@ static int s_TestStressClient(struct aws_allocator *allocator, void *ctx) return AWS_OP_SUCCESS; } +#endif From 5c3ccfced2ac3cb51c96bd8d62e98e4bda025967 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 22 Apr 2025 14:09:12 -0700 Subject: [PATCH 13/56] Includes --- .../tests/EventStreamClientTest.cpp | 79 ------------------- 1 file changed, 79 deletions(-) diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 6f2bf37f3..6a101b212 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -15,10 +15,6 @@ #endif #include -#include -#include -#include -#include using namespace Aws::Crt; using namespace Aws::Eventstreamrpc; @@ -240,81 +236,6 @@ AWS_TEST_CASE(EchoClientConnectSuccess, s_TestEchoClientConnectSuccess); #ifdef NEVER -static int s_TestEventStreamConnect(struct aws_allocator *allocator, void *ctx) -{ - ApiHandle apiHandle(allocator); - EventStreamClientTestContext testContext; - s_testSetup(allocator, testContext); - - if (!testContext.hasTestEnvironment()) - { - printf("Environment Variables are not set for the test, skipping..."); - return AWS_OP_SKIP; - } - - /* Happy path case. */ - { - ConnectionLifecycleHandler lifecycleHandler; - Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); - auto connectedStatus = client.Connect(lifecycleHandler); - EventStreamRpcStatusCode clientStatus = connectedStatus.get().baseStatus; - - ASSERT_INT_EQUALS(EVENT_STREAM_RPC_SUCCESS, clientStatus); - client.Close(); - } - - /* Empty amendment headers. */ - { - ConnectionConfig accessDeniedConfig; - accessDeniedConfig.SetHostName(testContext.echoServerHost); - accessDeniedConfig.SetPort(testContext.echoServerPort); - - TestLifecycleHandler lifecycleHandler; - ClientConnection connection(allocator); - auto future = connection.Connect(accessDeniedConfig, &lifecycleHandler, *testContext.clientBootstrap); - EventStreamRpcStatusCode clientStatus = future.get().baseStatus; - - // TOFIX: this isn't reliably true on Windows over TCP due to RSTs blocking final data reads - ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, clientStatus); - } - - /* Rejected client-name header. */ - { - ConnectionConfig accessDeniedConfig; - accessDeniedConfig.SetHostName(testContext.echoServerHost); - accessDeniedConfig.SetPort(testContext.echoServerPort); - - MessageAmendment connectionAmendment; - connectionAmendment.AddHeader(EventStreamHeader( - Aws::Crt::String("client-name"), Aws::Crt::String("rejected.testy_mc_testerson"), allocator)); - - accessDeniedConfig.SetConnectAmendment(connectionAmendment); - - TestLifecycleHandler lifecycleHandler; - ClientConnection connection(allocator); - - auto future = connection.Connect(accessDeniedConfig, &lifecycleHandler, *testContext.clientBootstrap); - EventStreamRpcStatusCode clientStatus = future.get().baseStatus; - - // TOFIX: this isn't reliably true on Windows over TCP due to RSTs blocking final data reads - ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, clientStatus); - } - - /* Connect without taking its future then immediately close. */ - { - ConnectionLifecycleHandler lifecycleHandler; - Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); - auto connectedStatus = client.Connect(lifecycleHandler); - client.Close(); - client.Close(); - ASSERT_FALSE(client.IsConnected()); - } - - return AWS_OP_SUCCESS; -} - -AWS_TEST_CASE(EventStreamConnect, s_TestEventStreamConnect); - AWS_TEST_CASE_FIXTURE( OperateWhileDisconnected, From a1b918aafd02f5acff6cae14e6ec345c4dd3462a Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 22 Apr 2025 14:18:09 -0700 Subject: [PATCH 14/56] Use latest configure credentials to see if retries avoid baffling error --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index faee4db88..976dfa63b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,7 @@ jobs: id-token: write # This is required for requesting the JWT steps: - name: configure AWS credentials (containers) - uses: aws-actions/configure-aws-credentials@v2 + uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ env.CI_IOT_CONTAINERS }} aws-region: ${{ env.AWS_DEFAULT_REGION }} From a571695902b4adedf7dede33abfcbcd8efa8bac2 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 22 Apr 2025 14:37:57 -0700 Subject: [PATCH 15/56] Widen failure possibility based on CI --- eventstream_rpc/tests/EventStreamClientTest.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 6a101b212..1f85fd83b 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -166,8 +166,7 @@ static int s_TestEventStreamConnectFailureNoAuthHeader(struct aws_allocator *all auto future = connection.Connect(connectionConfig, &lifecycleHandler, *testContext.clientBootstrap); EventStreamRpcStatusCode clientStatus = future.get().baseStatus; - // TOFIX: this isn't reliably true on Windows over TCP due to RSTs blocking final data reads - ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, clientStatus); + ASSERT_TRUE(clientStatus == EVENT_STREAM_RPC_CRT_ERROR || clientStatus == EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED); } return AWS_OP_SUCCESS; @@ -200,8 +199,7 @@ static int s_TestEventStreamConnectFailureBadAuthHeader(struct aws_allocator *al auto future = connection.Connect(connectionConfig, &lifecycleHandler, *testContext.clientBootstrap); EventStreamRpcStatusCode clientStatus = future.get().baseStatus; - // TOFIX: this isn't reliably true on Windows over TCP due to RSTs blocking final data reads - ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, clientStatus); + ASSERT_TRUE(clientStatus == EVENT_STREAM_RPC_CRT_ERROR || clientStatus == EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED); } return AWS_OP_SUCCESS; From 9c5dd023af1a728a85df7f6065fcc4ef4c5f5dba Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 23 Apr 2025 09:31:37 -0700 Subject: [PATCH 16/56] Custom eventstream server step so that we can dump server-side logs for debugging on posix systems --- .builder/actions/setup-eventstream-server.py | 86 ++++++++++++++++++++ builder.json | 2 +- 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 .builder/actions/setup-eventstream-server.py diff --git a/.builder/actions/setup-eventstream-server.py b/.builder/actions/setup-eventstream-server.py new file mode 100644 index 000000000..5f6c80342 --- /dev/null +++ b/.builder/actions/setup-eventstream-server.py @@ -0,0 +1,86 @@ +import atexit +import Builder +import os +import subprocess + +class SetupEventstreamServer(Builder.Action): + + def _build_and_run_eventstream_echo_server(self, env): + java_sdk_dir = None + + try: + env.shell.exec(["mvn", "--version"], check=True) + + # maven is installed, so this is a configuration we can start an event stream echo server + java_sdk_dir = env.shell.mktemp() + + env.shell.exec(["git", "clone", "https://github.com/aws/aws-iot-device-sdk-java-v2"], working_dir=java_sdk_dir, check=True) + + sdk_dir = os.path.join(java_sdk_dir, "aws-iot-device-sdk-java-v2", "sdk") + env.shell.pushd(sdk_dir) + + try: + # The EchoTest server is in test-only code + env.shell.exec(["mvn", "test-compile"], check=True) + + env.shell.exec(["mvn", "dependency:build-classpath", "-Dmdep.outputFile=classpath.txt"], check=True) + + with open('classpath.txt', 'r') as file: + classpath = file.read() + + test_class_path = os.path.join(sdk_dir, "target", "test-classes") + target_class_path = os.path.join(sdk_dir, "target", "classes") + directory_separator = os.pathsep + + echo_server_command = [ + "java", + "-Daws.crt.log.level=Trace", + "-Daws.crt.log.destination=File", + "-Daws.crt.log.filename=/tmp/crt.txt", + "-classpath", + f"{test_class_path}{directory_separator}{target_class_path}{directory_separator}{classpath}", + "software.amazon.awssdk.eventstreamrpc.echotest.EchoTestServiceRunner", + "127.0.0.1", + "8033"] + + print(f'Echo server command: {echo_server_command}') + + # bypass builder's exec wrapper since it doesn't allow for background execution + proc = subprocess.Popen(echo_server_command) + + @atexit.register + def _terminate_echo_server(): + proc.terminate() + proc.wait() + with open('/tmp/crt.txt', 'r') as logfile: + serverlog = logfile.read() + print("**************************************************") + print("Eventstream Server Log:\n\n") + print(serverlog) + print("\n\nEnd Log") + print("**************************************************") + os.remove("/tmp/crt.txt") + + env.shell.setenv("AWS_TEST_EVENT_STREAM_ECHO_SERVER_HOST", "127.0.0.1", quiet=False) + env.shell.setenv("AWS_TEST_EVENT_STREAM_ECHO_SERVER_PORT", "8033", quiet=False) + finally: + env.shell.popd() + + except: + print('Failed to set up event stream server. Eventstream CI tests will not be run.') + + return java_sdk_dir + + def run(self, env): + + actions = [] + java_sdk_dir = None + + try: + java_sdk_dir = self._build_and_run_eventstream_echo_server(env) + Builder.SetupCrossCICrtEnvironment().run(env) + except: + if java_sdk_dir: + env.shell.rm(java_sdk_dir) + + return Builder.Script(actions, name='setup-eventstream-server') diff --git a/builder.json b/builder.json index 4f1256ac0..c4cdf6b7c 100644 --- a/builder.json +++ b/builder.json @@ -24,7 +24,7 @@ "build-samples" ], "test_steps": [ - "sdk-ci-test-setup", + "setup-eventstream-server", "test" ], "variants" : { From 8639e715e2388cb0b429edfdb561aaf51d3f5935 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 23 Apr 2025 09:46:51 -0700 Subject: [PATCH 17/56] Install maven during setup --- builder.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builder.json b/builder.json index c4cdf6b7c..8bd999ebb 100644 --- a/builder.json +++ b/builder.json @@ -1,5 +1,8 @@ { "name": "aws-iot-device-sdk-cpp-v2", + "packages": [ + "maven" + ], "!cmake_args": [ "-DPERFORM_HEADER_CHECK=OFF", "-DS2N_NO_PQ_ASM=ON" From 8085d1ae662058a29707aa078236a659da8e546d Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 23 Apr 2025 10:28:06 -0700 Subject: [PATCH 18/56] Try to gather output that tells us whether the Java CRT is supported on this platform --- .builder/actions/setup-eventstream-server.py | 22 ++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.builder/actions/setup-eventstream-server.py b/.builder/actions/setup-eventstream-server.py index 5f6c80342..6188b8d86 100644 --- a/.builder/actions/setup-eventstream-server.py +++ b/.builder/actions/setup-eventstream-server.py @@ -21,9 +21,9 @@ def _build_and_run_eventstream_echo_server(self, env): try: # The EchoTest server is in test-only code - env.shell.exec(["mvn", "test-compile"], check=True) + env.shell.exec(["mvn", "-q", "test-compile"], check=True) - env.shell.exec(["mvn", "dependency:build-classpath", "-Dmdep.outputFile=classpath.txt"], check=True) + env.shell.exec(["mvn", "-q", "dependency:build-classpath", "-Dmdep.outputFile=classpath.txt"], check=True) with open('classpath.txt', 'r') as file: classpath = file.read() @@ -32,6 +32,24 @@ def _build_and_run_eventstream_echo_server(self, env): target_class_path = os.path.join(sdk_dir, "target", "classes") directory_separator = os.pathsep + echo_server_probe_command = [ + "java", + "-Daws.crt.log.level=Trace", + "-Daws.crt.log.destination=File", + "-Daws.crt.log.filename=/tmp/crt.txt", + "-classpath", + f"{test_class_path}{directory_separator}{target_class_path}{directory_separator}{classpath}", + "software.amazon.awssdk.eventstreamrpc.echotest.EchoTestServiceRunner"] + + """ + Try to run the echo server in the foreground without required arguments. This always fails, but + the exception text can tell us whether or not the Java CRT is available on the platform (we have SDK CI + that runs on platforms that the Java CRT does not support). + """ + probe_output = env.shell.exec(echo_server_probe_command) + print("Probe result:\n\n") + print(probe_output) + echo_server_command = [ "java", "-Daws.crt.log.level=Trace", From cf79be3c8066ef278e7eb6d6a24673093a1a4da4 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 23 Apr 2025 11:23:40 -0700 Subject: [PATCH 19/56] Check stderr of eventstream run to verify platform Java CRT support --- .builder/actions/setup-eventstream-server.py | 39 ++++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/.builder/actions/setup-eventstream-server.py b/.builder/actions/setup-eventstream-server.py index 6188b8d86..f32785f49 100644 --- a/.builder/actions/setup-eventstream-server.py +++ b/.builder/actions/setup-eventstream-server.py @@ -34,21 +34,46 @@ def _build_and_run_eventstream_echo_server(self, env): echo_server_probe_command = [ "java", - "-Daws.crt.log.level=Trace", - "-Daws.crt.log.destination=File", - "-Daws.crt.log.filename=/tmp/crt.txt", "-classpath", f"{test_class_path}{directory_separator}{target_class_path}{directory_separator}{classpath}", "software.amazon.awssdk.eventstreamrpc.echotest.EchoTestServiceRunner"] """ Try to run the echo server in the foreground without required arguments. This always fails, but - the exception text can tell us whether or not the Java CRT is available on the platform (we have SDK CI + the output can tell us whether or not the Java CRT is available on the platform (we have SDK CI that runs on platforms that the Java CRT does not support). + + If the CRT supports the platform, we fail with an out-of-index exception (referencing non-existent + command line arguments) + + If the CRT does not support the platform, we fail with + 'java.io.IOException: Unable to open library in jar for AWS CRT' """ - probe_output = env.shell.exec(echo_server_probe_command) - print("Probe result:\n\n") - print(probe_output) + prone_output = "" + probe = subprocess.Popen( + echo_server_probe_command, + stdout=subprocess.STDOUT, + stderr=subprocess.PIPE, + shell=True, + bufsize=0) # do not buffer output + with probe: + + # Convert all output to strings, which makes it much easier to both print + # and process, since all known uses of parsing output want strings anyway + line = probe.stderr.readline() + while (line): + # ignore weird characters coming back from the shell (colors, etc) + if not isinstance(line, str): + line = line.decode('ascii', 'ignore') + # We're reading in binary mode, so no automatic newline translation + if sys.platform == 'win32': + line = line.replace('\r\n', '\n') + prone_output += line + line = probe.stderr.readline() + probe.wait() + + if "java.io.IOException" in probe_output: + raise Exception("Java CRT not supported by this platform") echo_server_command = [ "java", From 440c493994bbaa5a0ce2696874673cde9d2469e2 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 23 Apr 2025 11:39:07 -0700 Subject: [PATCH 20/56] print stderr --- .builder/actions/setup-eventstream-server.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.builder/actions/setup-eventstream-server.py b/.builder/actions/setup-eventstream-server.py index f32785f49..3bd8548c1 100644 --- a/.builder/actions/setup-eventstream-server.py +++ b/.builder/actions/setup-eventstream-server.py @@ -72,7 +72,11 @@ def _build_and_run_eventstream_echo_server(self, env): line = probe.stderr.readline() probe.wait() + print("Probe stderr:\n\n") + print(probe_output) + if "java.io.IOException" in probe_output: + print("Skipping eventstream server unsupported platform") raise Exception("Java CRT not supported by this platform") echo_server_command = [ From e8f00fdff1ace5e94bfed9d5e95a6be17a4afc30 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 23 Apr 2025 11:59:56 -0700 Subject: [PATCH 21/56] Why is everything failing now? --- .builder/actions/setup-eventstream-server.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.builder/actions/setup-eventstream-server.py b/.builder/actions/setup-eventstream-server.py index 3bd8548c1..af4824137 100644 --- a/.builder/actions/setup-eventstream-server.py +++ b/.builder/actions/setup-eventstream-server.py @@ -49,7 +49,7 @@ def _build_and_run_eventstream_echo_server(self, env): If the CRT does not support the platform, we fail with 'java.io.IOException: Unable to open library in jar for AWS CRT' """ - prone_output = "" + probe_output = "" probe = subprocess.Popen( echo_server_probe_command, stdout=subprocess.STDOUT, @@ -68,7 +68,7 @@ def _build_and_run_eventstream_echo_server(self, env): # We're reading in binary mode, so no automatic newline translation if sys.platform == 'win32': line = line.replace('\r\n', '\n') - prone_output += line + probe_output += line line = probe.stderr.readline() probe.wait() @@ -113,8 +113,9 @@ def _terminate_echo_server(): finally: env.shell.popd() - except: + except Exception as ex: print('Failed to set up event stream server. Eventstream CI tests will not be run.') + print(ex) return java_sdk_dir From d80780f1f5b832aa082c72e15bc57b1c6ad42c4d Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 23 Apr 2025 12:18:13 -0700 Subject: [PATCH 22/56] Don't route stdout to stdout --- .builder/actions/setup-eventstream-server.py | 1 - 1 file changed, 1 deletion(-) diff --git a/.builder/actions/setup-eventstream-server.py b/.builder/actions/setup-eventstream-server.py index af4824137..46a921442 100644 --- a/.builder/actions/setup-eventstream-server.py +++ b/.builder/actions/setup-eventstream-server.py @@ -52,7 +52,6 @@ def _build_and_run_eventstream_echo_server(self, env): probe_output = "" probe = subprocess.Popen( echo_server_probe_command, - stdout=subprocess.STDOUT, stderr=subprocess.PIPE, shell=True, bufsize=0) # do not buffer output From 121dc44508dc5465037ed8258ec3974c0c735919 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 23 Apr 2025 12:30:35 -0700 Subject: [PATCH 23/56] Missing import --- .builder/actions/setup-eventstream-server.py | 1 + 1 file changed, 1 insertion(+) diff --git a/.builder/actions/setup-eventstream-server.py b/.builder/actions/setup-eventstream-server.py index 46a921442..a16da933d 100644 --- a/.builder/actions/setup-eventstream-server.py +++ b/.builder/actions/setup-eventstream-server.py @@ -2,6 +2,7 @@ import Builder import os import subprocess +import sys class SetupEventstreamServer(Builder.Action): From 7c7f7cdcf21db1bf6899b420de5d073b9a908be6 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 23 Apr 2025 12:45:17 -0700 Subject: [PATCH 24/56] Probe command log --- .builder/actions/setup-eventstream-server.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.builder/actions/setup-eventstream-server.py b/.builder/actions/setup-eventstream-server.py index a16da933d..6c2e8cd14 100644 --- a/.builder/actions/setup-eventstream-server.py +++ b/.builder/actions/setup-eventstream-server.py @@ -3,6 +3,7 @@ import os import subprocess import sys +import time class SetupEventstreamServer(Builder.Action): @@ -24,8 +25,9 @@ def _build_and_run_eventstream_echo_server(self, env): # The EchoTest server is in test-only code env.shell.exec(["mvn", "-q", "test-compile"], check=True) - env.shell.exec(["mvn", "-q", "dependency:build-classpath", "-Dmdep.outputFile=classpath.txt"], check=True) + env.shell.exec(["mvn", "dependency:build-classpath", "-Dmdep.outputFile=classpath.txt"], check=True) + time.sleep(1) with open('classpath.txt', 'r') as file: classpath = file.read() @@ -39,6 +41,9 @@ def _build_and_run_eventstream_echo_server(self, env): f"{test_class_path}{directory_separator}{target_class_path}{directory_separator}{classpath}", "software.amazon.awssdk.eventstreamrpc.echotest.EchoTestServiceRunner"] + probe_command_flat = " ".join(echo_server_probe_command) + print(f'Echo probe command: {probe_command_flat}') + """ Try to run the echo server in the foreground without required arguments. This always fails, but the output can tell us whether or not the Java CRT is available on the platform (we have SDK CI From 2028eacca5bd3a5f5efdca879b68156a8d13844c Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 23 Apr 2025 13:52:45 -0700 Subject: [PATCH 25/56] Updates --- .builder/actions/setup-eventstream-server.py | 28 +++++--------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/.builder/actions/setup-eventstream-server.py b/.builder/actions/setup-eventstream-server.py index 6c2e8cd14..349826c3c 100644 --- a/.builder/actions/setup-eventstream-server.py +++ b/.builder/actions/setup-eventstream-server.py @@ -1,6 +1,7 @@ import atexit import Builder import os +import shutil import subprocess import sys import time @@ -23,8 +24,7 @@ def _build_and_run_eventstream_echo_server(self, env): try: # The EchoTest server is in test-only code - env.shell.exec(["mvn", "-q", "test-compile"], check=True) - + env.shell.exec(["mvn", "test-compile"], check=True) env.shell.exec(["mvn", "dependency:build-classpath", "-Dmdep.outputFile=classpath.txt"], check=True) time.sleep(1) @@ -58,9 +58,7 @@ def _build_and_run_eventstream_echo_server(self, env): probe_output = "" probe = subprocess.Popen( echo_server_probe_command, - stderr=subprocess.PIPE, - shell=True, - bufsize=0) # do not buffer output + stderr=subprocess.PIPE) with probe: # Convert all output to strings, which makes it much easier to both print @@ -86,9 +84,6 @@ def _build_and_run_eventstream_echo_server(self, env): echo_server_command = [ "java", - "-Daws.crt.log.level=Trace", - "-Daws.crt.log.destination=File", - "-Daws.crt.log.filename=/tmp/crt.txt", "-classpath", f"{test_class_path}{directory_separator}{target_class_path}{directory_separator}{classpath}", "software.amazon.awssdk.eventstreamrpc.echotest.EchoTestServiceRunner", @@ -104,14 +99,7 @@ def _build_and_run_eventstream_echo_server(self, env): def _terminate_echo_server(): proc.terminate() proc.wait() - with open('/tmp/crt.txt', 'r') as logfile: - serverlog = logfile.read() - print("**************************************************") - print("Eventstream Server Log:\n\n") - print(serverlog) - print("\n\nEnd Log") - print("**************************************************") - os.remove("/tmp/crt.txt") + shutil.rmtree(java_sdk_dir) env.shell.setenv("AWS_TEST_EVENT_STREAM_ECHO_SERVER_HOST", "127.0.0.1", quiet=False) env.shell.setenv("AWS_TEST_EVENT_STREAM_ECHO_SERVER_PORT", "8033", quiet=False) @@ -122,18 +110,16 @@ def _terminate_echo_server(): print('Failed to set up event stream server. Eventstream CI tests will not be run.') print(ex) - return java_sdk_dir + return def run(self, env): actions = [] - java_sdk_dir = None try: - java_sdk_dir = self._build_and_run_eventstream_echo_server(env) + self._build_and_run_eventstream_echo_server(env) Builder.SetupCrossCICrtEnvironment().run(env) except: - if java_sdk_dir: - env.shell.rm(java_sdk_dir) + pass return Builder.Script(actions, name='setup-eventstream-server') From 231e4f4eb7e7aaef2c7a6dc539d655ffe4122b96 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 23 Apr 2025 14:10:12 -0700 Subject: [PATCH 26/56] Umm let's not cause tsan warnings by blindly unlocking stuff --- eventstream_rpc/source/EventStreamClient.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index ddf1d1c99..3a52b259b 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -221,22 +221,28 @@ namespace Aws ClientConnection::~ClientConnection() noexcept { m_stateMutex.lock(); - if (m_connectionWillSetup) + bool waitForSetup = m_connectionWillSetup; + m_stateMutex.unlock(); + + if (waitForSetup) { - m_stateMutex.unlock(); m_connectionSetupPromise.get_future().wait(); } + + bool waitForClosed = false; m_stateMutex.lock(); if (m_clientState != DISCONNECTED) { Close(); - m_stateMutex.unlock(); - m_closedPromise.get_future().wait(); + waitForClosed = true; } - /* Cover the case in which the if statements are not hit. */ - m_stateMutex.unlock(); m_stateMutex.unlock(); + if (waitForClosed) + { + m_closedPromise.get_future().wait(); + } + m_underlyingConnection = nullptr; } From cc7afc785e30d4f22c3578ebf1651c2cdb4351ce Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Thu, 24 Apr 2025 13:03:14 -0700 Subject: [PATCH 27/56] Formatting fix (but don't check in format update yet) + more test work --- .github/workflows/lint.yml | 15 +- eventstream_rpc/tests/EchoTestRpcModel.cpp | 57 +++- .../tests/EventStreamClientTest.cpp | 279 +++++++++++++++--- .../tests/include/awstest/EchoTestRpcModel.h | 48 +-- format-check.py | 6 +- 5 files changed, 321 insertions(+), 84 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index a0da81330..a09ac6dec 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,15 +9,12 @@ on: jobs: clang-format: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 # latest steps: - - name: Checkout Sources - uses: actions/checkout@v1 + - name: Checkout Sources + uses: actions/checkout@v4 - - name: clang-format lint - uses: DoozyX/clang-format-lint-action@v0.13 - with: - # List of extensions to check - extensions: cpp,h - clangFormatVersion: 11.1.0 + - name: clang-format lint + run: | + ./format-check.py diff --git a/eventstream_rpc/tests/EchoTestRpcModel.cpp b/eventstream_rpc/tests/EchoTestRpcModel.cpp index c0737ce68..3220f85a0 100644 --- a/eventstream_rpc/tests/EchoTestRpcModel.cpp +++ b/eventstream_rpc/tests/EchoTestRpcModel.cpp @@ -36,7 +36,10 @@ namespace Awstest const char *Product::MODEL_NAME = "awstest#Product"; - Aws::Crt::String Product::GetModelName() const noexcept { return Product::MODEL_NAME; } + Aws::Crt::String Product::GetModelName() const noexcept + { + return Product::MODEL_NAME; + } Aws::Crt::ScopedResource Product::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -84,7 +87,10 @@ namespace Awstest const char *Pair::MODEL_NAME = "awstest#Pair"; - Aws::Crt::String Pair::GetModelName() const noexcept { return Pair::MODEL_NAME; } + Aws::Crt::String Pair::GetModelName() const noexcept + { + return Pair::MODEL_NAME; + } Aws::Crt::ScopedResource Pair::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -140,7 +146,10 @@ namespace Awstest const char *Customer::MODEL_NAME = "awstest#Customer"; - Aws::Crt::String Customer::GetModelName() const noexcept { return Customer::MODEL_NAME; } + Aws::Crt::String Customer::GetModelName() const noexcept + { + return Customer::MODEL_NAME; + } Aws::Crt::ScopedResource Customer::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -317,7 +326,7 @@ namespace Awstest } } - Aws::Crt::Optional MessageData::GetEnumMessage() noexcept + Aws::Crt::Optional MessageData::GetEnumMessage() const noexcept { if (!m_enumMessage.has_value()) return Aws::Crt::Optional(); @@ -343,7 +352,10 @@ namespace Awstest const char *MessageData::MODEL_NAME = "awstest#MessageData"; - Aws::Crt::String MessageData::GetModelName() const noexcept { return MessageData::MODEL_NAME; } + Aws::Crt::String MessageData::GetModelName() const noexcept + { + return MessageData::MODEL_NAME; + } Aws::Crt::ScopedResource MessageData::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -419,7 +431,10 @@ namespace Awstest const char *EchoStreamingMessage::MODEL_NAME = "awstest#EchoStreamingMessage"; - Aws::Crt::String EchoStreamingMessage::GetModelName() const noexcept { return EchoStreamingMessage::MODEL_NAME; } + Aws::Crt::String EchoStreamingMessage::GetModelName() const noexcept + { + return EchoStreamingMessage::MODEL_NAME; + } Aws::Crt::ScopedResource EchoStreamingMessage::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -468,7 +483,10 @@ namespace Awstest const char *ServiceError::MODEL_NAME = "awstest#ServiceError"; - Aws::Crt::String ServiceError::GetModelName() const noexcept { return ServiceError::MODEL_NAME; } + Aws::Crt::String ServiceError::GetModelName() const noexcept + { + return ServiceError::MODEL_NAME; + } Aws::Crt::ScopedResource ServiceError::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -566,7 +584,10 @@ namespace Awstest const char *GetAllProductsRequest::MODEL_NAME = "awstest#GetAllProductsRequest"; - Aws::Crt::String GetAllProductsRequest::GetModelName() const noexcept { return GetAllProductsRequest::MODEL_NAME; } + Aws::Crt::String GetAllProductsRequest::GetModelName() const noexcept + { + return GetAllProductsRequest::MODEL_NAME; + } Aws::Crt::ScopedResource GetAllProductsRequest::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -707,7 +728,10 @@ namespace Awstest const char *EchoStreamingResponse::MODEL_NAME = "awstest#EchoStreamingResponse"; - Aws::Crt::String EchoStreamingResponse::GetModelName() const noexcept { return EchoStreamingResponse::MODEL_NAME; } + Aws::Crt::String EchoStreamingResponse::GetModelName() const noexcept + { + return EchoStreamingResponse::MODEL_NAME; + } Aws::Crt::ScopedResource EchoStreamingResponse::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -745,7 +769,10 @@ namespace Awstest const char *EchoStreamingRequest::MODEL_NAME = "awstest#EchoStreamingRequest"; - Aws::Crt::String EchoStreamingRequest::GetModelName() const noexcept { return EchoStreamingRequest::MODEL_NAME; } + Aws::Crt::String EchoStreamingRequest::GetModelName() const noexcept + { + return EchoStreamingRequest::MODEL_NAME; + } Aws::Crt::ScopedResource EchoStreamingRequest::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -791,7 +818,10 @@ namespace Awstest const char *EchoMessageResponse::MODEL_NAME = "awstest#EchoMessageResponse"; - Aws::Crt::String EchoMessageResponse::GetModelName() const noexcept { return EchoMessageResponse::MODEL_NAME; } + Aws::Crt::String EchoMessageResponse::GetModelName() const noexcept + { + return EchoMessageResponse::MODEL_NAME; + } Aws::Crt::ScopedResource EchoMessageResponse::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -837,7 +867,10 @@ namespace Awstest const char *EchoMessageRequest::MODEL_NAME = "awstest#EchoMessageRequest"; - Aws::Crt::String EchoMessageRequest::GetModelName() const noexcept { return EchoMessageRequest::MODEL_NAME; } + Aws::Crt::String EchoMessageRequest::GetModelName() const noexcept + { + return EchoMessageRequest::MODEL_NAME; + } Aws::Crt::ScopedResource EchoMessageRequest::s_allocateFromPayload( Aws::Crt::StringView stringView, diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 1f85fd83b..5f50258dd 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -38,14 +38,11 @@ struct EventStreamClientTestContext Aws::Crt::String echoServerHost; }; -EventStreamClientTestContext::EventStreamClientTestContext(struct aws_allocator *allocator) : - echoServerPort(0) +EventStreamClientTestContext::EventStreamClientTestContext(struct aws_allocator *allocator) : echoServerPort(0) { elGroup = Aws::Crt::MakeShared(allocator, 0, allocator); - resolver = - Aws::Crt::MakeShared(allocator, *elGroup, 8, 30, allocator); - clientBootstrap = Aws::Crt::MakeShared( - allocator, *elGroup, *resolver, allocator); + resolver = Aws::Crt::MakeShared(allocator, *elGroup, 8, 30, allocator); + clientBootstrap = Aws::Crt::MakeShared(allocator, *elGroup, *resolver, allocator); aws_string *host_env_value = nullptr; aws_get_environment_value(allocator, s_env_name_echo_server_host, &host_env_value); @@ -55,7 +52,8 @@ EventStreamClientTestContext::EventStreamClientTestContext(struct aws_allocator } struct aws_string *port_env_value = nullptr; - if (!aws_get_environment_value(allocator, s_env_name_echo_server_port, &port_env_value) && port_env_value != nullptr) + if (!aws_get_environment_value(allocator, s_env_name_echo_server_port, &port_env_value) && + port_env_value != nullptr) { echoServerPort = static_cast(atoi(aws_string_c_str(port_env_value))); } @@ -72,11 +70,11 @@ bool EventStreamClientTestContext::isValidEnvironment() const class TestLifecycleHandler : public ConnectionLifecycleHandler { public: - TestLifecycleHandler() : - isConnected(false), - disconnectCrtErrorCode(AWS_ERROR_SUCCESS), - disconnectRpcStatusCode(EVENT_STREAM_RPC_SUCCESS) - {} + TestLifecycleHandler() + : isConnected(false), disconnectCrtErrorCode(AWS_ERROR_SUCCESS), + disconnectRpcStatusCode(EVENT_STREAM_RPC_SUCCESS) + { + } void OnConnectCallback() override { @@ -104,7 +102,6 @@ class TestLifecycleHandler : public ConnectionLifecycleHandler } private: - std::condition_variable semaphore; std::mutex semaphoreLock; @@ -126,7 +123,7 @@ static int s_TestEventStreamConnectSuccess(struct aws_allocator *allocator, void { MessageAmendment connectionAmendment; connectionAmendment.AddHeader(EventStreamHeader( - Aws::Crt::String("client-name"), Aws::Crt::String("accepted.testy_mc_testerson"), allocator)); + Aws::Crt::String("client-name"), Aws::Crt::String("accepted.testy_mc_testerson"), allocator)); ConnectionConfig connectionConfig; connectionConfig.SetHostName(testContext.echoServerHost); @@ -166,7 +163,8 @@ static int s_TestEventStreamConnectFailureNoAuthHeader(struct aws_allocator *all auto future = connection.Connect(connectionConfig, &lifecycleHandler, *testContext.clientBootstrap); EventStreamRpcStatusCode clientStatus = future.get().baseStatus; - ASSERT_TRUE(clientStatus == EVENT_STREAM_RPC_CRT_ERROR || clientStatus == EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED); + ASSERT_TRUE( + clientStatus == EVENT_STREAM_RPC_CRT_ERROR || clientStatus == EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED); } return AWS_OP_SUCCESS; @@ -187,7 +185,7 @@ static int s_TestEventStreamConnectFailureBadAuthHeader(struct aws_allocator *al { MessageAmendment connectionAmendment; connectionAmendment.AddHeader(EventStreamHeader( - Aws::Crt::String("client-name"), Aws::Crt::String("rejected.testy_mc_testerson"), allocator)); + Aws::Crt::String("client-name"), Aws::Crt::String("rejected.testy_mc_testerson"), allocator)); ConnectionConfig connectionConfig; connectionConfig.SetHostName(testContext.echoServerHost); @@ -199,7 +197,8 @@ static int s_TestEventStreamConnectFailureBadAuthHeader(struct aws_allocator *al auto future = connection.Connect(connectionConfig, &lifecycleHandler, *testContext.clientBootstrap); EventStreamRpcStatusCode clientStatus = future.get().baseStatus; - ASSERT_TRUE(clientStatus == EVENT_STREAM_RPC_CRT_ERROR || clientStatus == EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED); + ASSERT_TRUE( + clientStatus == EVENT_STREAM_RPC_CRT_ERROR || clientStatus == EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED); } return AWS_OP_SUCCESS; @@ -232,54 +231,259 @@ static int s_TestEchoClientConnectSuccess(struct aws_allocator *allocator, void AWS_TEST_CASE(EchoClientConnectSuccess, s_TestEchoClientConnectSuccess); -#ifdef NEVER +static int s_TestEchoClientDoubleClose(struct aws_allocator *allocator, void *ctx) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + { + ConnectionLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + client.Close(); + client.Close(); + } -AWS_TEST_CASE_FIXTURE( - OperateWhileDisconnected, - s_testSetup, - s_TestOperationWhileDisconnected, - s_testTeardown, - &s_testContext); -static int s_TestOperationWhileDisconnected(struct aws_allocator *allocator, void *ctx) + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(EchoClientDoubleClose, s_TestEchoClientDoubleClose); + +static int s_TestEchoClientMultiConnectSuccessFail(struct aws_allocator *allocator, void *ctx) { - auto *testContext = static_cast(ctx); + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { + ConnectionLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedStatus = client.Connect(lifecycleHandler); + + auto failedStatus1 = client.Connect(lifecycleHandler); + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED, failedStatus1.get().baseStatus); + + auto failedStatus2 = client.Connect(lifecycleHandler); + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED, failedStatus2.get().baseStatus); + + EventStreamRpcStatusCode clientStatus = connectedStatus.get().baseStatus; + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_SUCCESS, clientStatus); + + client.Close(); + } + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(EchoClientMultiConnectSuccessFail, s_TestEchoClientMultiConnectSuccessFail); + +static void s_onMessageFlush(int errorCode) +{ + (void)errorCode; +} + +#define DEFINE_CHECK_MESSAGE_DATA_MEMBER_EQUALITY_FN(TYPENAME) \ + static int s_checkMessageDataMemberEquality( \ + Aws::Crt::Optional expectedValue, Aws::Crt::Optional actualValue) \ + { \ + ASSERT_TRUE(expectedValue.has_value() == actualValue.has_value()); \ + if (expectedValue.has_value()) \ + { \ + ASSERT_TRUE(expectedValue.value() == actualValue.value()); \ + } \ + \ + return AWS_OP_SUCCESS; \ + } + +DEFINE_CHECK_MESSAGE_DATA_MEMBER_EQUALITY_FN(Aws::Crt::String) +DEFINE_CHECK_MESSAGE_DATA_MEMBER_EQUALITY_FN(bool) + +static int s_checkMessageDataEquality(const MessageData &expectedData, const MessageData &actualData) +{ + ASSERT_SUCCESS(s_checkMessageDataMemberEquality(expectedData.GetStringMessage(), actualData.GetStringMessage())); + ASSERT_SUCCESS(s_checkMessageDataMemberEquality(expectedData.GetBooleanMessage(), actualData.GetBooleanMessage())); + + return AWS_OP_SUCCESS; +} + +static int s_DoTestEchoClientOperationEchoSuccess( + struct aws_allocator *allocator, + std::function messageDataBuilder) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { + ConnectionLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedStatus = client.Connect(lifecycleHandler); + ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); + + auto echoMessage = client.NewEchoMessage(); + EchoMessageRequest echoMessageRequest; + MessageData messageData; + messageDataBuilder(messageData); + echoMessageRequest.SetMessage(messageData); + + auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); + requestFuture.wait(); + auto result = echoMessage->GetResult().get(); + ASSERT_TRUE(result); + auto response = result.GetOperationResponse(); + ASSERT_NOT_NULL(response); + + ASSERT_SUCCESS(s_checkMessageDataEquality(messageData, response->GetMessage().value())); + } + + return AWS_OP_SUCCESS; +} + +static int s_TestEchoClientOperationEchoSuccessString(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientOperationEchoSuccess( + allocator, + [](MessageData &messageData) + { + Aws::Crt::String value = "Hello World"; + messageData.SetStringMessage(value); + }); +} + +AWS_TEST_CASE(EchoClientOperationEchoSuccessString, s_TestEchoClientOperationEchoSuccessString); - /* Don't connect at all and try running operations as normal. */ +static int s_TestEchoClientOperationEchoSuccessMultiple(struct aws_allocator *allocator, void *ctx) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) { - if (!s_isEchoserverSetup(*testContext)) + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { + ConnectionLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedStatus = client.Connect(lifecycleHandler); + ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); + + for (size_t i = 0; i < 5; i++) { - printf("Environment Variables are not set for the test, skip the test"); - return AWS_OP_SKIP; + auto echoMessage = client.NewEchoMessage(); + EchoMessageRequest echoMessageRequest; + MessageData messageData; + Aws::Crt::StringStream ss; + ss << "Hello Echo #" << i + 1; + Aws::Crt::String expectedMessage(ss.str().c_str()); + messageData.SetStringMessage(expectedMessage); + echoMessageRequest.SetMessage(messageData); + + auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); + requestFuture.wait(); + auto result = echoMessage->GetResult().get(); + ASSERT_TRUE(result); + auto response = result.GetOperationResponse(); + ASSERT_NOT_NULL(response); + ASSERT_TRUE(response->GetMessage().value().GetStringMessage().value() == expectedMessage); } + } + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(EchoClientOperationEchoSuccessMultiple, s_TestEchoClientOperationEchoSuccessMultiple); +static int s_TestEchoClientOperationEchoFailureNeverConnected(struct aws_allocator *allocator, void *ctx) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { ConnectionLifecycleHandler lifecycleHandler; - Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto echoMessage = client.NewEchoMessage(); EchoMessageRequest echoMessageRequest; MessageData messageData; Aws::Crt::String expectedMessage("l33t"); messageData.SetStringMessage(expectedMessage); echoMessageRequest.SetMessage(messageData); + auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - ASSERT_TRUE(requestFuture.get().baseStatus == EVENT_STREAM_RPC_CONNECTION_CLOSED); + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_CLOSED, requestFuture.get().baseStatus); + auto result = echoMessage->GetOperationResult().get(); ASSERT_FALSE(result); + auto error = result.GetRpcError(); - ASSERT_TRUE(error.baseStatus == EVENT_STREAM_RPC_CONNECTION_CLOSED); + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_CLOSED, error.baseStatus); + } + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(EchoClientOperationEchoFailureNeverConnected, s_TestEchoClientOperationEchoFailureNeverConnected); + +static int s_TestEchoClientOperationEchoFailureDisconnected(struct aws_allocator *allocator, void *ctx) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; } - /* Idempotent close and its safety. */ { ConnectionLifecycleHandler lifecycleHandler; - Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); - client.Close(); + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedStatus = client.Connect(lifecycleHandler); + ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); + client.Close(); + + auto echoMessage = client.NewEchoMessage(); + EchoMessageRequest echoMessageRequest; + MessageData messageData; + Aws::Crt::String expectedMessage("l33t"); + messageData.SetStringMessage(expectedMessage); + echoMessageRequest.SetMessage(messageData); + + auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_CLOSED, requestFuture.get().baseStatus); + + auto result = echoMessage->GetOperationResult().get(); + ASSERT_FALSE(result); + + auto error = result.GetRpcError(); + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_CLOSED, error.baseStatus); } return AWS_OP_SUCCESS; } +AWS_TEST_CASE(EchoClientOperationEchoFailureDisconnected, s_TestEchoClientOperationEchoFailureDisconnected); + +#ifdef NEVER + AWS_TEST_CASE_FIXTURE(EchoOperation, s_testSetup, s_TestEchoOperation, s_testTeardown, &s_testContext); static int s_TestEchoOperation(struct aws_allocator *allocator, void *ctx) { @@ -598,7 +802,8 @@ static int s_TestStressClient(struct aws_allocator *allocator, void *ctx) Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); auto connectedStatus = client.Connect(lifecycleHandler); ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); - auto invokeOperation = [&](void) -> int { + auto invokeOperation = [&](void) -> int + { auto echoMessage = client.NewEchoMessage(); messageData.SetStringMessage(expectedMessage); echoMessageRequest.SetMessage(messageData); diff --git a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h index b3eec4ce2..ea644a271 100644 --- a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h +++ b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h @@ -34,7 +34,7 @@ namespace Awstest /** * The product's name */ - Aws::Crt::Optional GetName() noexcept { return m_name; } + Aws::Crt::Optional GetName() const noexcept { return m_name; } /** * How much the product costs */ @@ -42,7 +42,7 @@ namespace Awstest /** * How much the product costs */ - Aws::Crt::Optional GetPrice() noexcept { return m_price; } + Aws::Crt::Optional GetPrice() const noexcept { return m_price; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(Product &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -76,7 +76,7 @@ namespace Awstest /** * Pair.key as a string */ - Aws::Crt::Optional GetKey() noexcept { return m_key; } + Aws::Crt::Optional GetKey() const noexcept { return m_key; } /** * Pair.value also a string! */ @@ -84,7 +84,7 @@ namespace Awstest /** * Pair.value also a string! */ - Aws::Crt::Optional GetValue() noexcept { return m_value; } + Aws::Crt::Optional GetValue() const noexcept { return m_value; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(Pair &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -126,7 +126,7 @@ namespace Awstest /** * Opaque customer identifier */ - Aws::Crt::Optional GetId() noexcept { return m_id; } + Aws::Crt::Optional GetId() const noexcept { return m_id; } /** * First name of the customer */ @@ -134,7 +134,7 @@ namespace Awstest /** * First name of the customer */ - Aws::Crt::Optional GetFirstName() noexcept { return m_firstName; } + Aws::Crt::Optional GetFirstName() const noexcept { return m_firstName; } /** * Last name of the customer */ @@ -142,7 +142,7 @@ namespace Awstest /** * Last name of the customer */ - Aws::Crt::Optional GetLastName() noexcept { return m_lastName; } + Aws::Crt::Optional GetLastName() const noexcept { return m_lastName; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(Customer &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -177,7 +177,7 @@ namespace Awstest /** * Some string data */ - Aws::Crt::Optional GetStringMessage() noexcept { return m_stringMessage; } + Aws::Crt::Optional GetStringMessage() const noexcept { return m_stringMessage; } /** * Some boolean data */ @@ -185,7 +185,7 @@ namespace Awstest /** * Some boolean data */ - Aws::Crt::Optional GetBooleanMessage() noexcept { return m_booleanMessage; } + Aws::Crt::Optional GetBooleanMessage() const noexcept { return m_booleanMessage; } /** * Some timestamp data */ @@ -193,7 +193,7 @@ namespace Awstest /** * Some timestamp data */ - Aws::Crt::Optional GetTimeMessage() noexcept { return m_timeMessage; } + Aws::Crt::Optional GetTimeMessage() const noexcept { return m_timeMessage; } /** * Some document data */ @@ -204,7 +204,7 @@ namespace Awstest /** * Some document data */ - Aws::Crt::Optional GetDocumentMessage() noexcept { return m_documentMessage; } + Aws::Crt::Optional GetDocumentMessage() const noexcept { return m_documentMessage; } /** * Some FruitEnum data */ @@ -212,7 +212,7 @@ namespace Awstest /** * Some FruitEnum data */ - Aws::Crt::Optional GetEnumMessage() noexcept; + Aws::Crt::Optional GetEnumMessage() const noexcept; /** * Some blob data */ @@ -220,7 +220,7 @@ namespace Awstest /** * Some blob data */ - Aws::Crt::Optional> GetBlobMessage() noexcept { return m_blobMessage; } + Aws::Crt::Optional> GetBlobMessage() const noexcept { return m_blobMessage; } /** * Some list of strings data */ @@ -231,7 +231,7 @@ namespace Awstest /** * Some list of strings data */ - Aws::Crt::Optional> GetStringListMessage() noexcept + Aws::Crt::Optional> GetStringListMessage() const noexcept { return m_stringListMessage; } @@ -245,7 +245,7 @@ namespace Awstest /** * A list of key-value pairs */ - Aws::Crt::Optional> GetKeyValuePairList() noexcept { return m_keyValuePairList; } + Aws::Crt::Optional> GetKeyValuePairList() const noexcept { return m_keyValuePairList; } /** * A map from strings to Product shapes */ @@ -256,7 +256,7 @@ namespace Awstest /** * A map from strings to Product shapes */ - Aws::Crt::Optional> GetStringToValue() noexcept + Aws::Crt::Optional> GetStringToValue() const noexcept { return m_stringToValue; } @@ -305,7 +305,7 @@ namespace Awstest /** * A message data record */ - Aws::Crt::Optional GetStreamMessage() noexcept + Aws::Crt::Optional GetStreamMessage() const noexcept { if (m_chosenMember == TAG_STREAM_MESSAGE) { @@ -327,7 +327,7 @@ namespace Awstest /** * A key value pair */ - Aws::Crt::Optional GetKeyValuePair() noexcept + Aws::Crt::Optional GetKeyValuePair() const noexcept { if (m_chosenMember == TAG_KEY_VALUE_PAIR) { @@ -376,7 +376,7 @@ namespace Awstest /** * An error message */ - Aws::Crt::Optional GetMessage() noexcept override { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept override { return m_message; } /** * Some auxiliary value */ @@ -384,7 +384,7 @@ namespace Awstest /** * Some auxiliary value */ - Aws::Crt::Optional GetValue() noexcept { return m_value; } + Aws::Crt::Optional GetValue() const noexcept { return m_value; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ServiceError &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -418,7 +418,7 @@ namespace Awstest /** * A map from strings to products */ - Aws::Crt::Optional> GetProducts() noexcept { return m_products; } + Aws::Crt::Optional> GetProducts() const noexcept { return m_products; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetAllProductsResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -475,7 +475,7 @@ namespace Awstest /** * A list of all known customers */ - Aws::Crt::Optional> GetCustomers() noexcept { return m_customers; } + Aws::Crt::Optional> GetCustomers() const noexcept { return m_customers; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetAllCustomersResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -580,7 +580,7 @@ namespace Awstest /** * Some message data */ - Aws::Crt::Optional GetMessage() noexcept { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(EchoMessageResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -613,7 +613,7 @@ namespace Awstest /** * Some message data */ - Aws::Crt::Optional GetMessage() noexcept { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(EchoMessageRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( diff --git a/format-check.py b/format-check.py index b2678b8a4..8dcc21958 100755 --- a/format-check.py +++ b/format-check.py @@ -20,9 +20,10 @@ check_dirs = ['deviceadvisor', 'devicedefender', 'discovery', 'eventstream_rpc', 'greengrass_ipc', 'identity', 'iotdevicecommon', 'jobs', 'shadow', 'samples', 'secure_tunneling'] +filepaths_file = NamedTemporaryFile(delete=False) for check_dir in check_dirs: # create file containing list of all files to format - filepaths_file = NamedTemporaryFile(delete=False) + for dirpath, dirnames, filenames in os.walk(check_dir): for filename in filenames: @@ -35,7 +36,8 @@ continue filepaths_file.write(f"{filepath}\n".encode()) - filepaths_file.close() + +filepaths_file.close() # use pipx to run clang-format from PyPI # this is a simple way to run the same clang-format version regardless of OS From cd9289ccca937b9c54d166e4dd80d9af3d1c3664 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Thu, 24 Apr 2025 13:29:13 -0700 Subject: [PATCH 28/56] Formatting and codegen updates --- .../aws/eventstreamrpc/EventStreamClient.h | 6 +- eventstream_rpc/source/EventStreamClient.cpp | 45 +- eventstream_rpc/tests/CMakeLists.txt | 14 +- eventstream_rpc/tests/EchoTestRpcClient.cpp | 15 +- .../aws/greengrass/GreengrassCoreIpcModel.h | 405 ++++++++++-------- .../source/GreengrassCoreIpcClient.cpp | 15 +- .../source/GreengrassCoreIpcModel.cpp | 166 ++++--- 7 files changed, 412 insertions(+), 254 deletions(-) diff --git a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h index 706b94fdf..ccd464eb9 100644 --- a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h +++ b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h @@ -127,9 +127,9 @@ namespace Aws void PrependHeaders(Crt::List &&headers); void SetPayload(const Crt::Optional &payload) noexcept; void SetPayload(Crt::Optional &&payload); - const Crt::List &GetHeaders() const &noexcept; + const Crt::List &GetHeaders() const & noexcept; Crt::List &&GetHeaders() &&; - const Crt::Optional &GetPayload() const &noexcept; + const Crt::Optional &GetPayload() const & noexcept; Crt::Optional &&GetPayload() &&; private: @@ -408,7 +408,7 @@ namespace Aws explicit OperationError() noexcept = default; static void s_customDeleter(OperationError *shape) noexcept; virtual void SerializeToJsonObject(Crt::JsonObject &payloadObject) const override; - virtual Crt::Optional GetMessage() noexcept = 0; + virtual Crt::Optional GetMessage() const noexcept = 0; }; /** diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 3a52b259b..65983178e 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -113,13 +113,25 @@ namespace Aws return *this; } - const Crt::List &MessageAmendment::GetHeaders() const &noexcept { return m_headers; } + const Crt::List &MessageAmendment::GetHeaders() const & noexcept + { + return m_headers; + } - Crt::List &&MessageAmendment::GetHeaders() && { return std::move(m_headers); } + Crt::List &&MessageAmendment::GetHeaders() && + { + return std::move(m_headers); + } - const Crt::Optional &MessageAmendment::GetPayload() const &noexcept { return m_payload; } + const Crt::Optional &MessageAmendment::GetPayload() const & noexcept + { + return m_payload; + } - Crt::Optional &&MessageAmendment::GetPayload() && { return std::move(m_payload); } + Crt::Optional &&MessageAmendment::GetPayload() && + { + return std::move(m_payload); + } void MessageAmendment::AddHeader(EventStreamHeader &&header) noexcept { @@ -139,7 +151,10 @@ namespace Aws } } - void MessageAmendment::SetPayload(Crt::Optional &&payload) { m_payload = std::move(payload); } + void MessageAmendment::SetPayload(Crt::Optional &&payload) + { + m_payload = std::move(payload); + } MessageAmendment::~MessageAmendment() noexcept { @@ -263,7 +278,10 @@ namespace Aws void ConnectionLifecycleHandler::OnConnectCallback() {} - void ConnectionLifecycleHandler::OnDisconnectCallback(RpcError error) { (void)error; } + void ConnectionLifecycleHandler::OnDisconnectCallback(RpcError error) + { + (void)error; + } Crt::String RpcError::StatusToString() { @@ -1129,7 +1147,10 @@ namespace Aws { } - void OperationError::SerializeToJsonObject(Crt::JsonObject &payloadObject) const { (void)payloadObject; } + void OperationError::SerializeToJsonObject(Crt::JsonObject &payloadObject) const + { + (void)payloadObject; + } AbstractShapeBase::AbstractShapeBase() noexcept : m_allocator(nullptr) {} @@ -1217,7 +1238,10 @@ namespace Aws rhs.m_rpcError = {EVENT_STREAM_RPC_UNINITIALIZED, 0}; } - TaggedResult::operator bool() const noexcept { return m_responseType == OPERATION_RESPONSE; } + TaggedResult::operator bool() const noexcept + { + return m_responseType == OPERATION_RESPONSE; + } AbstractShapeBase *TaggedResult::GetOperationResponse() const noexcept { @@ -1546,7 +1570,10 @@ namespace Aws } } - void ClientOperation::WithLaunchMode(std::launch mode) noexcept { m_asyncLaunchMode = mode; } + void ClientOperation::WithLaunchMode(std::launch mode) noexcept + { + m_asyncLaunchMode = mode; + } std::future ClientOperation::Close(OnMessageFlushCallback onMessageFlushCallback) noexcept { diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index ddb0b2027..456a3368d 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -33,12 +33,18 @@ set(TEST_BINARY_NAME ${PROJECT_NAME}-tests) add_test_case(EventStreamConnectSuccess) add_test_case(EventStreamConnectFailureNoAuthHeader) add_test_case(EventStreamConnectFailureBadAuthHeader) + add_test_case(EchoClientConnectSuccess) +add_test_case(EchoClientDoubleClose) +add_test_case(EchoClientMultiConnectSuccessFail) + +add_test_case(EchoClientOperationEchoSuccessString) +add_test_case(EchoClientOperationEchoSuccessMultiple) +add_test_case(EchoClientOperationEchoFailureNeverConnected) +add_test_case(EchoClientOperationEchoFailureDisconnected) + + -#add_test_case(OperateWhileDisconnected) -# The tests below can be commented out when an EchoRPC Server is running on 127.0.0.1:8033 -#add_test_case(EventStreamConnect) -#add_test_case(EchoOperation) #add_test_case(StressTestClient) generate_cpp_test_driver(${TEST_BINARY_NAME}) aws_add_sanitizers(${TEST_BINARY_NAME}) diff --git a/eventstream_rpc/tests/EchoTestRpcClient.cpp b/eventstream_rpc/tests/EchoTestRpcClient.cpp index 508e13fcb..05fe07477 100644 --- a/eventstream_rpc/tests/EchoTestRpcClient.cpp +++ b/eventstream_rpc/tests/EchoTestRpcClient.cpp @@ -28,11 +28,20 @@ namespace Awstest return m_connection.Connect(connectionConfig, &lifecycleHandler, m_clientBootstrap); } - void EchoTestRpcClient::Close() noexcept { m_connection.Close(); } + void EchoTestRpcClient::Close() noexcept + { + m_connection.Close(); + } - void EchoTestRpcClient::WithLaunchMode(std::launch mode) noexcept { m_asyncLaunchMode = mode; } + void EchoTestRpcClient::WithLaunchMode(std::launch mode) noexcept + { + m_asyncLaunchMode = mode; + } - EchoTestRpcClient::~EchoTestRpcClient() noexcept { Close(); } + EchoTestRpcClient::~EchoTestRpcClient() noexcept + { + Close(); + } std::shared_ptr EchoTestRpcClient::NewGetAllProducts() noexcept { diff --git a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h index 652da3f4a..5884b7172 100644 --- a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h +++ b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h @@ -29,11 +29,11 @@ namespace Aws void SetKey(const Aws::Crt::String &key) noexcept { m_key = key; } - Aws::Crt::Optional GetKey() noexcept { return m_key; } + Aws::Crt::Optional GetKey() const noexcept { return m_key; } void SetValue(const Aws::Crt::String &value) noexcept { m_value = value; } - Aws::Crt::Optional GetValue() noexcept { return m_value; } + Aws::Crt::Optional GetValue() const noexcept { return m_value; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(UserProperty &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -77,7 +77,7 @@ namespace Aws /** * The topic where the message was published. */ - Aws::Crt::Optional GetTopic() noexcept { return m_topic; } + Aws::Crt::Optional GetTopic() const noexcept { return m_topic; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(MessageContext &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -123,7 +123,7 @@ namespace Aws /** * The detailed deployment status of the local deployment. */ - Aws::Crt::Optional GetDetailedDeploymentStatus() noexcept; + Aws::Crt::Optional GetDetailedDeploymentStatus() const noexcept; /** * (Optional) The list of local deployment errors */ @@ -134,7 +134,7 @@ namespace Aws /** * (Optional) The list of local deployment errors */ - Aws::Crt::Optional> GetDeploymentErrorStack() noexcept + Aws::Crt::Optional> GetDeploymentErrorStack() const noexcept { return m_deploymentErrorStack; } @@ -148,7 +148,7 @@ namespace Aws /** * (Optional) The list of local deployment error types */ - Aws::Crt::Optional> GetDeploymentErrorTypes() noexcept + Aws::Crt::Optional> GetDeploymentErrorTypes() const noexcept { return m_deploymentErrorTypes; } @@ -162,7 +162,7 @@ namespace Aws /** * (Optional) The cause of local deployment failure */ - Aws::Crt::Optional GetDeploymentFailureCause() noexcept + Aws::Crt::Optional GetDeploymentFailureCause() const noexcept { return m_deploymentFailureCause; } @@ -221,7 +221,7 @@ namespace Aws * (Optional) The maximum amount of RAM (in kilobytes) that this component's processes can use on the core * device. */ - Aws::Crt::Optional GetMemory() noexcept { return m_memory; } + Aws::Crt::Optional GetMemory() const noexcept { return m_memory; } /** * (Optional) The maximum amount of CPU time that this component's processes can use on the core device. */ @@ -229,7 +229,7 @@ namespace Aws /** * (Optional) The maximum amount of CPU time that this component's processes can use on the core device. */ - Aws::Crt::Optional GetCpus() noexcept { return m_cpus; } + Aws::Crt::Optional GetCpus() const noexcept { return m_cpus; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(SystemResourceLimits &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -263,7 +263,7 @@ namespace Aws /** * The object that contains the new configuration. */ - Aws::Crt::Optional GetConfiguration() noexcept { return m_configuration; } + Aws::Crt::Optional GetConfiguration() const noexcept { return m_configuration; } /** * The ID of the AWS IoT Greengrass deployment that updates the component. */ @@ -271,7 +271,7 @@ namespace Aws /** * The ID of the AWS IoT Greengrass deployment that updates the component. */ - Aws::Crt::Optional GetDeploymentId() noexcept { return m_deploymentId; } + Aws::Crt::Optional GetDeploymentId() const noexcept { return m_deploymentId; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ValidateConfigurationUpdateEvent &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -302,7 +302,7 @@ namespace Aws /** * The binary message as a blob. */ - Aws::Crt::Optional> GetMessage() noexcept { return m_message; } + Aws::Crt::Optional> GetMessage() const noexcept { return m_message; } /** * The context of the message, such as the topic where the message was published. */ @@ -310,7 +310,7 @@ namespace Aws /** * The context of the message, such as the topic where the message was published. */ - Aws::Crt::Optional GetContext() noexcept { return m_context; } + Aws::Crt::Optional GetContext() const noexcept { return m_context; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(BinaryMessage &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -341,7 +341,7 @@ namespace Aws /** * The JSON message as an object. */ - Aws::Crt::Optional GetMessage() noexcept { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept { return m_message; } /** * The context of the message, such as the topic where the message was published. */ @@ -349,7 +349,7 @@ namespace Aws /** * The context of the message, such as the topic where the message was published. */ - Aws::Crt::Optional GetContext() noexcept { return m_context; } + Aws::Crt::Optional GetContext() const noexcept { return m_context; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(JsonMessage &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -380,7 +380,7 @@ namespace Aws /** * The topic to which the message was published. */ - Aws::Crt::Optional GetTopicName() noexcept { return m_topicName; } + Aws::Crt::Optional GetTopicName() const noexcept { return m_topicName; } /** * (Optional) The message payload as a blob. */ @@ -388,7 +388,7 @@ namespace Aws /** * (Optional) The message payload as a blob. */ - Aws::Crt::Optional> GetPayload() noexcept { return m_payload; } + Aws::Crt::Optional> GetPayload() const noexcept { return m_payload; } /** * (Optional) The value of the retain flag. */ @@ -396,7 +396,7 @@ namespace Aws /** * (Optional) The value of the retain flag. */ - Aws::Crt::Optional GetRetain() noexcept { return m_retain; } + Aws::Crt::Optional GetRetain() const noexcept { return m_retain; } /** * (Optional) MQTT user properties associated with the message. */ @@ -407,7 +407,10 @@ namespace Aws /** * (Optional) MQTT user properties associated with the message. */ - Aws::Crt::Optional> GetUserProperties() noexcept { return m_userProperties; } + Aws::Crt::Optional> GetUserProperties() const noexcept + { + return m_userProperties; + } /** * (Optional) Message expiry interval in seconds. */ @@ -418,7 +421,7 @@ namespace Aws /** * (Optional) Message expiry interval in seconds. */ - Aws::Crt::Optional GetMessageExpiryIntervalSeconds() noexcept + Aws::Crt::Optional GetMessageExpiryIntervalSeconds() const noexcept { return m_messageExpiryIntervalSeconds; } @@ -432,7 +435,10 @@ namespace Aws /** * (Optional) Correlation data blob for request/response. */ - Aws::Crt::Optional> GetCorrelationData() noexcept { return m_correlationData; } + Aws::Crt::Optional> GetCorrelationData() const noexcept + { + return m_correlationData; + } /** * (Optional) Response topic for request/response. */ @@ -440,7 +446,7 @@ namespace Aws /** * (Optional) Response topic for request/response. */ - Aws::Crt::Optional GetResponseTopic() noexcept { return m_responseTopic; } + Aws::Crt::Optional GetResponseTopic() const noexcept { return m_responseTopic; } /** * (Optional) Message payload format. */ @@ -448,7 +454,7 @@ namespace Aws /** * (Optional) Message payload format. */ - Aws::Crt::Optional GetPayloadFormat() noexcept; + Aws::Crt::Optional GetPayloadFormat() const noexcept; /** * (Optional) Message content type. */ @@ -456,7 +462,7 @@ namespace Aws /** * (Optional) Message content type. */ - Aws::Crt::Optional GetContentType() noexcept { return m_contentType; } + Aws::Crt::Optional GetContentType() const noexcept { return m_contentType; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(MQTTMessage &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -494,7 +500,7 @@ namespace Aws /** * The name of the component. */ - Aws::Crt::Optional GetComponentName() noexcept { return m_componentName; } + Aws::Crt::Optional GetComponentName() const noexcept { return m_componentName; } /** * The key path to the configuration value that updated. */ @@ -502,7 +508,7 @@ namespace Aws /** * The key path to the configuration value that updated. */ - Aws::Crt::Optional> GetKeyPath() noexcept { return m_keyPath; } + Aws::Crt::Optional> GetKeyPath() const noexcept { return m_keyPath; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ConfigurationUpdateEvent &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -533,7 +539,7 @@ namespace Aws /** * The ID of the AWS IoT Greengrass deployment that updated the component. */ - Aws::Crt::Optional GetDeploymentId() noexcept { return m_deploymentId; } + Aws::Crt::Optional GetDeploymentId() const noexcept { return m_deploymentId; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(PostComponentUpdateEvent &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -563,7 +569,7 @@ namespace Aws /** * The ID of the AWS IoT Greengrass deployment that updates the component. */ - Aws::Crt::Optional GetDeploymentId() noexcept { return m_deploymentId; } + Aws::Crt::Optional GetDeploymentId() const noexcept { return m_deploymentId; } /** * Whether or not Greengrass needs to restart to apply the update. */ @@ -571,7 +577,7 @@ namespace Aws /** * Whether or not Greengrass needs to restart to apply the update. */ - Aws::Crt::Optional GetIsGgcRestarting() noexcept { return m_isGgcRestarting; } + Aws::Crt::Optional GetIsGgcRestarting() const noexcept { return m_isGgcRestarting; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(PreComponentUpdateEvent &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -602,7 +608,7 @@ namespace Aws /** * The private key in pem format. */ - Aws::Crt::Optional GetPrivateKey() noexcept { return m_privateKey; } + Aws::Crt::Optional GetPrivateKey() const noexcept { return m_privateKey; } /** * The public key in pem format. */ @@ -610,7 +616,7 @@ namespace Aws /** * The public key in pem format. */ - Aws::Crt::Optional GetPublicKey() noexcept { return m_publicKey; } + Aws::Crt::Optional GetPublicKey() const noexcept { return m_publicKey; } /** * The certificate in pem format. */ @@ -618,7 +624,7 @@ namespace Aws /** * The certificate in pem format. */ - Aws::Crt::Optional GetCertificate() noexcept { return m_certificate; } + Aws::Crt::Optional GetCertificate() const noexcept { return m_certificate; } /** * List of CA certificates in pem format. */ @@ -629,7 +635,7 @@ namespace Aws /** * List of CA certificates in pem format. */ - Aws::Crt::Optional> GetCaCertificates() noexcept + Aws::Crt::Optional> GetCaCertificates() const noexcept { return m_caCertificates; } @@ -672,15 +678,15 @@ namespace Aws void SetName(const Aws::Crt::String &name) noexcept { m_name = name; } - Aws::Crt::Optional GetName() noexcept { return m_name; } + Aws::Crt::Optional GetName() const noexcept { return m_name; } void SetUnit(MetricUnitType unit) noexcept; - Aws::Crt::Optional GetUnit() noexcept; + Aws::Crt::Optional GetUnit() const noexcept; void SetValue(const double &value) noexcept { m_value = value; } - Aws::Crt::Optional GetValue() noexcept { return m_value; } + Aws::Crt::Optional GetValue() const noexcept { return m_value; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(Metric &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -712,7 +718,7 @@ namespace Aws /** * The ID of the local deployment. */ - Aws::Crt::Optional GetDeploymentId() noexcept { return m_deploymentId; } + Aws::Crt::Optional GetDeploymentId() const noexcept { return m_deploymentId; } /** * The status of the local deployment. */ @@ -720,7 +726,7 @@ namespace Aws /** * The status of the local deployment. */ - Aws::Crt::Optional GetStatus() noexcept; + Aws::Crt::Optional GetStatus() const noexcept; /** * (Optional) The timestamp at which the local deployment was created in MM/dd/yyyy hh:mm:ss format */ @@ -728,7 +734,7 @@ namespace Aws /** * (Optional) The timestamp at which the local deployment was created in MM/dd/yyyy hh:mm:ss format */ - Aws::Crt::Optional GetCreatedOn() noexcept { return m_createdOn; } + Aws::Crt::Optional GetCreatedOn() const noexcept { return m_createdOn; } /** * (Optional) The status details of the local deployment. */ @@ -739,7 +745,7 @@ namespace Aws /** * (Optional) The status details of the local deployment. */ - Aws::Crt::Optional GetDeploymentStatusDetails() noexcept + Aws::Crt::Optional GetDeploymentStatusDetails() const noexcept { return m_deploymentStatusDetails; } @@ -775,7 +781,7 @@ namespace Aws /** * The name of the component. */ - Aws::Crt::Optional GetComponentName() noexcept { return m_componentName; } + Aws::Crt::Optional GetComponentName() const noexcept { return m_componentName; } /** * The version of the component. */ @@ -783,7 +789,7 @@ namespace Aws /** * The version of the component. */ - Aws::Crt::Optional GetVersion() noexcept { return m_version; } + Aws::Crt::Optional GetVersion() const noexcept { return m_version; } /** * The state of the component. */ @@ -791,7 +797,7 @@ namespace Aws /** * The state of the component. */ - Aws::Crt::Optional GetState() noexcept; + Aws::Crt::Optional GetState() const noexcept; /** * The component's configuration as a JSON object. */ @@ -802,7 +808,7 @@ namespace Aws /** * The component's configuration as a JSON object. */ - Aws::Crt::Optional GetConfiguration() noexcept { return m_configuration; } + Aws::Crt::Optional GetConfiguration() const noexcept { return m_configuration; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ComponentDetails &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -835,7 +841,7 @@ namespace Aws /** * The client ID to used to connect. */ - Aws::Crt::Optional GetClientId() noexcept { return m_clientId; } + Aws::Crt::Optional GetClientId() const noexcept { return m_clientId; } /** * The client certificate in pem format. */ @@ -846,7 +852,7 @@ namespace Aws /** * The client certificate in pem format. */ - Aws::Crt::Optional GetCertificatePem() noexcept { return m_certificatePem; } + Aws::Crt::Optional GetCertificatePem() const noexcept { return m_certificatePem; } /** * The username. (unused). */ @@ -854,7 +860,7 @@ namespace Aws /** * The username. (unused). */ - Aws::Crt::Optional GetUsername() noexcept { return m_username; } + Aws::Crt::Optional GetUsername() const noexcept { return m_username; } /** * The password. (unused). */ @@ -862,7 +868,7 @@ namespace Aws /** * The password. (unused). */ - Aws::Crt::Optional GetPassword() noexcept { return m_password; } + Aws::Crt::Optional GetPassword() const noexcept { return m_password; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(MQTTCredential &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -897,7 +903,7 @@ namespace Aws * (Optional) The POSIX system user and, optionally, group to use to run this component on Linux core * devices. */ - Aws::Crt::Optional GetPosixUser() noexcept { return m_posixUser; } + Aws::Crt::Optional GetPosixUser() const noexcept { return m_posixUser; } /** * (Optional) The Windows user to use to run this component on Windows core devices. */ @@ -905,7 +911,7 @@ namespace Aws /** * (Optional) The Windows user to use to run this component on Windows core devices. */ - Aws::Crt::Optional GetWindowsUser() noexcept { return m_windowsUser; } + Aws::Crt::Optional GetWindowsUser() const noexcept { return m_windowsUser; } /** * (Optional) The system resource limits to apply to this component's processes. */ @@ -916,7 +922,7 @@ namespace Aws /** * (Optional) The system resource limits to apply to this component's processes. */ - Aws::Crt::Optional GetSystemResourceLimits() noexcept + Aws::Crt::Optional GetSystemResourceLimits() const noexcept { return m_systemResourceLimits; } @@ -956,7 +962,7 @@ namespace Aws /** * The client device's X.509 device certificate. */ - Aws::Crt::Optional GetClientDeviceCertificate() noexcept + Aws::Crt::Optional GetClientDeviceCertificate() const noexcept { if (m_chosenMember == TAG_CLIENT_DEVICE_CERTIFICATE) { @@ -1015,7 +1021,7 @@ namespace Aws /** * The configuration update event. */ - Aws::Crt::Optional GetValidateConfigurationUpdateEvent() noexcept + Aws::Crt::Optional GetValidateConfigurationUpdateEvent() const noexcept { if (m_chosenMember == TAG_VALIDATE_CONFIGURATION_UPDATE_EVENT) { @@ -1064,7 +1070,7 @@ namespace Aws /** * (Optional) A JSON message. */ - Aws::Crt::Optional GetJsonMessage() noexcept + Aws::Crt::Optional GetJsonMessage() const noexcept { if (m_chosenMember == TAG_JSON_MESSAGE) { @@ -1086,7 +1092,7 @@ namespace Aws /** * (Optional) A binary message. */ - Aws::Crt::Optional GetBinaryMessage() noexcept + Aws::Crt::Optional GetBinaryMessage() const noexcept { if (m_chosenMember == TAG_BINARY_MESSAGE) { @@ -1143,7 +1149,7 @@ namespace Aws /** * The MQTT message. */ - Aws::Crt::Optional GetMessage() noexcept + Aws::Crt::Optional GetMessage() const noexcept { if (m_chosenMember == TAG_MESSAGE) { @@ -1198,7 +1204,7 @@ namespace Aws /** * The configuration update event. */ - Aws::Crt::Optional GetConfigurationUpdateEvent() noexcept + Aws::Crt::Optional GetConfigurationUpdateEvent() const noexcept { if (m_chosenMember == TAG_CONFIGURATION_UPDATE_EVENT) { @@ -1247,7 +1253,7 @@ namespace Aws /** * An event that indicates that the Greengrass wants to update a component. */ - Aws::Crt::Optional GetPreUpdateEvent() noexcept + Aws::Crt::Optional GetPreUpdateEvent() const noexcept { if (m_chosenMember == TAG_PRE_UPDATE_EVENT) { @@ -1269,7 +1275,7 @@ namespace Aws /** * An event that indicates that the nucleus updated a component. */ - Aws::Crt::Optional GetPostUpdateEvent() noexcept + Aws::Crt::Optional GetPostUpdateEvent() const noexcept { if (m_chosenMember == TAG_POST_UPDATE_EVENT) { @@ -1320,7 +1326,7 @@ namespace Aws /** * The information about the new certificate. */ - Aws::Crt::Optional GetCertificateUpdate() noexcept + Aws::Crt::Optional GetCertificateUpdate() const noexcept { if (m_chosenMember == TAG_CERTIFICATE_UPDATE) { @@ -1364,7 +1370,7 @@ namespace Aws /** * The types of certificate updates to subscribe to. */ - Aws::Crt::Optional GetCertificateType() noexcept; + Aws::Crt::Optional GetCertificateType() const noexcept; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(CertificateOptions &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -1400,7 +1406,7 @@ namespace Aws /** * The validity status. */ - Aws::Crt::Optional GetStatus() noexcept; + Aws::Crt::Optional GetStatus() const noexcept; /** * The ID of the AWS IoT Greengrass deployment that requested the configuration update. */ @@ -1408,7 +1414,7 @@ namespace Aws /** * The ID of the AWS IoT Greengrass deployment that requested the configuration update. */ - Aws::Crt::Optional GetDeploymentId() noexcept { return m_deploymentId; } + Aws::Crt::Optional GetDeploymentId() const noexcept { return m_deploymentId; } /** * (Optional) A message that reports why the configuration isn't valid. */ @@ -1416,7 +1422,7 @@ namespace Aws /** * (Optional) A message that reports why the configuration isn't valid. */ - Aws::Crt::Optional GetMessage() noexcept { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ConfigurationValidityReport &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -1453,7 +1459,7 @@ namespace Aws /** * (Optional) A JSON message. */ - Aws::Crt::Optional GetJsonMessage() noexcept + Aws::Crt::Optional GetJsonMessage() const noexcept { if (m_chosenMember == TAG_JSON_MESSAGE) { @@ -1475,7 +1481,7 @@ namespace Aws /** * (Optional) A binary message. */ - Aws::Crt::Optional GetBinaryMessage() noexcept + Aws::Crt::Optional GetBinaryMessage() const noexcept { if (m_chosenMember == TAG_BINARY_MESSAGE) { @@ -1526,7 +1532,7 @@ namespace Aws /** * The decrypted part of the protected secret information that you provided to Secrets Manager as a string. */ - Aws::Crt::Optional GetSecretString() noexcept + Aws::Crt::Optional GetSecretString() const noexcept { if (m_chosenMember == TAG_SECRET_STRING) { @@ -1550,7 +1556,7 @@ namespace Aws * (Optional) The decrypted part of the protected secret information that you provided to Secrets Manager as * binary data in the form of a byte array. */ - Aws::Crt::Optional> GetSecretBinary() noexcept + Aws::Crt::Optional> GetSecretBinary() const noexcept { if (m_chosenMember == TAG_SECRET_BINARY) { @@ -1603,7 +1609,7 @@ namespace Aws * The client device's MQTT credentials. Specify the client ID and certificate that the client device uses * to connect. */ - Aws::Crt::Optional GetMqttCredential() noexcept + Aws::Crt::Optional GetMqttCredential() const noexcept { if (m_chosenMember == TAG_MQTT_CREDENTIAL) { @@ -1649,7 +1655,7 @@ namespace Aws void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } - Aws::Crt::Optional GetMessage() noexcept override { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept override { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(InvalidArgumentsError &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -1675,11 +1681,11 @@ namespace Aws void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } - Aws::Crt::Optional GetMessage() noexcept override { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept override { return m_message; } void SetContext(const Aws::Crt::JsonObject &context) noexcept { m_context = context; } - Aws::Crt::Optional GetContext() noexcept { return m_context; } + Aws::Crt::Optional GetContext() const noexcept { return m_context; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ServiceError &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -1706,7 +1712,7 @@ namespace Aws void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } - Aws::Crt::Optional GetMessage() noexcept override { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept override { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(UnauthorizedError &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -1739,7 +1745,7 @@ namespace Aws /** * Whether the client device's identity is valid. */ - Aws::Crt::Optional GetIsValidClientDevice() noexcept { return m_isValidClientDevice; } + Aws::Crt::Optional GetIsValidClientDevice() const noexcept { return m_isValidClientDevice; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(VerifyClientDeviceIdentityResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -1769,7 +1775,7 @@ namespace Aws /** * The client device's credentials. */ - Aws::Crt::Optional GetCredential() noexcept { return m_credential; } + Aws::Crt::Optional GetCredential() const noexcept { return m_credential; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(VerifyClientDeviceIdentityRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -1795,7 +1801,7 @@ namespace Aws void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } - Aws::Crt::Optional GetMessage() noexcept override { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept override { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(InvalidTokenError &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -1821,7 +1827,7 @@ namespace Aws void SetIsValid(const bool &isValid) noexcept { m_isValid = isValid; } - Aws::Crt::Optional GetIsValid() noexcept { return m_isValid; } + Aws::Crt::Optional GetIsValid() const noexcept { return m_isValid; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ValidateAuthorizationTokenResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -1847,7 +1853,7 @@ namespace Aws void SetToken(const Aws::Crt::String &token) noexcept { m_token = token; } - Aws::Crt::Optional GetToken() noexcept { return m_token; } + Aws::Crt::Optional GetToken() const noexcept { return m_token; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ValidateAuthorizationTokenRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -1873,7 +1879,7 @@ namespace Aws void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } - Aws::Crt::Optional GetMessage() noexcept override { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept override { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ConflictError &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -1903,7 +1909,7 @@ namespace Aws /** * The response state document as a JSON encoded blob. */ - Aws::Crt::Optional> GetPayload() noexcept { return m_payload; } + Aws::Crt::Optional> GetPayload() const noexcept { return m_payload; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(UpdateThingShadowResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -1933,7 +1939,7 @@ namespace Aws /** * The name of the thing. */ - Aws::Crt::Optional GetThingName() noexcept { return m_thingName; } + Aws::Crt::Optional GetThingName() const noexcept { return m_thingName; } /** * The name of the shadow. To specify the thing's classic shadow, set this parameter to an empty string * (""). @@ -1943,7 +1949,7 @@ namespace Aws * The name of the shadow. To specify the thing's classic shadow, set this parameter to an empty string * (""). */ - Aws::Crt::Optional GetShadowName() noexcept { return m_shadowName; } + Aws::Crt::Optional GetShadowName() const noexcept { return m_shadowName; } /** * The request state document as a JSON encoded blob. */ @@ -1951,7 +1957,7 @@ namespace Aws /** * The request state document as a JSON encoded blob. */ - Aws::Crt::Optional> GetPayload() noexcept { return m_payload; } + Aws::Crt::Optional> GetPayload() const noexcept { return m_payload; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(UpdateThingShadowRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -1979,15 +1985,15 @@ namespace Aws void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } - Aws::Crt::Optional GetMessage() noexcept override { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept override { return m_message; } void SetResourceType(const Aws::Crt::String &resourceType) noexcept { m_resourceType = resourceType; } - Aws::Crt::Optional GetResourceType() noexcept { return m_resourceType; } + Aws::Crt::Optional GetResourceType() const noexcept { return m_resourceType; } void SetResourceName(const Aws::Crt::String &resourceName) noexcept { m_resourceName = resourceName; } - Aws::Crt::Optional GetResourceName() noexcept { return m_resourceName; } + Aws::Crt::Optional GetResourceName() const noexcept { return m_resourceName; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ResourceNotFoundError &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2040,7 +2046,7 @@ namespace Aws /** * The state to set this component to. */ - Aws::Crt::Optional GetState() noexcept; + Aws::Crt::Optional GetState() const noexcept; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(UpdateStateRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2066,7 +2072,7 @@ namespace Aws void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } - Aws::Crt::Optional GetMessage() noexcept override { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept override { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(FailedUpdateConditionCheckError &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2119,7 +2125,7 @@ namespace Aws * (Optional) The key path to the container node (the object) to update. Specify a list where each entry is * the key for a single level in the configuration object. Defaults to the root of the configuration object. */ - Aws::Crt::Optional> GetKeyPath() noexcept { return m_keyPath; } + Aws::Crt::Optional> GetKeyPath() const noexcept { return m_keyPath; } /** * The current Unix epoch time in milliseconds. This operation uses this timestamp to resolve concurrent * updates to the key. If the key in the component configuration has a greater timestamp than the timestamp @@ -2131,7 +2137,7 @@ namespace Aws * updates to the key. If the key in the component configuration has a greater timestamp than the timestamp * in the request, then the request fails. */ - Aws::Crt::Optional GetTimestamp() noexcept { return m_timestamp; } + Aws::Crt::Optional GetTimestamp() const noexcept { return m_timestamp; } /** * The configuration object to merge at the location that you specify in keyPath. */ @@ -2139,7 +2145,7 @@ namespace Aws /** * The configuration object to merge at the location that you specify in keyPath. */ - Aws::Crt::Optional GetValueToMerge() noexcept { return m_valueToMerge; } + Aws::Crt::Optional GetValueToMerge() const noexcept { return m_valueToMerge; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(UpdateConfigurationRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2221,7 +2227,7 @@ namespace Aws /** * @deprecated No longer used */ - Aws::Crt::Optional GetTopicName() noexcept { return m_topicName; } + Aws::Crt::Optional GetTopicName() const noexcept { return m_topicName; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(SubscribeToTopicResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2251,7 +2257,7 @@ namespace Aws /** * The topic to subscribe to. Supports MQTT-style wildcards. */ - Aws::Crt::Optional GetTopic() noexcept { return m_topic; } + Aws::Crt::Optional GetTopic() const noexcept { return m_topic; } /** * (Optional) The behavior that specifies whether the component receives messages from itself. */ @@ -2259,7 +2265,7 @@ namespace Aws /** * (Optional) The behavior that specifies whether the component receives messages from itself. */ - Aws::Crt::Optional GetReceiveMode() noexcept; + Aws::Crt::Optional GetReceiveMode() const noexcept; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(SubscribeToTopicRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2311,7 +2317,7 @@ namespace Aws /** * The topic to which to subscribe. Supports MQTT wildcards. */ - Aws::Crt::Optional GetTopicName() noexcept { return m_topicName; } + Aws::Crt::Optional GetTopicName() const noexcept { return m_topicName; } /** * The MQTT QoS to use. */ @@ -2319,7 +2325,7 @@ namespace Aws /** * The MQTT QoS to use. */ - Aws::Crt::Optional GetQos() noexcept; + Aws::Crt::Optional GetQos() const noexcept; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(SubscribeToIoTCoreRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2374,7 +2380,7 @@ namespace Aws /** * (Optional) The name of the component. Defaults to the name of the component that makes the request. */ - Aws::Crt::Optional GetComponentName() noexcept { return m_componentName; } + Aws::Crt::Optional GetComponentName() const noexcept { return m_componentName; } /** * The key path to the configuration value for which to subscribe. Specify a list where each entry is the * key for a single level in the configuration object. @@ -2384,7 +2390,7 @@ namespace Aws * The key path to the configuration value for which to subscribe. Specify a list where each entry is the * key for a single level in the configuration object. */ - Aws::Crt::Optional> GetKeyPath() noexcept { return m_keyPath; } + Aws::Crt::Optional> GetKeyPath() const noexcept { return m_keyPath; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView( SubscribeToConfigurationUpdateRequest &, @@ -2481,7 +2487,10 @@ namespace Aws m_certificateOptions = certificateOptions; } - Aws::Crt::Optional GetCertificateOptions() noexcept { return m_certificateOptions; } + Aws::Crt::Optional GetCertificateOptions() const noexcept + { + return m_certificateOptions; + } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(SubscribeToCertificateUpdatesRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2507,7 +2516,7 @@ namespace Aws void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } - Aws::Crt::Optional GetMessage() noexcept override { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept override { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ComponentNotFoundError &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2537,7 +2546,7 @@ namespace Aws /** * The status of the stop request. */ - Aws::Crt::Optional GetStopStatus() noexcept; + Aws::Crt::Optional GetStopStatus() const noexcept; /** * A message about why the component failed to stop, if the request failed. */ @@ -2545,7 +2554,7 @@ namespace Aws /** * A message about why the component failed to stop, if the request failed. */ - Aws::Crt::Optional GetMessage() noexcept { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(StopComponentResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2576,7 +2585,7 @@ namespace Aws /** * The name of the component. */ - Aws::Crt::Optional GetComponentName() noexcept { return m_componentName; } + Aws::Crt::Optional GetComponentName() const noexcept { return m_componentName; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(StopComponentRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2633,7 +2642,7 @@ namespace Aws /** * The report that tells Greengrass whether or not the configuration update is valid. */ - Aws::Crt::Optional GetConfigurationValidityReport() noexcept + Aws::Crt::Optional GetConfigurationValidityReport() const noexcept { return m_configurationValidityReport; } @@ -2690,7 +2699,7 @@ namespace Aws /** * The name of the component to resume. */ - Aws::Crt::Optional GetComponentName() noexcept { return m_componentName; } + Aws::Crt::Optional GetComponentName() const noexcept { return m_componentName; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ResumeComponentRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2720,7 +2729,7 @@ namespace Aws /** * The status of the restart request. */ - Aws::Crt::Optional GetRestartStatus() noexcept; + Aws::Crt::Optional GetRestartStatus() const noexcept; /** * A message about why the component failed to restart, if the request failed. */ @@ -2728,7 +2737,7 @@ namespace Aws /** * A message about why the component failed to restart, if the request failed. */ - Aws::Crt::Optional GetMessage() noexcept { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(RestartComponentResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2759,7 +2768,7 @@ namespace Aws /** * The name of the component. */ - Aws::Crt::Optional GetComponentName() noexcept { return m_componentName; } + Aws::Crt::Optional GetComponentName() const noexcept { return m_componentName; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(RestartComponentRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2806,7 +2815,7 @@ namespace Aws void SetMetrics(const Aws::Crt::Vector &metrics) noexcept { m_metrics = metrics; } - Aws::Crt::Optional> GetMetrics() noexcept { return m_metrics; } + Aws::Crt::Optional> GetMetrics() const noexcept { return m_metrics; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(PutComponentMetricRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2857,7 +2866,7 @@ namespace Aws /** * The topic to publish the message. */ - Aws::Crt::Optional GetTopic() noexcept { return m_topic; } + Aws::Crt::Optional GetTopic() const noexcept { return m_topic; } /** * The message to publish. */ @@ -2865,7 +2874,7 @@ namespace Aws /** * The message to publish. */ - Aws::Crt::Optional GetPublishMessage() noexcept { return m_publishMessage; } + Aws::Crt::Optional GetPublishMessage() const noexcept { return m_publishMessage; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(PublishToTopicRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -2917,7 +2926,7 @@ namespace Aws /** * The topic to which to publish the message. */ - Aws::Crt::Optional GetTopicName() noexcept { return m_topicName; } + Aws::Crt::Optional GetTopicName() const noexcept { return m_topicName; } /** * The MQTT QoS to use. */ @@ -2925,7 +2934,7 @@ namespace Aws /** * The MQTT QoS to use. */ - Aws::Crt::Optional GetQos() noexcept; + Aws::Crt::Optional GetQos() const noexcept; /** * (Optional) The message payload as a blob. */ @@ -2933,7 +2942,7 @@ namespace Aws /** * (Optional) The message payload as a blob. */ - Aws::Crt::Optional> GetPayload() noexcept { return m_payload; } + Aws::Crt::Optional> GetPayload() const noexcept { return m_payload; } /** * (Optional) Whether to set MQTT retain option to true when publishing. */ @@ -2941,7 +2950,7 @@ namespace Aws /** * (Optional) Whether to set MQTT retain option to true when publishing. */ - Aws::Crt::Optional GetRetain() noexcept { return m_retain; } + Aws::Crt::Optional GetRetain() const noexcept { return m_retain; } /** * (Optional) MQTT user properties associated with the message. */ @@ -2952,7 +2961,10 @@ namespace Aws /** * (Optional) MQTT user properties associated with the message. */ - Aws::Crt::Optional> GetUserProperties() noexcept { return m_userProperties; } + Aws::Crt::Optional> GetUserProperties() const noexcept + { + return m_userProperties; + } /** * (Optional) Message expiry interval in seconds. */ @@ -2963,7 +2975,7 @@ namespace Aws /** * (Optional) Message expiry interval in seconds. */ - Aws::Crt::Optional GetMessageExpiryIntervalSeconds() noexcept + Aws::Crt::Optional GetMessageExpiryIntervalSeconds() const noexcept { return m_messageExpiryIntervalSeconds; } @@ -2977,7 +2989,10 @@ namespace Aws /** * (Optional) Correlation data blob for request/response. */ - Aws::Crt::Optional> GetCorrelationData() noexcept { return m_correlationData; } + Aws::Crt::Optional> GetCorrelationData() const noexcept + { + return m_correlationData; + } /** * (Optional) Response topic for request/response. */ @@ -2985,7 +3000,7 @@ namespace Aws /** * (Optional) Response topic for request/response. */ - Aws::Crt::Optional GetResponseTopic() noexcept { return m_responseTopic; } + Aws::Crt::Optional GetResponseTopic() const noexcept { return m_responseTopic; } /** * (Optional) Message payload format. */ @@ -2993,7 +3008,7 @@ namespace Aws /** * (Optional) Message payload format. */ - Aws::Crt::Optional GetPayloadFormat() noexcept; + Aws::Crt::Optional GetPayloadFormat() const noexcept; /** * (Optional) Message content type. */ @@ -3001,7 +3016,7 @@ namespace Aws /** * (Optional) Message content type. */ - Aws::Crt::Optional GetContentType() noexcept { return m_contentType; } + Aws::Crt::Optional GetContentType() const noexcept { return m_contentType; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(PublishToIoTCoreRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3061,7 +3076,7 @@ namespace Aws /** * The name of the component to pause, which must be a generic component. */ - Aws::Crt::Optional GetComponentName() noexcept { return m_componentName; } + Aws::Crt::Optional GetComponentName() const noexcept { return m_componentName; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(PauseComponentRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3091,7 +3106,7 @@ namespace Aws /** * The list of shadow names. */ - Aws::Crt::Optional> GetResults() noexcept { return m_results; } + Aws::Crt::Optional> GetResults() const noexcept { return m_results; } /** * (Optional) The date and time that the response was generated. */ @@ -3099,7 +3114,7 @@ namespace Aws /** * (Optional) The date and time that the response was generated. */ - Aws::Crt::Optional GetTimestamp() noexcept { return m_timestamp; } + Aws::Crt::Optional GetTimestamp() const noexcept { return m_timestamp; } /** * (Optional) The token value to use in paged requests to retrieve the next page in the sequence. This token * isn't present when there are no more shadow names to return. @@ -3109,7 +3124,7 @@ namespace Aws * (Optional) The token value to use in paged requests to retrieve the next page in the sequence. This token * isn't present when there are no more shadow names to return. */ - Aws::Crt::Optional GetNextToken() noexcept { return m_nextToken; } + Aws::Crt::Optional GetNextToken() const noexcept { return m_nextToken; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ListNamedShadowsForThingResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3141,7 +3156,7 @@ namespace Aws /** * The name of the thing. */ - Aws::Crt::Optional GetThingName() noexcept { return m_thingName; } + Aws::Crt::Optional GetThingName() const noexcept { return m_thingName; } /** * (Optional) The token to retrieve the next set of results. This value is returned on paged results and is * used in the call that returns the next page. @@ -3151,7 +3166,7 @@ namespace Aws * (Optional) The token to retrieve the next set of results. This value is returned on paged results and is * used in the call that returns the next page. */ - Aws::Crt::Optional GetNextToken() noexcept { return m_nextToken; } + Aws::Crt::Optional GetNextToken() const noexcept { return m_nextToken; } /** * (Optional) The number of shadow names to return in each call. Value must be between 1 and 100. Default * is 25. @@ -3161,7 +3176,7 @@ namespace Aws * (Optional) The number of shadow names to return in each call. Value must be between 1 and 100. Default * is 25. */ - Aws::Crt::Optional GetPageSize() noexcept { return m_pageSize; } + Aws::Crt::Optional GetPageSize() const noexcept { return m_pageSize; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ListNamedShadowsForThingRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3196,7 +3211,7 @@ namespace Aws /** * The list of local deployments. */ - Aws::Crt::Optional> GetLocalDeployments() noexcept + Aws::Crt::Optional> GetLocalDeployments() const noexcept { return m_localDeployments; } @@ -3253,7 +3268,10 @@ namespace Aws /** * The list of components. */ - Aws::Crt::Optional> GetComponents() noexcept { return m_components; } + Aws::Crt::Optional> GetComponents() const noexcept + { + return m_components; + } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ListComponentsResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3304,7 +3322,7 @@ namespace Aws /** * The response state document as a JSON encoded blob. */ - Aws::Crt::Optional> GetPayload() noexcept { return m_payload; } + Aws::Crt::Optional> GetPayload() const noexcept { return m_payload; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetThingShadowResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3334,7 +3352,7 @@ namespace Aws /** * The name of the thing. */ - Aws::Crt::Optional GetThingName() noexcept { return m_thingName; } + Aws::Crt::Optional GetThingName() const noexcept { return m_thingName; } /** * The name of the shadow. To specify the thing's classic shadow, set this parameter to an empty string * (""). @@ -3344,7 +3362,7 @@ namespace Aws * The name of the shadow. To specify the thing's classic shadow, set this parameter to an empty string * (""). */ - Aws::Crt::Optional GetShadowName() noexcept { return m_shadowName; } + Aws::Crt::Optional GetShadowName() const noexcept { return m_shadowName; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetThingShadowRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3375,7 +3393,7 @@ namespace Aws /** * The ID of the secret. */ - Aws::Crt::Optional GetSecretId() noexcept { return m_secretId; } + Aws::Crt::Optional GetSecretId() const noexcept { return m_secretId; } /** * The ID of this version of the secret. */ @@ -3383,7 +3401,7 @@ namespace Aws /** * The ID of this version of the secret. */ - Aws::Crt::Optional GetVersionId() noexcept { return m_versionId; } + Aws::Crt::Optional GetVersionId() const noexcept { return m_versionId; } /** * The list of staging labels attached to this version of the secret. */ @@ -3394,7 +3412,10 @@ namespace Aws /** * The list of staging labels attached to this version of the secret. */ - Aws::Crt::Optional> GetVersionStage() noexcept { return m_versionStage; } + Aws::Crt::Optional> GetVersionStage() const noexcept + { + return m_versionStage; + } /** * The value of this version of the secret. */ @@ -3402,7 +3423,7 @@ namespace Aws /** * The value of this version of the secret. */ - Aws::Crt::Optional GetSecretValue() noexcept { return m_secretValue; } + Aws::Crt::Optional GetSecretValue() const noexcept { return m_secretValue; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetSecretValueResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3437,7 +3458,7 @@ namespace Aws * The name of the secret to get. You can specify either the Amazon Resource Name (ARN) or the friendly name * of the secret. */ - Aws::Crt::Optional GetSecretId() noexcept { return m_secretId; } + Aws::Crt::Optional GetSecretId() const noexcept { return m_secretId; } /** * (Optional) The ID of the version to get. If you don't specify versionId or versionStage, this operation * defaults to the version with the AWSCURRENT label. @@ -3447,7 +3468,7 @@ namespace Aws * (Optional) The ID of the version to get. If you don't specify versionId or versionStage, this operation * defaults to the version with the AWSCURRENT label. */ - Aws::Crt::Optional GetVersionId() noexcept { return m_versionId; } + Aws::Crt::Optional GetVersionId() const noexcept { return m_versionId; } /** * (Optional) The staging label of the version to get. If you don't specify versionId or versionStage, this * operation defaults to the version with the AWSCURRENT label. @@ -3457,7 +3478,7 @@ namespace Aws * (Optional) The staging label of the version to get. If you don't specify versionId or versionStage, this * operation defaults to the version with the AWSCURRENT label. */ - Aws::Crt::Optional GetVersionStage() noexcept { return m_versionStage; } + Aws::Crt::Optional GetVersionStage() const noexcept { return m_versionStage; } /** * (Optional) Whether to fetch the latest secret from cloud when the request is handled. Defaults to false. */ @@ -3465,7 +3486,7 @@ namespace Aws /** * (Optional) Whether to fetch the latest secret from cloud when the request is handled. Defaults to false. */ - Aws::Crt::Optional GetRefresh() noexcept { return m_refresh; } + Aws::Crt::Optional GetRefresh() const noexcept { return m_refresh; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetSecretValueRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3498,7 +3519,7 @@ namespace Aws /** * The local deployment. */ - Aws::Crt::Optional GetDeployment() noexcept { return m_deployment; } + Aws::Crt::Optional GetDeployment() const noexcept { return m_deployment; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetLocalDeploymentStatusResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3528,7 +3549,7 @@ namespace Aws /** * The ID of the local deployment to get. */ - Aws::Crt::Optional GetDeploymentId() noexcept { return m_deploymentId; } + Aws::Crt::Optional GetDeploymentId() const noexcept { return m_deploymentId; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetLocalDeploymentStatusRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3558,7 +3579,7 @@ namespace Aws /** * The name of the component. */ - Aws::Crt::Optional GetComponentName() noexcept { return m_componentName; } + Aws::Crt::Optional GetComponentName() const noexcept { return m_componentName; } /** * The requested configuration as an object. */ @@ -3566,7 +3587,7 @@ namespace Aws /** * The requested configuration as an object. */ - Aws::Crt::Optional GetValue() noexcept { return m_value; } + Aws::Crt::Optional GetValue() const noexcept { return m_value; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetConfigurationResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3597,7 +3618,7 @@ namespace Aws /** * (Optional) The name of the component. Defaults to the name of the component that makes the request. */ - Aws::Crt::Optional GetComponentName() noexcept { return m_componentName; } + Aws::Crt::Optional GetComponentName() const noexcept { return m_componentName; } /** * The key path to the configuration value. Specify a list where each entry is the key for a single level in * the configuration object. @@ -3607,7 +3628,7 @@ namespace Aws * The key path to the configuration value. Specify a list where each entry is the key for a single level in * the configuration object. */ - Aws::Crt::Optional> GetKeyPath() noexcept { return m_keyPath; } + Aws::Crt::Optional> GetKeyPath() const noexcept { return m_keyPath; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetConfigurationRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3641,7 +3662,7 @@ namespace Aws /** * The component's details. */ - Aws::Crt::Optional GetComponentDetails() noexcept { return m_componentDetails; } + Aws::Crt::Optional GetComponentDetails() const noexcept { return m_componentDetails; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetComponentDetailsResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3671,7 +3692,7 @@ namespace Aws /** * The name of the component to get. */ - Aws::Crt::Optional GetComponentName() noexcept { return m_componentName; } + Aws::Crt::Optional GetComponentName() const noexcept { return m_componentName; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetComponentDetailsRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3697,7 +3718,7 @@ namespace Aws void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } - Aws::Crt::Optional GetMessage() noexcept override { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept override { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(InvalidCredentialError &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3732,7 +3753,10 @@ namespace Aws * The session token for the client device. You can use this session token in subsequent requests to * authorize this client device's actions. */ - Aws::Crt::Optional GetClientDeviceAuthToken() noexcept { return m_clientDeviceAuthToken; } + Aws::Crt::Optional GetClientDeviceAuthToken() const noexcept + { + return m_clientDeviceAuthToken; + } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetClientDeviceAuthTokenResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3762,7 +3786,7 @@ namespace Aws /** * The client device's credentials. */ - Aws::Crt::Optional GetCredential() noexcept { return m_credential; } + Aws::Crt::Optional GetCredential() const noexcept { return m_credential; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetClientDeviceAuthTokenRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3792,7 +3816,7 @@ namespace Aws /** * An empty response state document. */ - Aws::Crt::Optional> GetPayload() noexcept { return m_payload; } + Aws::Crt::Optional> GetPayload() const noexcept { return m_payload; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(DeleteThingShadowResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3822,7 +3846,7 @@ namespace Aws /** * The name of the thing. */ - Aws::Crt::Optional GetThingName() noexcept { return m_thingName; } + Aws::Crt::Optional GetThingName() const noexcept { return m_thingName; } /** * The name of the shadow. To specify the thing's classic shadow, set this parameter to an empty string * (""). @@ -3832,7 +3856,7 @@ namespace Aws * The name of the shadow. To specify the thing's classic shadow, set this parameter to an empty string * (""). */ - Aws::Crt::Optional GetShadowName() noexcept { return m_shadowName; } + Aws::Crt::Optional GetShadowName() const noexcept { return m_shadowName; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(DeleteThingShadowRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3884,7 +3908,7 @@ namespace Aws /** * The ID of the AWS IoT Greengrass deployment to defer. */ - Aws::Crt::Optional GetDeploymentId() noexcept { return m_deploymentId; } + Aws::Crt::Optional GetDeploymentId() const noexcept { return m_deploymentId; } /** * (Optional) The name of the component for which to defer updates. Defaults to the name of the component * that makes the request. @@ -3894,7 +3918,7 @@ namespace Aws * (Optional) The name of the component for which to defer updates. Defaults to the name of the component * that makes the request. */ - Aws::Crt::Optional GetMessage() noexcept { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept { return m_message; } /** * The amount of time in milliseconds for which to defer the update. Greengrass waits for this amount of * time and then sends another PreComponentUpdateEvent @@ -3904,7 +3928,7 @@ namespace Aws * The amount of time in milliseconds for which to defer the update. Greengrass waits for this amount of * time and then sends another PreComponentUpdateEvent */ - Aws::Crt::Optional GetRecheckAfterMs() noexcept { return m_recheckAfterMs; } + Aws::Crt::Optional GetRecheckAfterMs() const noexcept { return m_recheckAfterMs; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(DeferComponentUpdateRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3932,7 +3956,7 @@ namespace Aws void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } - Aws::Crt::Optional GetMessage() noexcept override { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept override { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(InvalidArtifactsDirectoryPathError &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3958,7 +3982,7 @@ namespace Aws void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } - Aws::Crt::Optional GetMessage() noexcept override { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept override { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(InvalidRecipeDirectoryPathError &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -3988,7 +4012,7 @@ namespace Aws /** * The ID of the local deployment that the request created. */ - Aws::Crt::Optional GetDeploymentId() noexcept { return m_deploymentId; } + Aws::Crt::Optional GetDeploymentId() const noexcept { return m_deploymentId; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(CreateLocalDeploymentResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -4020,7 +4044,7 @@ namespace Aws * The thing group name the deployment is targeting. If the group name is not specified, "LOCAL_DEPLOYMENT" * will be used. */ - Aws::Crt::Optional GetGroupName() noexcept { return m_groupName; } + Aws::Crt::Optional GetGroupName() const noexcept { return m_groupName; } /** * Map of component name to version. Components will be added to the group's existing root components. */ @@ -4032,8 +4056,8 @@ namespace Aws /** * Map of component name to version. Components will be added to the group's existing root components. */ - Aws::Crt::Optional> - GetRootComponentVersionsToAdd() noexcept + Aws::Crt::Optional> GetRootComponentVersionsToAdd() + const noexcept { return m_rootComponentVersionsToAdd; } @@ -4049,7 +4073,7 @@ namespace Aws * List of components that need to be removed from the group, for example if new artifacts were loaded in * this request but recipe version did not change. */ - Aws::Crt::Optional> GetRootComponentsToRemove() noexcept + Aws::Crt::Optional> GetRootComponentsToRemove() const noexcept { return m_rootComponentsToRemove; } @@ -4064,8 +4088,8 @@ namespace Aws /** * Map of component names to configuration. */ - Aws::Crt::Optional> - GetComponentToConfiguration() noexcept + Aws::Crt::Optional> GetComponentToConfiguration() + const noexcept { return m_componentToConfiguration; } @@ -4080,7 +4104,7 @@ namespace Aws /** * Map of component names to component run as info. */ - Aws::Crt::Optional> GetComponentToRunWithInfo() noexcept + Aws::Crt::Optional> GetComponentToRunWithInfo() const noexcept { return m_componentToRunWithInfo; } @@ -4094,7 +4118,10 @@ namespace Aws /** * All recipes files in this directory will be copied over to the Greengrass package store. */ - Aws::Crt::Optional GetRecipeDirectoryPath() noexcept { return m_recipeDirectoryPath; } + Aws::Crt::Optional GetRecipeDirectoryPath() const noexcept + { + return m_recipeDirectoryPath; + } /** * All artifact files in this directory will be copied over to the Greengrass package store. */ @@ -4105,7 +4132,7 @@ namespace Aws /** * All artifact files in this directory will be copied over to the Greengrass package store. */ - Aws::Crt::Optional GetArtifactsDirectoryPath() noexcept + Aws::Crt::Optional GetArtifactsDirectoryPath() const noexcept { return m_artifactsDirectoryPath; } @@ -4116,7 +4143,7 @@ namespace Aws /** * Deployment failure handling policy. */ - Aws::Crt::Optional GetFailureHandlingPolicy() noexcept; + Aws::Crt::Optional GetFailureHandlingPolicy() const noexcept; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(CreateLocalDeploymentRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -4149,32 +4176,41 @@ namespace Aws void SetPassword(const Aws::Crt::String &password) noexcept { m_password = password; } - Aws::Crt::Optional GetPassword() noexcept { return m_password; } + Aws::Crt::Optional GetPassword() const noexcept { return m_password; } void SetUsername(const Aws::Crt::String &username) noexcept { m_username = username; } - Aws::Crt::Optional GetUsername() noexcept { return m_username; } + Aws::Crt::Optional GetUsername() const noexcept { return m_username; } void SetPasswordExpiration(const Aws::Crt::DateTime &passwordExpiration) noexcept { m_passwordExpiration = passwordExpiration; } - Aws::Crt::Optional GetPasswordExpiration() noexcept { return m_passwordExpiration; } + Aws::Crt::Optional GetPasswordExpiration() const noexcept + { + return m_passwordExpiration; + } void SetCertificateSHA256Hash(const Aws::Crt::String &certificateSHA256Hash) noexcept { m_certificateSHA256Hash = certificateSHA256Hash; } - Aws::Crt::Optional GetCertificateSHA256Hash() noexcept { return m_certificateSHA256Hash; } + Aws::Crt::Optional GetCertificateSHA256Hash() const noexcept + { + return m_certificateSHA256Hash; + } void SetCertificateSHA1Hash(const Aws::Crt::String &certificateSHA1Hash) noexcept { m_certificateSHA1Hash = certificateSHA1Hash; } - Aws::Crt::Optional GetCertificateSHA1Hash() noexcept { return m_certificateSHA1Hash; } + Aws::Crt::Optional GetCertificateSHA1Hash() const noexcept + { + return m_certificateSHA1Hash; + } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(CreateDebugPasswordResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -4225,7 +4261,7 @@ namespace Aws void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } - Aws::Crt::Optional GetMessage() noexcept { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(CancelLocalDeploymentResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -4255,7 +4291,7 @@ namespace Aws /** * (Optional) The ID of the local deployment to cancel. */ - Aws::Crt::Optional GetDeploymentId() noexcept { return m_deploymentId; } + Aws::Crt::Optional GetDeploymentId() const noexcept { return m_deploymentId; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(CancelLocalDeploymentRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -4281,7 +4317,7 @@ namespace Aws void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } - Aws::Crt::Optional GetMessage() noexcept override { return m_message; } + Aws::Crt::Optional GetMessage() const noexcept override { return m_message; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(InvalidClientDeviceAuthTokenError &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -4311,7 +4347,7 @@ namespace Aws /** * Whether the client device is authorized to perform the operation on the resource. */ - Aws::Crt::Optional GetIsAuthorized() noexcept { return m_isAuthorized; } + Aws::Crt::Optional GetIsAuthorized() const noexcept { return m_isAuthorized; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(AuthorizeClientDeviceActionResponse &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( @@ -4344,7 +4380,10 @@ namespace Aws /** * The session token for the client device from GetClientDeviceAuthToken. */ - Aws::Crt::Optional GetClientDeviceAuthToken() noexcept { return m_clientDeviceAuthToken; } + Aws::Crt::Optional GetClientDeviceAuthToken() const noexcept + { + return m_clientDeviceAuthToken; + } /** * The operation to authorize. */ @@ -4352,7 +4391,7 @@ namespace Aws /** * The operation to authorize. */ - Aws::Crt::Optional GetOperation() noexcept { return m_operation; } + Aws::Crt::Optional GetOperation() const noexcept { return m_operation; } /** * The resource the client device performs the operation on. */ @@ -4360,7 +4399,7 @@ namespace Aws /** * The resource the client device performs the operation on. */ - Aws::Crt::Optional GetResource() noexcept { return m_resource; } + Aws::Crt::Optional GetResource() const noexcept { return m_resource; } void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(AuthorizeClientDeviceActionRequest &, const Aws::Crt::JsonView &) noexcept; static Aws::Crt::ScopedResource s_allocateFromPayload( diff --git a/greengrass_ipc/source/GreengrassCoreIpcClient.cpp b/greengrass_ipc/source/GreengrassCoreIpcClient.cpp index 5d75d1240..a1db24d5a 100644 --- a/greengrass_ipc/source/GreengrassCoreIpcClient.cpp +++ b/greengrass_ipc/source/GreengrassCoreIpcClient.cpp @@ -58,11 +58,20 @@ namespace Aws return m_connection.Connect(connectionConfig, &lifecycleHandler, m_clientBootstrap); } - void GreengrassCoreIpcClient::Close() noexcept { m_connection.Close(); } + void GreengrassCoreIpcClient::Close() noexcept + { + m_connection.Close(); + } - void GreengrassCoreIpcClient::WithLaunchMode(std::launch mode) noexcept { m_asyncLaunchMode = mode; } + void GreengrassCoreIpcClient::WithLaunchMode(std::launch mode) noexcept + { + m_asyncLaunchMode = mode; + } - GreengrassCoreIpcClient::~GreengrassCoreIpcClient() noexcept { Close(); } + GreengrassCoreIpcClient::~GreengrassCoreIpcClient() noexcept + { + Close(); + } std::shared_ptr GreengrassCoreIpcClient::NewSubscribeToIoTCore( std::shared_ptr streamHandler) noexcept diff --git a/greengrass_ipc/source/GreengrassCoreIpcModel.cpp b/greengrass_ipc/source/GreengrassCoreIpcModel.cpp index a3f9331eb..272d0d146 100644 --- a/greengrass_ipc/source/GreengrassCoreIpcModel.cpp +++ b/greengrass_ipc/source/GreengrassCoreIpcModel.cpp @@ -38,7 +38,10 @@ namespace Aws const char *UserProperty::MODEL_NAME = "aws.greengrass#UserProperty"; - Aws::Crt::String UserProperty::GetModelName() const noexcept { return UserProperty::MODEL_NAME; } + Aws::Crt::String UserProperty::GetModelName() const noexcept + { + return UserProperty::MODEL_NAME; + } Aws::Crt::ScopedResource UserProperty::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -81,7 +84,10 @@ namespace Aws const char *MessageContext::MODEL_NAME = "aws.greengrass#MessageContext"; - Aws::Crt::String MessageContext::GetModelName() const noexcept { return MessageContext::MODEL_NAME; } + Aws::Crt::String MessageContext::GetModelName() const noexcept + { + return MessageContext::MODEL_NAME; + } Aws::Crt::ScopedResource MessageContext::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -205,7 +211,8 @@ namespace Aws } } - Aws::Crt::Optional DeploymentStatusDetails::GetDetailedDeploymentStatus() noexcept + Aws::Crt::Optional DeploymentStatusDetails::GetDetailedDeploymentStatus() + const noexcept { if (!m_detailedDeploymentStatus.has_value()) return Aws::Crt::Optional(); @@ -412,7 +419,10 @@ namespace Aws const char *BinaryMessage::MODEL_NAME = "aws.greengrass#BinaryMessage"; - Aws::Crt::String BinaryMessage::GetModelName() const noexcept { return BinaryMessage::MODEL_NAME; } + Aws::Crt::String BinaryMessage::GetModelName() const noexcept + { + return BinaryMessage::MODEL_NAME; + } Aws::Crt::ScopedResource BinaryMessage::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -465,7 +475,10 @@ namespace Aws const char *JsonMessage::MODEL_NAME = "aws.greengrass#JsonMessage"; - Aws::Crt::String JsonMessage::GetModelName() const noexcept { return JsonMessage::MODEL_NAME; } + Aws::Crt::String JsonMessage::GetModelName() const noexcept + { + return JsonMessage::MODEL_NAME; + } Aws::Crt::ScopedResource JsonMessage::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -614,7 +627,7 @@ namespace Aws } } - Aws::Crt::Optional MQTTMessage::GetPayloadFormat() noexcept + Aws::Crt::Optional MQTTMessage::GetPayloadFormat() const noexcept { if (!m_payloadFormat.has_value()) return Aws::Crt::Optional(); @@ -632,7 +645,10 @@ namespace Aws const char *MQTTMessage::MODEL_NAME = "aws.greengrass#MQTTMessage"; - Aws::Crt::String MQTTMessage::GetModelName() const noexcept { return MQTTMessage::MODEL_NAME; } + Aws::Crt::String MQTTMessage::GetModelName() const noexcept + { + return MQTTMessage::MODEL_NAME; + } Aws::Crt::ScopedResource MQTTMessage::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -888,7 +904,10 @@ namespace Aws const char *CertificateUpdate::MODEL_NAME = "aws.greengrass#CertificateUpdate"; - Aws::Crt::String CertificateUpdate::GetModelName() const noexcept { return CertificateUpdate::MODEL_NAME; } + Aws::Crt::String CertificateUpdate::GetModelName() const noexcept + { + return CertificateUpdate::MODEL_NAME; + } Aws::Crt::ScopedResource CertificateUpdate::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -970,7 +989,7 @@ namespace Aws } } - Aws::Crt::Optional Metric::GetUnit() noexcept + Aws::Crt::Optional Metric::GetUnit() const noexcept { if (!m_unit.has_value()) return Aws::Crt::Optional(); @@ -1004,7 +1023,10 @@ namespace Aws const char *Metric::MODEL_NAME = "aws.greengrass#Metric"; - Aws::Crt::String Metric::GetModelName() const noexcept { return Metric::MODEL_NAME; } + Aws::Crt::String Metric::GetModelName() const noexcept + { + return Metric::MODEL_NAME; + } Aws::Crt::ScopedResource Metric::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -1098,7 +1120,7 @@ namespace Aws } } - Aws::Crt::Optional LocalDeployment::GetStatus() noexcept + Aws::Crt::Optional LocalDeployment::GetStatus() const noexcept { if (!m_status.has_value()) return Aws::Crt::Optional(); @@ -1128,7 +1150,10 @@ namespace Aws const char *LocalDeployment::MODEL_NAME = "aws.greengrass#LocalDeployment"; - Aws::Crt::String LocalDeployment::GetModelName() const noexcept { return LocalDeployment::MODEL_NAME; } + Aws::Crt::String LocalDeployment::GetModelName() const noexcept + { + return LocalDeployment::MODEL_NAME; + } Aws::Crt::ScopedResource LocalDeployment::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -1228,7 +1253,7 @@ namespace Aws } } - Aws::Crt::Optional ComponentDetails::GetState() noexcept + Aws::Crt::Optional ComponentDetails::GetState() const noexcept { if (!m_state.has_value()) return Aws::Crt::Optional(); @@ -1270,7 +1295,10 @@ namespace Aws const char *ComponentDetails::MODEL_NAME = "aws.greengrass#ComponentDetails"; - Aws::Crt::String ComponentDetails::GetModelName() const noexcept { return ComponentDetails::MODEL_NAME; } + Aws::Crt::String ComponentDetails::GetModelName() const noexcept + { + return ComponentDetails::MODEL_NAME; + } Aws::Crt::ScopedResource ComponentDetails::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -1338,7 +1366,10 @@ namespace Aws const char *MQTTCredential::MODEL_NAME = "aws.greengrass#MQTTCredential"; - Aws::Crt::String MQTTCredential::GetModelName() const noexcept { return MQTTCredential::MODEL_NAME; } + Aws::Crt::String MQTTCredential::GetModelName() const noexcept + { + return MQTTCredential::MODEL_NAME; + } Aws::Crt::ScopedResource MQTTCredential::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -1399,7 +1430,10 @@ namespace Aws const char *RunWithInfo::MODEL_NAME = "aws.greengrass#RunWithInfo"; - Aws::Crt::String RunWithInfo::GetModelName() const noexcept { return RunWithInfo::MODEL_NAME; } + Aws::Crt::String RunWithInfo::GetModelName() const noexcept + { + return RunWithInfo::MODEL_NAME; + } Aws::Crt::ScopedResource RunWithInfo::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -1662,7 +1696,10 @@ namespace Aws const char *IoTCoreMessage::MODEL_NAME = "aws.greengrass#IoTCoreMessage"; - Aws::Crt::String IoTCoreMessage::GetModelName() const noexcept { return IoTCoreMessage::MODEL_NAME; } + Aws::Crt::String IoTCoreMessage::GetModelName() const noexcept + { + return IoTCoreMessage::MODEL_NAME; + } Aws::Crt::ScopedResource IoTCoreMessage::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -1920,7 +1957,7 @@ namespace Aws } } - Aws::Crt::Optional CertificateOptions::GetCertificateType() noexcept + Aws::Crt::Optional CertificateOptions::GetCertificateType() const noexcept { if (!m_certificateType.has_value()) return Aws::Crt::Optional(); @@ -1934,7 +1971,10 @@ namespace Aws const char *CertificateOptions::MODEL_NAME = "aws.greengrass#CertificateOptions"; - Aws::Crt::String CertificateOptions::GetModelName() const noexcept { return CertificateOptions::MODEL_NAME; } + Aws::Crt::String CertificateOptions::GetModelName() const noexcept + { + return CertificateOptions::MODEL_NAME; + } Aws::Crt::ScopedResource CertificateOptions::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -2009,7 +2049,7 @@ namespace Aws } } - Aws::Crt::Optional ConfigurationValidityReport::GetStatus() noexcept + Aws::Crt::Optional ConfigurationValidityReport::GetStatus() const noexcept { if (!m_status.has_value()) return Aws::Crt::Optional(); @@ -2106,7 +2146,10 @@ namespace Aws const char *PublishMessage::MODEL_NAME = "aws.greengrass#PublishMessage"; - Aws::Crt::String PublishMessage::GetModelName() const noexcept { return PublishMessage::MODEL_NAME; } + Aws::Crt::String PublishMessage::GetModelName() const noexcept + { + return PublishMessage::MODEL_NAME; + } Aws::Crt::ScopedResource PublishMessage::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -2179,7 +2222,10 @@ namespace Aws const char *SecretValue::MODEL_NAME = "aws.greengrass#SecretValue"; - Aws::Crt::String SecretValue::GetModelName() const noexcept { return SecretValue::MODEL_NAME; } + Aws::Crt::String SecretValue::GetModelName() const noexcept + { + return SecretValue::MODEL_NAME; + } Aws::Crt::ScopedResource SecretValue::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -2237,7 +2283,10 @@ namespace Aws const char *CredentialDocument::MODEL_NAME = "aws.greengrass#CredentialDocument"; - Aws::Crt::String CredentialDocument::GetModelName() const noexcept { return CredentialDocument::MODEL_NAME; } + Aws::Crt::String CredentialDocument::GetModelName() const noexcept + { + return CredentialDocument::MODEL_NAME; + } Aws::Crt::ScopedResource CredentialDocument::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -2333,7 +2382,10 @@ namespace Aws const char *ServiceError::MODEL_NAME = "aws.greengrass#ServiceError"; - Aws::Crt::String ServiceError::GetModelName() const noexcept { return ServiceError::MODEL_NAME; } + Aws::Crt::String ServiceError::GetModelName() const noexcept + { + return ServiceError::MODEL_NAME; + } Aws::Crt::ScopedResource ServiceError::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -2376,7 +2428,10 @@ namespace Aws const char *UnauthorizedError::MODEL_NAME = "aws.greengrass#UnauthorizedError"; - Aws::Crt::String UnauthorizedError::GetModelName() const noexcept { return UnauthorizedError::MODEL_NAME; } + Aws::Crt::String UnauthorizedError::GetModelName() const noexcept + { + return UnauthorizedError::MODEL_NAME; + } Aws::Crt::ScopedResource UnauthorizedError::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -2521,7 +2576,10 @@ namespace Aws const char *InvalidTokenError::MODEL_NAME = "aws.greengrass#InvalidTokenError"; - Aws::Crt::String InvalidTokenError::GetModelName() const noexcept { return InvalidTokenError::MODEL_NAME; } + Aws::Crt::String InvalidTokenError::GetModelName() const noexcept + { + return InvalidTokenError::MODEL_NAME; + } Aws::Crt::ScopedResource InvalidTokenError::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -2662,7 +2720,10 @@ namespace Aws const char *ConflictError::MODEL_NAME = "aws.greengrass#ConflictError"; - Aws::Crt::String ConflictError::GetModelName() const noexcept { return ConflictError::MODEL_NAME; } + Aws::Crt::String ConflictError::GetModelName() const noexcept + { + return ConflictError::MODEL_NAME; + } Aws::Crt::ScopedResource ConflictError::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -2888,7 +2949,10 @@ namespace Aws const char *UpdateStateResponse::MODEL_NAME = "aws.greengrass#UpdateStateResponse"; - Aws::Crt::String UpdateStateResponse::GetModelName() const noexcept { return UpdateStateResponse::MODEL_NAME; } + Aws::Crt::String UpdateStateResponse::GetModelName() const noexcept + { + return UpdateStateResponse::MODEL_NAME; + } Aws::Crt::ScopedResource UpdateStateResponse::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -2944,7 +3008,7 @@ namespace Aws } } - Aws::Crt::Optional UpdateStateRequest::GetState() noexcept + Aws::Crt::Optional UpdateStateRequest::GetState() const noexcept { if (!m_state.has_value()) return Aws::Crt::Optional(); @@ -2962,7 +3026,10 @@ namespace Aws const char *UpdateStateRequest::MODEL_NAME = "aws.greengrass#UpdateStateRequest"; - Aws::Crt::String UpdateStateRequest::GetModelName() const noexcept { return UpdateStateRequest::MODEL_NAME; } + Aws::Crt::String UpdateStateRequest::GetModelName() const noexcept + { + return UpdateStateRequest::MODEL_NAME; + } Aws::Crt::ScopedResource UpdateStateRequest::s_allocateFromPayload( Aws::Crt::StringView stringView, @@ -3330,7 +3397,7 @@ namespace Aws } } - Aws::Crt::Optional SubscribeToTopicRequest::GetReceiveMode() noexcept + Aws::Crt::Optional SubscribeToTopicRequest::GetReceiveMode() const noexcept { if (!m_receiveMode.has_value()) return Aws::Crt::Optional(); @@ -3457,7 +3524,7 @@ namespace Aws } } - Aws::Crt::Optional SubscribeToIoTCoreRequest::GetQos() noexcept + Aws::Crt::Optional SubscribeToIoTCoreRequest::GetQos() const noexcept { if (!m_qos.has_value()) return Aws::Crt::Optional(); @@ -3895,7 +3962,7 @@ namespace Aws } } - Aws::Crt::Optional StopComponentResponse::GetStopStatus() noexcept + Aws::Crt::Optional StopComponentResponse::GetStopStatus() const noexcept { if (!m_stopStatus.has_value()) return Aws::Crt::Optional(); @@ -4217,7 +4284,7 @@ namespace Aws } } - Aws::Crt::Optional RestartComponentResponse::GetRestartStatus() noexcept + Aws::Crt::Optional RestartComponentResponse::GetRestartStatus() const noexcept { if (!m_restartStatus.has_value()) return Aws::Crt::Optional(); @@ -4691,7 +4758,7 @@ namespace Aws } } - Aws::Crt::Optional PublishToIoTCoreRequest::GetQos() noexcept + Aws::Crt::Optional PublishToIoTCoreRequest::GetQos() const noexcept { if (!m_qos.has_value()) return Aws::Crt::Optional(); @@ -4721,7 +4788,7 @@ namespace Aws } } - Aws::Crt::Optional PublishToIoTCoreRequest::GetPayloadFormat() noexcept + Aws::Crt::Optional PublishToIoTCoreRequest::GetPayloadFormat() const noexcept { if (!m_payloadFormat.has_value()) return Aws::Crt::Optional(); @@ -6469,7 +6536,8 @@ namespace Aws } } - Aws::Crt::Optional CreateLocalDeploymentRequest::GetFailureHandlingPolicy() noexcept + Aws::Crt::Optional CreateLocalDeploymentRequest::GetFailureHandlingPolicy() + const noexcept { if (!m_failureHandlingPolicy.has_value()) return Aws::Crt::Optional(); @@ -7211,9 +7279,9 @@ namespace Aws std::future SubscribeToConfigurationUpdateOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { - return SubscribeToConfigurationUpdateResult(GetOperationResult().get()); - }); + return std::async( + m_asyncLaunchMode, + [this]() { return SubscribeToConfigurationUpdateResult(GetOperationResult().get()); }); } SubscribeToConfigurationUpdateOperation::SubscribeToConfigurationUpdateOperation( @@ -7516,9 +7584,9 @@ namespace Aws std::future SubscribeToValidateConfigurationUpdatesOperation:: GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { - return SubscribeToValidateConfigurationUpdatesResult(GetOperationResult().get()); - }); + return std::async( + m_asyncLaunchMode, + [this]() { return SubscribeToValidateConfigurationUpdatesResult(GetOperationResult().get()); }); } SubscribeToValidateConfigurationUpdatesOperation::SubscribeToValidateConfigurationUpdatesOperation( @@ -8003,9 +8071,9 @@ namespace Aws std::future SubscribeToCertificateUpdatesOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { - return SubscribeToCertificateUpdatesResult(GetOperationResult().get()); - }); + return std::async( + m_asyncLaunchMode, + [this]() { return SubscribeToCertificateUpdatesResult(GetOperationResult().get()); }); } SubscribeToCertificateUpdatesOperation::SubscribeToCertificateUpdatesOperation( @@ -8418,9 +8486,9 @@ namespace Aws std::future SendConfigurationValidityReportOperation:: GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { - return SendConfigurationValidityReportResult(GetOperationResult().get()); - }); + return std::async( + m_asyncLaunchMode, + [this]() { return SendConfigurationValidityReportResult(GetOperationResult().get()); }); } SendConfigurationValidityReportOperation::SendConfigurationValidityReportOperation( From 34b1e291716a0e3782993e080ac8ef65e98c0133 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Fri, 25 Apr 2025 12:18:30 -0700 Subject: [PATCH 29/56] More tests --- eventstream_rpc/tests/CMakeLists.txt | 9 + .../tests/EventStreamClientTest.cpp | 250 ++++++++++++++++-- 2 files changed, 242 insertions(+), 17 deletions(-) diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index 456a3368d..3d5838d63 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -39,6 +39,15 @@ add_test_case(EchoClientDoubleClose) add_test_case(EchoClientMultiConnectSuccessFail) add_test_case(EchoClientOperationEchoSuccessString) +add_test_case(EchoClientOperationEchoSuccessBoolean) +add_test_case(EchoClientOperationEchoSuccessTime) +add_test_case(EchoClientOperationEchoSuccessDocument) +add_test_case(EchoClientOperationEchoSuccessEnum) +add_test_case(EchoClientOperationEchoSuccessBlob) +add_test_case(EchoClientOperationEchoSuccessStringList) +add_test_case(EchoClientOperationEchoSuccessPairList) +add_test_case(EchoClientOperationEchoSuccessProductMap) + add_test_case(EchoClientOperationEchoSuccessMultiple) add_test_case(EchoClientOperationEchoFailureNeverConnected) add_test_case(EchoClientOperationEchoFailureDisconnected) diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 5f50258dd..e867a24a9 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -290,26 +290,129 @@ static void s_onMessageFlush(int errorCode) (void)errorCode; } -#define DEFINE_CHECK_MESSAGE_DATA_MEMBER_EQUALITY_FN(TYPENAME) \ - static int s_checkMessageDataMemberEquality( \ - Aws::Crt::Optional expectedValue, Aws::Crt::Optional actualValue) \ - { \ - ASSERT_TRUE(expectedValue.has_value() == actualValue.has_value()); \ - if (expectedValue.has_value()) \ - { \ - ASSERT_TRUE(expectedValue.value() == actualValue.value()); \ - } \ - \ - return AWS_OP_SUCCESS; \ - } - -DEFINE_CHECK_MESSAGE_DATA_MEMBER_EQUALITY_FN(Aws::Crt::String) -DEFINE_CHECK_MESSAGE_DATA_MEMBER_EQUALITY_FN(bool) +template +static bool s_messageDataMembersAreEqual(Aws::Crt::Optional expectedValue, Aws::Crt::Optional actualValue) +{ + if (expectedValue.has_value() != actualValue.has_value()) + { + return false; + } + + if (expectedValue.has_value()) + { + return expectedValue.value() == actualValue.value(); + } + + return true; +} + +// Specialization for Vector since we don't codegen == for Shapes +static bool s_messageDataMembersAreEqual( + const Aws::Crt::Optional> &lhs, + const Aws::Crt::Optional> &rhs) +{ + if (lhs.has_value() != rhs.has_value()) + { + return false; + } + + if (!lhs.has_value()) + { + return true; + } + + if (lhs.value().size() != rhs.value().size()) + { + return false; + } + + for (size_t i = 0; i < lhs.value().size(); ++i) + { + const auto &lhs_pair = (lhs.value())[i]; + const auto &rhs_pair = (rhs.value())[i]; + + if (lhs_pair.GetKey().has_value() != rhs_pair.GetKey().has_value()) + { + return false; + } + + if (lhs_pair.GetValue().has_value() != rhs_pair.GetValue().has_value()) + { + return false; + } + + if (lhs_pair.GetKey().value() != rhs_pair.GetKey().value() || + lhs_pair.GetValue().value() != rhs_pair.GetValue().value()) + { + return false; + } + } + + return true; +} + +// Specialization for Map since we don't codegen == for Shapes +static bool s_messageDataMembersAreEqual( + const Aws::Crt::Optional> &lhs, + const Aws::Crt::Optional> &rhs) +{ + if (lhs.has_value() != rhs.has_value()) + { + return false; + } + + if (!lhs.has_value()) + { + return true; + } + + if (lhs.value().size() != rhs.value().size()) + { + return false; + } + + for (const auto &lhs_entry : lhs.value()) + { + const auto &rhs_entry = rhs.value().find(lhs_entry.first); + if (rhs_entry == rhs.value().end()) + { + return false; + } + + const auto &lhs_product = lhs_entry.second; + const auto &rhs_product = rhs_entry->second; + + if (lhs_product.GetName().has_value() != rhs_product.GetName().has_value()) + { + return false; + } + + if (lhs_product.GetPrice().has_value() != rhs_product.GetPrice().has_value()) + { + return false; + } + + if (lhs_product.GetName().value() != rhs_product.GetName().value() || + lhs_product.GetPrice().value() != rhs_product.GetPrice().value()) + { + return false; + } + } + + return true; +} static int s_checkMessageDataEquality(const MessageData &expectedData, const MessageData &actualData) { - ASSERT_SUCCESS(s_checkMessageDataMemberEquality(expectedData.GetStringMessage(), actualData.GetStringMessage())); - ASSERT_SUCCESS(s_checkMessageDataMemberEquality(expectedData.GetBooleanMessage(), actualData.GetBooleanMessage())); + ASSERT_TRUE(s_messageDataMembersAreEqual(expectedData.GetStringMessage(), actualData.GetStringMessage())); + ASSERT_TRUE(s_messageDataMembersAreEqual(expectedData.GetBooleanMessage(), actualData.GetBooleanMessage())); + ASSERT_TRUE(s_messageDataMembersAreEqual(expectedData.GetTimeMessage(), actualData.GetTimeMessage())); + ASSERT_TRUE(s_messageDataMembersAreEqual(expectedData.GetDocumentMessage(), actualData.GetDocumentMessage())); + ASSERT_TRUE(s_messageDataMembersAreEqual(expectedData.GetEnumMessage(), actualData.GetEnumMessage())); + ASSERT_TRUE(s_messageDataMembersAreEqual(expectedData.GetBlobMessage(), actualData.GetBlobMessage())); + ASSERT_TRUE(s_messageDataMembersAreEqual(expectedData.GetStringListMessage(), actualData.GetStringListMessage())); + ASSERT_TRUE(s_messageDataMembersAreEqual(expectedData.GetKeyValuePairList(), actualData.GetKeyValuePairList())); + ASSERT_TRUE(s_messageDataMembersAreEqual(expectedData.GetStringToValue(), actualData.GetStringToValue())); return AWS_OP_SUCCESS; } @@ -364,6 +467,119 @@ static int s_TestEchoClientOperationEchoSuccessString(struct aws_allocator *allo AWS_TEST_CASE(EchoClientOperationEchoSuccessString, s_TestEchoClientOperationEchoSuccessString); +static int s_TestEchoClientOperationEchoSuccessBoolean(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientOperationEchoSuccess( + allocator, [](MessageData &messageData) { messageData.SetBooleanMessage(true); }); +} + +AWS_TEST_CASE(EchoClientOperationEchoSuccessBoolean, s_TestEchoClientOperationEchoSuccessBoolean); + +static int s_TestEchoClientOperationEchoSuccessTime(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientOperationEchoSuccess( + allocator, [](MessageData &messageData) { messageData.SetTimeMessage(Aws::Crt::DateTime::Now()); }); +} + +AWS_TEST_CASE(EchoClientOperationEchoSuccessTime, s_TestEchoClientOperationEchoSuccessTime); + +static int s_TestEchoClientOperationEchoSuccessDocument(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientOperationEchoSuccess( + allocator, + [](MessageData &messageData) + { + Aws::Crt::JsonObject subobject; + subobject.WithString("Hello", "There"); + Aws::Crt::JsonObject document; + document.WithInt64("Derp", 21); + document.WithObject("DailyAffirmations", subobject); + + messageData.SetDocumentMessage(document); + }); +} + +AWS_TEST_CASE(EchoClientOperationEchoSuccessDocument, s_TestEchoClientOperationEchoSuccessDocument); + +static int s_TestEchoClientOperationEchoSuccessEnum(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientOperationEchoSuccess( + allocator, [](MessageData &messageData) { messageData.SetEnumMessage(FruitEnum::FRUIT_ENUM_PINEAPPLE); }); +} + +AWS_TEST_CASE(EchoClientOperationEchoSuccessEnum, s_TestEchoClientOperationEchoSuccessEnum); + +static int s_TestEchoClientOperationEchoSuccessBlob(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientOperationEchoSuccess( + allocator, + [](MessageData &messageData) + { + Aws::Crt::Vector blob = {1, 2, 3, 4, 5}; + messageData.SetBlobMessage(blob); + }); +} + +AWS_TEST_CASE(EchoClientOperationEchoSuccessBlob, s_TestEchoClientOperationEchoSuccessBlob); + +static int s_TestEchoClientOperationEchoSuccessStringList(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientOperationEchoSuccess( + allocator, + [](MessageData &messageData) + { + Aws::Crt::Vector stringList = {"1", "2", "Toasty", "Mctoaster"}; + messageData.SetStringListMessage(stringList); + }); +} + +AWS_TEST_CASE(EchoClientOperationEchoSuccessStringList, s_TestEchoClientOperationEchoSuccessStringList); + +static int s_TestEchoClientOperationEchoSuccessPairList(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientOperationEchoSuccess( + allocator, + [](MessageData &messageData) + { + Pair pair1; + pair1.SetKey("Uff"); + pair1.SetValue("Dah"); + + Pair pair2; + pair2.SetKey("Hello"); + pair2.SetValue("World"); + + Aws::Crt::Vector pairList = {pair1, pair2}; + messageData.SetKeyValuePairList(pairList); + }); +} + +AWS_TEST_CASE(EchoClientOperationEchoSuccessPairList, s_TestEchoClientOperationEchoSuccessPairList); + +static int s_TestEchoClientOperationEchoSuccessProductMap(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientOperationEchoSuccess( + allocator, + [](MessageData &messageData) + { + Aws::Crt::Map productMap = {}; + Product product1; + product1.SetName("Derp"); + product1.SetPrice(4.0); + + Product product2; + product2.SetName("Can Of Derp"); + product2.SetPrice(7.5); + + productMap[product1.GetName().value()] = product1; + productMap[product2.GetName().value()] = product2; + + messageData.SetStringToValue(productMap); + }); +} + +AWS_TEST_CASE(EchoClientOperationEchoSuccessProductMap, s_TestEchoClientOperationEchoSuccessProductMap); + static int s_TestEchoClientOperationEchoSuccessMultiple(struct aws_allocator *allocator, void *ctx) { ApiHandle apiHandle(allocator); From 1d0236206204ca8dd5e5b7053eca7c7d00681ee0 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Fri, 25 Apr 2025 12:55:52 -0700 Subject: [PATCH 30/56] Weird x86 compile error --- eventstream_rpc/tests/EventStreamClientTest.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index e867a24a9..f54aa31df 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -306,6 +306,21 @@ static bool s_messageDataMembersAreEqual(Aws::Crt::Optional expectedValue, Aw return true; } +static bool s_messageDataMembersAreEqual(Aws::Crt::Optional expectedValue, Aws::Crt::Optional actualValue) +{ + if (expectedValue.has_value() != actualValue.has_value()) + { + return false; + } + + if (expectedValue.has_value()) + { + return expectedValue.value() == actualValue.value(); + } + + return true; +} + // Specialization for Vector since we don't codegen == for Shapes static bool s_messageDataMembersAreEqual( const Aws::Crt::Optional> &lhs, From 7cdbd3924caa4e3c46840b95ff046fc58fd66c94 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Thu, 8 May 2025 14:28:40 -0700 Subject: [PATCH 31/56] Checkpoint before refactoring impl --- .../aws/eventstreamrpc/EventStreamClient.h | 218 ++---- eventstream_rpc/source/EventStreamClient.cpp | 620 ++++++++++-------- eventstream_rpc/tests/CMakeLists.txt | 26 +- .../tests/EventStreamClientTest.cpp | 17 +- 4 files changed, 429 insertions(+), 452 deletions(-) diff --git a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h index ccd464eb9..1414409dd 100644 --- a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h +++ b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h @@ -41,6 +41,7 @@ namespace Aws class ClientOperation; class ClientConnection; class ClientContinuation; + class ClientContinuationHandler; using HeaderValueType = aws_event_stream_header_value_type; using MessageType = aws_event_stream_rpc_message_type; @@ -212,10 +213,11 @@ namespace Aws struct AWS_EVENTSTREAMRPC_API RpcError { + explicit operator bool() const noexcept { return baseStatus == EVENT_STREAM_RPC_SUCCESS; } + Crt::String StatusToString(); + EventStreamRpcStatusCode baseStatus; int crtError; - operator bool() const noexcept { return baseStatus == EVENT_STREAM_RPC_SUCCESS; } - Crt::String StatusToString(); }; /** @@ -232,20 +234,21 @@ namespace Aws * is invoked, the `ClientConnection` is ready to be used for sending messages. */ virtual void OnConnectCallback(); + /** * Invoked upon connection shutdown. * @param status The status upon disconnection. It can be treated as a bool * with true implying a successful disconnection. */ virtual void OnDisconnectCallback(RpcError status); + /** * Invoked upon receiving an error. Use the return value to determine - * whether or not to force the connection to close. Keep in mind that once - * closed, the `ClientConnection` can no longer send messages. - * @param status The status upon disconnection. It can be treated as a bool - * with true implying a successful disconnection. + * whether or not to force the connection to close. + * @param status Details about the error encountered. */ virtual bool OnErrorCallback(RpcError status); + /** * Invoked upon receiving a ping from the server. The `headers` and `payload` * refer to what is contained in the ping message. @@ -255,6 +258,61 @@ namespace Aws const Crt::Optional &payload); }; + + class ClientConnectionImpl; + + /** + * Class representing a connection to an RPC server. + */ + class AWS_EVENTSTREAMRPC_API ClientConnection final + { + public: + + explicit ClientConnection(Crt::Allocator *allocator = Crt::g_allocator) noexcept; + ~ClientConnection() noexcept; + + /** + * Initiates a new outgoing event-stream-rpc connection. + * @param connectionOptions Connection options. + * @param connectionLifecycleHandler Handler to process connection lifecycle events. + * @param clientBootstrap ClientBootstrap object to run the connection on. + * @return Future that will be resolved when connection either succeeds or fails. + */ + std::future Connect( + const ConnectionConfig &connectionOptions, + ConnectionLifecycleHandler *connectionLifecycleHandler, + Crt::Io::ClientBootstrap &clientBootstrap) noexcept; + + /** + * Create a new stream. + * @note Activate() must be called on the stream for it to actually initiate the new stream. + * @param clientContinuationHandler Handler to process continuation events. + * @return A newly created continuation. + */ + ClientContinuation NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept; + + /** + * Close the connection. + */ + void Close() noexcept; + + /** + * Check if the connection is open. + * @return True if the connection is open, false otherwise. + */ + bool IsOpen() const noexcept; + + /** + * Returns the C connection object, if it exists. + * @return the C connection object, if it exists. + */ + struct aws_event_stream_rpc_client_connection *GetUnderlyingHandle() const noexcept; + + private: + + std::shared_ptr m_impl; + }; + /** * User data passed to callbacks for a new stream. */ @@ -301,7 +359,7 @@ namespace Aws private: friend class ClientContinuation; - ContinuationCallbackData *m_callbackData; + std::shared_ptr m_callbackData; }; /** @@ -320,7 +378,7 @@ namespace Aws * @param allocator Allocator to use. */ ClientContinuation( - ClientConnection *connection, + struct aws_event_stream_rpc_client_connection *connection, ClientContinuationHandler &continuationHandler, Crt::Allocator *allocator) noexcept; ~ClientContinuation() noexcept; @@ -372,7 +430,9 @@ namespace Aws Crt::Allocator *m_allocator; ClientContinuationHandler &m_continuationHandler; struct aws_event_stream_rpc_client_continuation_token *m_continuationToken; - ContinuationCallbackData *m_callbackData; + std::shared_ptr m_callbackData; + + void Release(); static void s_onContinuationMessage( struct aws_event_stream_rpc_client_continuation_token *continuationToken, @@ -722,146 +782,6 @@ namespace Aws std::condition_variable m_closeReady; }; - /** - * Class representing a connection to an RPC server. - */ - class AWS_EVENTSTREAMRPC_API ClientConnection final - { - public: - ClientConnection(Crt::Allocator *allocator = Crt::g_allocator) noexcept; - ~ClientConnection() noexcept; - ClientConnection(const ClientConnection &) noexcept = delete; - ClientConnection &operator=(const ClientConnection &) noexcept = delete; - ClientConnection(ClientConnection &&) noexcept; - ClientConnection &operator=(ClientConnection &&) noexcept; - /** - * Initiates a new outgoing event-stream-rpc connection. - * @param connectionOptions Connection options. - * @param connectionLifecycleHandler Handler to process connection lifecycle events. - * @param clientBootstrap ClientBootstrap object to run the connection on. - * @return Future that will be resolved when connection either succeeds or fails. - */ - std::future Connect( - const ConnectionConfig &connectionOptions, - ConnectionLifecycleHandler *connectionLifecycleHandler, - Crt::Io::ClientBootstrap &clientBootstrap) noexcept; - - std::future SendPing( - const Crt::List &headers, - const Crt::Optional &payload, - OnMessageFlushCallback onMessageFlushCallback) noexcept; - - std::future SendPingResponse( - const Crt::List &headers, - const Crt::Optional &payload, - OnMessageFlushCallback onMessageFlushCallback) noexcept; - - /** - * Create a new stream. - * @note Activate() must be called on the stream for it to actually initiate the new stream. - * @param clientContinuationHandler Handler to process continuation events. - * @return A newly created continuation. - */ - ClientContinuation NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept; - - /** - * Close the connection. - */ - void Close() noexcept; - - /** - * Check if the connection is open. - * @return True if the connection is open, false otherwise. - */ - bool IsOpen() const noexcept - { - if (this->m_underlyingConnection == nullptr) - { - return false; - } - else - { - return aws_event_stream_rpc_client_connection_is_open(this->m_underlyingConnection); - } - } - - /** - * @return true if the connection is open, false otherwise. - */ - operator bool() const noexcept { return IsOpen(); } - - private: - friend class ClientContinuation; - friend std::future ClientOperation::Close(OnMessageFlushCallback onMessageFlushCallback) noexcept; - enum ClientState - { - DISCONNECTED = 1, - CONNECTING_SOCKET, - WAITING_FOR_CONNECT_ACK, - CONNECTED, - DISCONNECTING, - }; - /* This recursive mutex protects m_clientState & m_connectionWillSetup */ - std::recursive_mutex m_stateMutex; - Crt::Allocator *m_allocator; - struct aws_event_stream_rpc_client_connection *m_underlyingConnection; - ClientState m_clientState; - ConnectionLifecycleHandler *m_lifecycleHandler; - ConnectMessageAmender m_connectMessageAmender; - std::promise m_connectionSetupPromise; - bool m_connectionWillSetup; - std::promise m_connectAckedPromise; - std::promise m_closedPromise; - bool m_onConnectCalled; - RpcError m_closeReason; - OnMessageFlushCallback m_onConnectRequestCallback; - Crt::Io::SocketOptions m_socketOptions; - ConnectionConfig m_connectionConfig; - std::future SendProtocolMessage( - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags, - OnMessageFlushCallback onMessageFlushCallback) noexcept; - - static void s_onConnectionShutdown( - struct aws_event_stream_rpc_client_connection *connection, - int errorCode, - void *userData) noexcept; - static void s_onConnectionSetup( - struct aws_event_stream_rpc_client_connection *connection, - int errorCode, - void *userData) noexcept; - static void s_onProtocolMessage( - struct aws_event_stream_rpc_client_connection *connection, - const struct aws_event_stream_rpc_message_args *messageArgs, - void *userData) noexcept; - - static void s_protocolMessageCallback(int errorCode, void *userData) noexcept; - - /** - * Sends a message on the connection. These must be connection level messages (not application messages). - */ - static std::future s_sendProtocolMessage( - ClientConnection *connection, - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags, - OnMessageFlushCallback onMessageFlushCallback) noexcept; - - static std::future s_sendPing( - ClientConnection *connection, - const Crt::List &headers, - const Crt::Optional &payload, - OnMessageFlushCallback onMessageFlushCallback) noexcept; - - static std::future s_sendPingResponse( - ClientConnection *connection, - const Crt::List &headers, - const Crt::Optional &payload, - OnMessageFlushCallback onMessageFlushCallback) noexcept; - }; } // namespace Eventstreamrpc } // namespace Aws diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 65983178e..e14bbdeb1 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -164,76 +164,260 @@ namespace Aws } } - class EventStreamCppToNativeCrtBuilder + static int s_fillNativeHeadersArray( + const Crt::List &headers, + struct aws_array_list *headersArray, + Crt::Allocator *m_allocator = Crt::g_allocator) { - private: - friend class ClientConnection; - friend class ClientContinuation; - static int s_fillNativeHeadersArray( - const Crt::List &headers, - struct aws_array_list *headersArray, - Crt::Allocator *m_allocator = Crt::g_allocator) - { - AWS_ZERO_STRUCT(*headersArray); - /* Check if the connection has expired before attempting to send. */ - int errorCode = aws_event_stream_headers_list_init(headersArray, m_allocator); + AWS_ZERO_STRUCT(*headersArray); + /* Check if the connection has expired before attempting to send. */ + int errorCode = aws_event_stream_headers_list_init(headersArray, m_allocator); - if (!errorCode) + if (!errorCode) + { + /* Populate the array with the underlying handle of each EventStreamHeader. */ + for (auto &i : headers) { - /* Populate the array with the underlying handle of each EventStreamHeader. */ - for (auto &i : headers) - { - errorCode = aws_array_list_push_back(headersArray, i.GetUnderlyingHandle()); + errorCode = aws_array_list_push_back(headersArray, i.GetUnderlyingHandle()); - if (errorCode) - { - break; - } + if (errorCode) + { + break; } } + } + + return errorCode; + } - return errorCode; + Crt::String RpcError::StatusToString() + { + switch (baseStatus) + { + case EVENT_STREAM_RPC_SUCCESS: + return "EVENT_STREAM_RPC_SUCCESS"; + case EVENT_STREAM_RPC_NULL_PARAMETER: + return "EVENT_STREAM_RPC_NULL_PARAMETER"; + case EVENT_STREAM_RPC_UNINITIALIZED: + return "EVENT_STREAM_RPC_UNINITIALIZED"; + case EVENT_STREAM_RPC_ALLOCATION_ERROR: + return "EVENT_STREAM_RPC_ALLOCATION_ERROR"; + case EVENT_STREAM_RPC_CONNECTION_SETUP_FAILED: + return "EVENT_STREAM_RPC_CONNECTION_SETUP_FAILED"; + case EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED: + return "EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED"; + case EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED: + return "EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED"; + case EVENT_STREAM_RPC_CONNECTION_CLOSED: + return "EVENT_STREAM_RPC_CONNECTION_CLOSED"; + case EVENT_STREAM_RPC_CONTINUATION_CLOSED: + return "EVENT_STREAM_RPC_CONTINUATION_CLOSED"; + case EVENT_STREAM_RPC_UNKNOWN_PROTOCOL_MESSAGE: + return "EVENT_STREAM_RPC_UNKNOWN_PROTOCOL_MESSAGE"; + case EVENT_STREAM_RPC_UNMAPPED_DATA: + return "EVENT_STREAM_RPC_UNMAPPED_DATA"; + case EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE: + return "EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE"; + case EVENT_STREAM_RPC_CRT_ERROR: + Crt::String ret = "Failed with EVENT_STREAM_RPC_CRT_ERROR, the CRT error was "; + ret += Crt::ErrorDebugString(crtError); + return ret; } - }; + return "Unknown status code"; + } + + bool ConnectionLifecycleHandler::OnErrorCallback(RpcError error) + { + (void)error; + /* Returning true implies that the connection should close as a result of encountering this error. */ + return true; + } - ClientConnection &ClientConnection::operator=(ClientConnection &&rhs) noexcept + void ConnectionLifecycleHandler::OnPingCallback( + const Crt::List &headers, + const Crt::Optional &payload) { - m_allocator = std::move(rhs.m_allocator); - m_underlyingConnection = rhs.m_underlyingConnection; - rhs.m_stateMutex.lock(); - m_clientState = rhs.m_clientState; - rhs.m_stateMutex.unlock(); - m_lifecycleHandler = rhs.m_lifecycleHandler; - m_connectMessageAmender = rhs.m_connectMessageAmender; - m_connectAckedPromise = std::move(rhs.m_connectAckedPromise); - m_closedPromise = std::move(rhs.m_closedPromise); - m_onConnectRequestCallback = rhs.m_onConnectRequestCallback; + (void)headers; + (void)payload; + } - /* Reset rhs. */ - rhs.m_allocator = nullptr; - rhs.m_underlyingConnection = nullptr; - rhs.m_clientState = DISCONNECTED; - rhs.m_lifecycleHandler = nullptr; - rhs.m_connectMessageAmender = nullptr; - rhs.m_closedPromise = {}; - rhs.m_onConnectRequestCallback = nullptr; + void ConnectionLifecycleHandler::OnConnectCallback() {} + + void ConnectionLifecycleHandler::OnDisconnectCallback(RpcError error) + { + (void)error; + } + + EventStreamHeader::EventStreamHeader( + const struct aws_event_stream_header_value_pair &header, + Crt::Allocator *allocator) + : m_allocator(allocator), m_valueByteBuf({}), m_underlyingHandle(header) + { + } + EventStreamHeader::EventStreamHeader( + const Crt::String &name, + const Crt::String &value, + Crt::Allocator *allocator) noexcept + : m_allocator(allocator), + m_valueByteBuf(Crt::ByteBufNewCopy(allocator, (uint8_t *)value.c_str(), value.length())) + { + m_underlyingHandle.header_name_len = static_cast(name.length()); + size_t length; + if (name.length() > INT8_MAX) + { + length = INT8_MAX; + } + else + { + length = static_cast(name.length()); + } + (void)memcpy(m_underlyingHandle.header_name, name.c_str(), length); + m_underlyingHandle.header_value_type = AWS_EVENT_STREAM_HEADER_STRING; + m_underlyingHandle.header_value.variable_len_val = m_valueByteBuf.buffer; + m_underlyingHandle.header_value_len = (uint16_t)m_valueByteBuf.len; + } + + EventStreamHeader::~EventStreamHeader() noexcept + { + if (aws_byte_buf_is_valid(&m_valueByteBuf)) + Crt::ByteBufDelete(m_valueByteBuf); + } + + EventStreamHeader::EventStreamHeader(const EventStreamHeader &lhs) noexcept + : m_allocator(lhs.m_allocator), + m_valueByteBuf(Crt::ByteBufNewCopy(lhs.m_allocator, lhs.m_valueByteBuf.buffer, lhs.m_valueByteBuf.len)), + m_underlyingHandle(lhs.m_underlyingHandle) + { + m_underlyingHandle.header_value.variable_len_val = m_valueByteBuf.buffer; + m_underlyingHandle.header_value_len = static_cast(m_valueByteBuf.len); + } + + EventStreamHeader &EventStreamHeader::operator=(const EventStreamHeader &lhs) noexcept + { + m_allocator = lhs.m_allocator; + m_valueByteBuf = Crt::ByteBufNewCopy(lhs.m_allocator, lhs.m_valueByteBuf.buffer, lhs.m_valueByteBuf.len); + m_underlyingHandle = lhs.m_underlyingHandle; + m_underlyingHandle.header_value.variable_len_val = m_valueByteBuf.buffer; + m_underlyingHandle.header_value_len = static_cast(m_valueByteBuf.len); return *this; } - ClientConnection::ClientConnection(ClientConnection &&rhs) noexcept : m_lifecycleHandler(rhs.m_lifecycleHandler) + EventStreamHeader::EventStreamHeader(EventStreamHeader &&rhs) noexcept + : m_allocator(rhs.m_allocator), m_valueByteBuf(rhs.m_valueByteBuf), + m_underlyingHandle(rhs.m_underlyingHandle) + { + rhs.m_valueByteBuf.allocator = nullptr; + rhs.m_valueByteBuf.buffer = nullptr; + } + + const struct aws_event_stream_header_value_pair *EventStreamHeader::GetUnderlyingHandle() const { - *this = std::move(rhs); + return &m_underlyingHandle; } - ClientConnection::ClientConnection(Crt::Allocator *allocator) noexcept + Crt::String EventStreamHeader::GetHeaderName() const noexcept + { + return Crt::String(m_underlyingHandle.header_name, m_underlyingHandle.header_name_len, m_allocator); + } + + bool EventStreamHeader::GetValueAsString(Crt::String &value) const noexcept + { + if (m_underlyingHandle.header_value_type != AWS_EVENT_STREAM_HEADER_STRING) + { + return false; + } + value = Crt::String( + reinterpret_cast(m_underlyingHandle.header_value.variable_len_val), + m_underlyingHandle.header_value_len, + m_allocator); + + return true; + } + + class ClientConnectionImpl final + { + public: + + explicit ClientConnectionImpl(Crt::Allocator *allocator = Crt::g_allocator) noexcept; + ~ClientConnectionImpl() noexcept; + + std::future Connect( + const ConnectionConfig &connectionOptions, + ConnectionLifecycleHandler *connectionLifecycleHandler, + Crt::Io::ClientBootstrap &clientBootstrap) noexcept; + + ClientContinuation NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept; + + void Close() noexcept; + + bool IsOpen() const noexcept; + + struct aws_event_stream_rpc_client_connection *GetUnderlyingHandle() const noexcept; + + void Shutdown() noexcept; + + private: + + enum ClientState + { + DISCONNECTED = 1, + CONNECTING_SOCKET, + WAITING_FOR_CONNECT_ACK, + CONNECTED, + DISCONNECTING, + }; + /* This recursive mutex protects m_clientState & m_connectionWillSetup */ + std::recursive_mutex m_stateMutex; + Crt::Allocator *m_allocator; + struct aws_event_stream_rpc_client_connection *m_underlyingConnection; + ClientState m_clientState; + ConnectionLifecycleHandler *m_lifecycleHandler; + ConnectMessageAmender m_connectMessageAmender; + std::promise m_connectionSetupPromise; + bool m_connectionWillSetup; + std::promise m_connectAckedPromise; + std::promise m_closedPromise; + bool m_onConnectCalled; + RpcError m_closeReason; + OnMessageFlushCallback m_onConnectRequestCallback; + Crt::Io::SocketOptions m_socketOptions; + ConnectionConfig m_connectionConfig; + + static std::future s_sendProtocolMessage( + ClientConnectionImpl *connectionImpl, + const Crt::List &headers, + const Crt::Optional &payload, + MessageType messageType, + uint32_t messageFlags, + OnMessageFlushCallback onMessageFlushCallback) noexcept; + + static void s_onConnectionShutdown( + struct aws_event_stream_rpc_client_connection *connection, + int errorCode, + void *userData) noexcept; + + static void s_onConnectionSetup( + struct aws_event_stream_rpc_client_connection *connection, + int errorCode, + void *userData) noexcept; + + static void s_onProtocolMessage( + struct aws_event_stream_rpc_client_connection *connection, + const struct aws_event_stream_rpc_message_args *messageArgs, + void *userData) noexcept; + + }; + + ClientConnectionImpl::ClientConnectionImpl(Crt::Allocator *allocator) noexcept : m_allocator(allocator), m_underlyingConnection(nullptr), m_clientState(DISCONNECTED), m_lifecycleHandler(nullptr), m_connectMessageAmender(nullptr), m_connectionWillSetup(false), + m_onConnectCalled(false), m_closeReason{EVENT_STREAM_RPC_SUCCESS, AWS_ERROR_SUCCESS}, m_onConnectRequestCallback(nullptr) { } - ClientConnection::~ClientConnection() noexcept + ClientConnectionImpl::~ClientConnectionImpl() noexcept { m_stateMutex.lock(); bool waitForSetup = m_connectionWillSetup; @@ -261,65 +445,12 @@ namespace Aws m_underlyingConnection = nullptr; } - bool ConnectionLifecycleHandler::OnErrorCallback(RpcError error) + void ClientConnectionImpl::Shutdown() noexcept { - (void)error; - /* Returning true implies that the connection should close as a result of encountering this error. */ - return true; - } - void ConnectionLifecycleHandler::OnPingCallback( - const Crt::List &headers, - const Crt::Optional &payload) - { - (void)headers; - (void)payload; - } - - void ConnectionLifecycleHandler::OnConnectCallback() {} - - void ConnectionLifecycleHandler::OnDisconnectCallback(RpcError error) - { - (void)error; } - Crt::String RpcError::StatusToString() - { - switch (baseStatus) - { - case EVENT_STREAM_RPC_SUCCESS: - return "EVENT_STREAM_RPC_SUCCESS"; - case EVENT_STREAM_RPC_NULL_PARAMETER: - return "EVENT_STREAM_RPC_NULL_PARAMETER"; - case EVENT_STREAM_RPC_UNINITIALIZED: - return "EVENT_STREAM_RPC_UNINITIALIZED"; - case EVENT_STREAM_RPC_ALLOCATION_ERROR: - return "EVENT_STREAM_RPC_ALLOCATION_ERROR"; - case EVENT_STREAM_RPC_CONNECTION_SETUP_FAILED: - return "EVENT_STREAM_RPC_CONNECTION_SETUP_FAILED"; - case EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED: - return "EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED"; - case EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED: - return "EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED"; - case EVENT_STREAM_RPC_CONNECTION_CLOSED: - return "EVENT_STREAM_RPC_CONNECTION_CLOSED"; - case EVENT_STREAM_RPC_CONTINUATION_CLOSED: - return "EVENT_STREAM_RPC_CONTINUATION_CLOSED"; - case EVENT_STREAM_RPC_UNKNOWN_PROTOCOL_MESSAGE: - return "EVENT_STREAM_RPC_UNKNOWN_PROTOCOL_MESSAGE"; - case EVENT_STREAM_RPC_UNMAPPED_DATA: - return "EVENT_STREAM_RPC_UNMAPPED_DATA"; - case EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE: - return "EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE"; - case EVENT_STREAM_RPC_CRT_ERROR: - Crt::String ret = "Failed with EVENT_STREAM_RPC_CRT_ERROR, the CRT error was "; - ret += Crt::ErrorDebugString(crtError); - return ret; - } - return "Unknown status code"; - } - - std::future ClientConnection::Connect( + std::future ClientConnectionImpl::Connect( const ConnectionConfig &connectionConfig, ConnectionLifecycleHandler *connectionLifecycleHandler, Crt::Io::ClientBootstrap &clientBootstrap) noexcept @@ -391,9 +522,9 @@ namespace Aws } connOptions.socket_options = &m_socketOptions.GetImpl(); - connOptions.on_connection_setup = ClientConnection::s_onConnectionSetup; - connOptions.on_connection_protocol_message = ClientConnection::s_onProtocolMessage; - connOptions.on_connection_shutdown = ClientConnection::s_onConnectionShutdown; + connOptions.on_connection_setup = ClientConnectionImpl::s_onConnectionSetup; + connOptions.on_connection_protocol_message = ClientConnectionImpl::s_onProtocolMessage; + connOptions.on_connection_shutdown = ClientConnectionImpl::s_onConnectionShutdown; connOptions.user_data = reinterpret_cast(this); m_lifecycleHandler = connectionLifecycleHandler; @@ -427,58 +558,7 @@ namespace Aws return m_connectAckedPromise.get_future(); } - std::future ClientConnection::SendPing( - const Crt::List &headers, - const Crt::Optional &payload, - OnMessageFlushCallback onMessageFlushCallback) noexcept - { - return s_sendPing(this, headers, payload, onMessageFlushCallback); - } - - std::future ClientConnection::SendPingResponse( - const Crt::List &headers, - const Crt::Optional &payload, - OnMessageFlushCallback onMessageFlushCallback) noexcept - { - return s_sendPingResponse(this, headers, payload, onMessageFlushCallback); - } - - std::future ClientConnection::s_sendPing( - ClientConnection *connection, - const Crt::List &headers, - const Crt::Optional &payload, - OnMessageFlushCallback onMessageFlushCallback) noexcept - { - return s_sendProtocolMessage( - connection, headers, payload, AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_PING, 0, onMessageFlushCallback); - } - - std::future ClientConnection::s_sendPingResponse( - ClientConnection *connection, - const Crt::List &headers, - const Crt::Optional &payload, - OnMessageFlushCallback onMessageFlushCallback) noexcept - { - return s_sendProtocolMessage( - connection, - headers, - payload, - AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_PING_RESPONSE, - 0, - onMessageFlushCallback); - } - - std::future ClientConnection::SendProtocolMessage( - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags, - OnMessageFlushCallback onMessageFlushCallback) noexcept - { - return s_sendProtocolMessage(this, headers, payload, messageType, messageFlags, onMessageFlushCallback); - } - - void ClientConnection::s_protocolMessageCallback(int errorCode, void *userData) noexcept + static void s_protocolMessageCallback(int errorCode, void *userData) noexcept { auto *callbackData = static_cast(userData); @@ -504,8 +584,8 @@ namespace Aws Crt::Delete(callbackData, callbackData->allocator); } - std::future ClientConnection::s_sendProtocolMessage( - ClientConnection *connection, + std::future ClientConnectionImpl::s_sendProtocolMessage( + ClientConnectionImpl *connection, const Crt::List &headers, const Crt::Optional &payload, MessageType messageType, @@ -519,9 +599,7 @@ namespace Aws /* The caller should never pass a NULL connection. */ AWS_PRECONDITION(connection != nullptr); - int errorCode = EventStreamCppToNativeCrtBuilder::s_fillNativeHeadersArray( - headers, &headersArray, connection->m_allocator); - + int errorCode = s_fillNativeHeadersArray(headers, &headersArray, connection->m_allocator); if (!errorCode) { struct aws_event_stream_rpc_message_args msg_args; @@ -541,7 +619,7 @@ namespace Aws errorCode = aws_event_stream_rpc_client_connection_send_protocol_message( connection->m_underlyingConnection, &msg_args, - ClientConnection::s_protocolMessageCallback, + s_protocolMessageCallback, reinterpret_cast(callbackContainer)); } @@ -569,7 +647,7 @@ namespace Aws return onFlushPromise.get_future(); } - void ClientConnection::Close() noexcept + void ClientConnectionImpl::Close() noexcept { const std::lock_guard lock(m_stateMutex); @@ -593,105 +671,28 @@ namespace Aws } } - EventStreamHeader::EventStreamHeader( - const struct aws_event_stream_header_value_pair &header, - Crt::Allocator *allocator) - : m_allocator(allocator), m_valueByteBuf({}), m_underlyingHandle(header) - { - } - - EventStreamHeader::EventStreamHeader( - const Crt::String &name, - const Crt::String &value, - Crt::Allocator *allocator) noexcept - : m_allocator(allocator), - m_valueByteBuf(Crt::ByteBufNewCopy(allocator, (uint8_t *)value.c_str(), value.length())) - { - m_underlyingHandle.header_name_len = static_cast(name.length()); - size_t length; - if (name.length() > INT8_MAX) - { - length = INT8_MAX; - } - else - { - length = static_cast(name.length()); - } - (void)memcpy(m_underlyingHandle.header_name, name.c_str(), length); - m_underlyingHandle.header_value_type = AWS_EVENT_STREAM_HEADER_STRING; - m_underlyingHandle.header_value.variable_len_val = m_valueByteBuf.buffer; - m_underlyingHandle.header_value_len = (uint16_t)m_valueByteBuf.len; - } - - EventStreamHeader::~EventStreamHeader() noexcept - { - if (aws_byte_buf_is_valid(&m_valueByteBuf)) - Crt::ByteBufDelete(m_valueByteBuf); - } - - EventStreamHeader::EventStreamHeader(const EventStreamHeader &lhs) noexcept - : m_allocator(lhs.m_allocator), - m_valueByteBuf(Crt::ByteBufNewCopy(lhs.m_allocator, lhs.m_valueByteBuf.buffer, lhs.m_valueByteBuf.len)), - m_underlyingHandle(lhs.m_underlyingHandle) - { - m_underlyingHandle.header_value.variable_len_val = m_valueByteBuf.buffer; - m_underlyingHandle.header_value_len = static_cast(m_valueByteBuf.len); - } - - EventStreamHeader &EventStreamHeader::operator=(const EventStreamHeader &lhs) noexcept - { - m_allocator = lhs.m_allocator; - m_valueByteBuf = Crt::ByteBufNewCopy(lhs.m_allocator, lhs.m_valueByteBuf.buffer, lhs.m_valueByteBuf.len); - m_underlyingHandle = lhs.m_underlyingHandle; - m_underlyingHandle.header_value.variable_len_val = m_valueByteBuf.buffer; - m_underlyingHandle.header_value_len = static_cast(m_valueByteBuf.len); - return *this; - } - - EventStreamHeader::EventStreamHeader(EventStreamHeader &&rhs) noexcept - : m_allocator(rhs.m_allocator), m_valueByteBuf(rhs.m_valueByteBuf), - m_underlyingHandle(rhs.m_underlyingHandle) - { - rhs.m_valueByteBuf.allocator = nullptr; - rhs.m_valueByteBuf.buffer = nullptr; - } - - const struct aws_event_stream_header_value_pair *EventStreamHeader::GetUnderlyingHandle() const - { - return &m_underlyingHandle; - } - - Crt::String EventStreamHeader::GetHeaderName() const noexcept + bool ClientConnectionImpl::IsOpen() const noexcept { - return Crt::String(m_underlyingHandle.header_name, m_underlyingHandle.header_name_len, m_allocator); - } - - bool EventStreamHeader::GetValueAsString(Crt::String &value) const noexcept - { - if (m_underlyingHandle.header_value_type != AWS_EVENT_STREAM_HEADER_STRING) + if (this->m_underlyingConnection == nullptr) { return false; } - value = Crt::String( - reinterpret_cast(m_underlyingHandle.header_value.variable_len_val), - m_underlyingHandle.header_value_len, - m_allocator); - return true; + return aws_event_stream_rpc_client_connection_is_open(this->m_underlyingConnection); } - ClientContinuation ClientConnection::NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept + struct aws_event_stream_rpc_client_connection *ClientConnectionImpl::GetUnderlyingHandle() const noexcept { - return ClientContinuation(this, clientContinuationHandler, m_allocator); + return m_underlyingConnection; } - void ClientConnection::s_onConnectionSetup( + void ClientConnectionImpl::s_onConnectionSetup( struct aws_event_stream_rpc_client_connection *connection, int errorCode, void *userData) noexcept { /* The `userData` pointer is used to pass `this` of a `ClientConnection` object. */ - auto *thisConnection = static_cast(userData); + auto *thisConnection = static_cast(userData); const std::lock_guard lock(thisConnection->m_stateMutex); @@ -745,14 +746,14 @@ namespace Aws thisConnection->m_connectionSetupPromise.set_value(); } - void ClientConnection::s_onConnectionShutdown( + void ClientConnectionImpl::s_onConnectionShutdown( struct aws_event_stream_rpc_client_connection *connection, int errorCode, void *userData) noexcept { (void)connection; /* The `userData` pointer is used to pass `this` of a `ClientConnection` object. */ - auto *thisConnection = static_cast(userData); + auto *thisConnection = static_cast(userData); const std::lock_guard lock(thisConnection->m_stateMutex); @@ -798,7 +799,7 @@ namespace Aws } } - void ClientConnection::s_onProtocolMessage( + void ClientConnectionImpl::s_onProtocolMessage( struct aws_event_stream_rpc_client_connection *connection, const struct aws_event_stream_rpc_message_args *messageArgs, void *userData) noexcept @@ -807,7 +808,7 @@ namespace Aws (void)connection; /* The `userData` pointer is used to pass `this` of a `ClientConnection` object. */ - auto *thisConnection = static_cast(userData); + auto *thisConnection = static_cast(userData); Crt::List pingHeaders; switch (messageArgs->message_type) @@ -883,14 +884,80 @@ namespace Aws } } + ClientContinuation ClientConnectionImpl::NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept + { + return ClientContinuation(m_underlyingConnection, clientContinuationHandler, m_allocator); + } + + ClientConnection::ClientConnection(Crt::Allocator *allocator) noexcept + :m_impl(Aws::Crt::MakeShared(allocator, allocator)) + { + } + + ClientConnection::~ClientConnection() noexcept + { + m_impl->Shutdown(); + m_impl = nullptr; + } + + std::future ClientConnection::Connect( + const ConnectionConfig &connectionOptions, + ConnectionLifecycleHandler *connectionLifecycleHandler, + Crt::Io::ClientBootstrap &clientBootstrap) noexcept + { + return m_impl->Connect(connectionOptions, connectionLifecycleHandler, clientBootstrap); + } + + ClientContinuation ClientConnection::NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept + { + return m_impl->NewStream(clientContinuationHandler); + } + + void ClientConnection::Close() noexcept + { + m_impl->Close(); + } + + bool ClientConnection::IsOpen() const noexcept + { + return m_impl->IsOpen(); + } + + struct aws_event_stream_rpc_client_connection *ClientConnection::GetUnderlyingHandle() const noexcept + { + return m_impl->GetUnderlyingHandle(); + } + void AbstractShapeBase::s_customDeleter(AbstractShapeBase *shape) noexcept { if (shape->m_allocator != nullptr) Crt::Delete(shape, shape->m_allocator); } + struct RawContinuationCallbackDataWrapper + { + RawContinuationCallbackDataWrapper(Aws::Crt::Allocator *allocator, const std::shared_ptr &callbackData) : + m_allocator(allocator), + m_callbackData(callbackData) + {} + + Aws::Crt::Allocator *m_allocator; + std::shared_ptr m_callbackData; + }; + + static void s_onContinuationTerminated(void *user_data) + { + if (user_data == nullptr) + { + return; + } + + struct RawContinuationCallbackDataWrapper *wrapper = static_cast(user_data); + Aws::Crt::Delete(wrapper, wrapper->m_allocator); + } + ClientContinuation::ClientContinuation( - ClientConnection *connection, + struct aws_event_stream_rpc_client_connection *connection, ClientContinuationHandler &continuationHandler, Crt::Allocator *allocator) noexcept : m_allocator(allocator), m_continuationHandler(continuationHandler), m_continuationToken(nullptr) @@ -898,19 +965,19 @@ namespace Aws struct aws_event_stream_rpc_client_stream_continuation_options options; options.on_continuation = ClientContinuation::s_onContinuationMessage; options.on_continuation_closed = ClientContinuation::s_onContinuationClosed; + options.on_continuation_terminated = s_onContinuationTerminated; - m_callbackData = Crt::New(m_allocator, this, m_allocator); + m_callbackData = Crt::MakeShared(m_allocator, this, m_allocator); m_continuationHandler.m_callbackData = m_callbackData; - options.user_data = reinterpret_cast(m_callbackData); + options.user_data = reinterpret_cast(Aws::Crt::New(allocator, allocator, m_callbackData)); - if (connection->IsOpen()) + if (connection) { m_continuationToken = - aws_event_stream_rpc_client_connection_new_stream(connection->m_underlyingConnection, &options); + aws_event_stream_rpc_client_connection_new_stream(connection, &options); if (m_continuationToken == nullptr) { - Crt::Delete(m_callbackData, m_allocator); m_continuationHandler.m_callbackData = nullptr; m_callbackData = nullptr; } @@ -919,18 +986,23 @@ namespace Aws ClientContinuation::~ClientContinuation() noexcept { - if (m_continuationToken) - { - aws_event_stream_rpc_client_continuation_release(m_continuationToken); - m_continuationToken = nullptr; - } + Release(); + } + + void ClientContinuation::Release() + { if (m_callbackData != nullptr) { { const std::lock_guard lock(m_callbackData->callbackMutex); m_callbackData->continuationDestroyed = true; } - Crt::Delete(m_callbackData, m_allocator); + } + + if (m_continuationToken) + { + aws_event_stream_rpc_client_continuation_release(m_continuationToken); + m_continuationToken = nullptr; } } @@ -941,7 +1013,7 @@ namespace Aws { (void)continuationToken; /* The `userData` pointer is used to pass a `ContinuationCallbackData` object. */ - auto *callbackData = static_cast(userData); + auto *callbackData = static_cast(userData)->m_callbackData.get(); auto *thisContinuation = callbackData->clientContinuation; Crt::List continuationMessageHeaders; @@ -976,7 +1048,7 @@ namespace Aws (void)continuationToken; /* The `userData` pointer is used to pass a `ContinuationCallbackData` object. */ - auto *callbackData = static_cast(userData); + auto *callbackData = static_cast(userData)->m_callbackData.get(); const std::lock_guard lock(callbackData->callbackMutex); if (callbackData->continuationDestroyed) @@ -1010,8 +1082,7 @@ namespace Aws return onFlushPromise.get_future(); } - int errorCode = - EventStreamCppToNativeCrtBuilder::s_fillNativeHeadersArray(headers, &headersArray, m_allocator); + int errorCode = s_fillNativeHeadersArray(headers, &headersArray, m_allocator); /* * Regardless of how the promise gets moved around (or not), this future should stay valid as a return @@ -1041,7 +1112,7 @@ namespace Aws m_continuationToken, Crt::ByteCursorFromCString(operationName.c_str()), &msg_args, - ClientConnection::s_protocolMessageCallback, + s_protocolMessageCallback, reinterpret_cast(callbackContainer)); } @@ -1078,8 +1149,7 @@ namespace Aws return onFlushPromise.get_future(); } - int errorCode = - EventStreamCppToNativeCrtBuilder::s_fillNativeHeadersArray(headers, &headersArray, m_allocator); + int errorCode = s_fillNativeHeadersArray(headers, &headersArray, m_allocator); if (!errorCode) { @@ -1101,7 +1171,7 @@ namespace Aws errorCode = aws_event_stream_rpc_client_continuation_send_message( m_continuationToken, &msg_args, - ClientConnection::s_protocolMessageCallback, + s_protocolMessageCallback, reinterpret_cast(callbackContainer)); } } @@ -1168,8 +1238,10 @@ namespace Aws ClientOperation::~ClientOperation() noexcept { Close().wait(); - std::unique_lock lock(m_continuationMutex); - m_closeReady.wait(lock, [this] { return m_expectingClose == false; }); + m_clientContinuation.Release(); + //std::unique_lock lock(m_continuationMutex); + //m_closeReady.wait(lock, [this] { return m_expectingClose == false; }); + } TaggedResult::TaggedResult(Crt::ScopedResource operationResponse) noexcept @@ -1608,7 +1680,7 @@ namespace Aws errorCode = aws_event_stream_rpc_client_continuation_send_message( m_clientContinuation.m_continuationToken, &msg_args, - ClientConnection::s_protocolMessageCallback, + s_protocolMessageCallback, reinterpret_cast(callbackContainer)); } diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index 3d5838d63..abf50b5a4 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -38,19 +38,19 @@ add_test_case(EchoClientConnectSuccess) add_test_case(EchoClientDoubleClose) add_test_case(EchoClientMultiConnectSuccessFail) -add_test_case(EchoClientOperationEchoSuccessString) -add_test_case(EchoClientOperationEchoSuccessBoolean) -add_test_case(EchoClientOperationEchoSuccessTime) -add_test_case(EchoClientOperationEchoSuccessDocument) -add_test_case(EchoClientOperationEchoSuccessEnum) -add_test_case(EchoClientOperationEchoSuccessBlob) -add_test_case(EchoClientOperationEchoSuccessStringList) -add_test_case(EchoClientOperationEchoSuccessPairList) -add_test_case(EchoClientOperationEchoSuccessProductMap) - -add_test_case(EchoClientOperationEchoSuccessMultiple) -add_test_case(EchoClientOperationEchoFailureNeverConnected) -add_test_case(EchoClientOperationEchoFailureDisconnected) +#add_test_case(EchoClientOperationEchoSuccessString) +#add_test_case(EchoClientOperationEchoSuccessBoolean) +#add_test_case(EchoClientOperationEchoSuccessTime) +#add_test_case(EchoClientOperationEchoSuccessDocument) +#add_test_case(EchoClientOperationEchoSuccessEnum) +#add_test_case(EchoClientOperationEchoSuccessBlob) +#add_test_case(EchoClientOperationEchoSuccessStringList) +#add_test_case(EchoClientOperationEchoSuccessPairList) +#add_test_case(EchoClientOperationEchoSuccessProductMap) + +#add_test_case(EchoClientOperationEchoSuccessMultiple) +#add_test_case(EchoClientOperationEchoFailureNeverConnected) +#add_test_case(EchoClientOperationEchoFailureDisconnected) diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index f54aa31df..05dcf2a52 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -291,22 +291,7 @@ static void s_onMessageFlush(int errorCode) } template -static bool s_messageDataMembersAreEqual(Aws::Crt::Optional expectedValue, Aws::Crt::Optional actualValue) -{ - if (expectedValue.has_value() != actualValue.has_value()) - { - return false; - } - - if (expectedValue.has_value()) - { - return expectedValue.value() == actualValue.value(); - } - - return true; -} - -static bool s_messageDataMembersAreEqual(Aws::Crt::Optional expectedValue, Aws::Crt::Optional actualValue) +static bool s_messageDataMembersAreEqual(const Aws::Crt::Optional &expectedValue, const Aws::Crt::Optional &actualValue) { if (expectedValue.has_value() != actualValue.has_value()) { From 8079f33c46546a08a2149c45e33248a2dfd40452 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 14 May 2025 14:43:32 -0700 Subject: [PATCH 32/56] Checkpoint --- .../aws/eventstreamrpc/EventStreamClient.h | 48 +- eventstream_rpc/source/EventStreamClient.cpp | 885 ++++++++++-------- eventstream_rpc/tests/EchoTestRpcClient.cpp | 4 +- .../tests/EventStreamClientTest.cpp | 12 +- .../tests/include/awstest/EchoTestRpcClient.h | 1 - .../aws/greengrass/GreengrassCoreIpcClient.h | 1 - .../source/GreengrassCoreIpcClient.cpp | 4 +- 7 files changed, 522 insertions(+), 433 deletions(-) diff --git a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h index 1414409dd..7f87df0f1 100644 --- a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h +++ b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h @@ -139,6 +139,23 @@ namespace Aws Crt::Allocator *m_allocator; }; + enum EventStreamRpcStatusCode + { + EVENT_STREAM_RPC_SUCCESS = 0, + EVENT_STREAM_RPC_NULL_PARAMETER, + EVENT_STREAM_RPC_UNINITIALIZED, + EVENT_STREAM_RPC_ALLOCATION_ERROR, + EVENT_STREAM_RPC_CONNECTION_SETUP_FAILED, + EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, + EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED, + EVENT_STREAM_RPC_CONNECTION_CLOSED, + EVENT_STREAM_RPC_CONTINUATION_CLOSED, + EVENT_STREAM_RPC_UNKNOWN_PROTOCOL_MESSAGE, + EVENT_STREAM_RPC_UNMAPPED_DATA, + EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE, + EVENT_STREAM_RPC_CRT_ERROR + }; + /** * Configuration structure holding all configurations relating to eventstream RPC connection establishment */ @@ -184,6 +201,8 @@ namespace Aws m_connectRequestCallback = connectRequestCallback; } + EventStreamRpcStatusCode Validate() const noexcept; + protected: Crt::Optional m_hostName; Crt::Optional m_port; @@ -194,23 +213,6 @@ namespace Aws OnMessageFlushCallback m_connectRequestCallback; }; - enum EventStreamRpcStatusCode - { - EVENT_STREAM_RPC_SUCCESS = 0, - EVENT_STREAM_RPC_NULL_PARAMETER, - EVENT_STREAM_RPC_UNINITIALIZED, - EVENT_STREAM_RPC_ALLOCATION_ERROR, - EVENT_STREAM_RPC_CONNECTION_SETUP_FAILED, - EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, - EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED, - EVENT_STREAM_RPC_CONNECTION_CLOSED, - EVENT_STREAM_RPC_CONTINUATION_CLOSED, - EVENT_STREAM_RPC_UNKNOWN_PROTOCOL_MESSAGE, - EVENT_STREAM_RPC_UNMAPPED_DATA, - EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE, - EVENT_STREAM_RPC_CRT_ERROR - }; - struct AWS_EVENTSTREAMRPC_API RpcError { explicit operator bool() const noexcept { return baseStatus == EVENT_STREAM_RPC_SUCCESS; } @@ -268,20 +270,18 @@ namespace Aws { public: - explicit ClientConnection(Crt::Allocator *allocator = Crt::g_allocator) noexcept; + explicit ClientConnection(Crt::Allocator *allocator, aws_client_bootstrap *bootstrap) noexcept; ~ClientConnection() noexcept; /** * Initiates a new outgoing event-stream-rpc connection. * @param connectionOptions Connection options. * @param connectionLifecycleHandler Handler to process connection lifecycle events. - * @param clientBootstrap ClientBootstrap object to run the connection on. * @return Future that will be resolved when connection either succeeds or fails. */ std::future Connect( const ConnectionConfig &connectionOptions, - ConnectionLifecycleHandler *connectionLifecycleHandler, - Crt::Io::ClientBootstrap &clientBootstrap) noexcept; + ConnectionLifecycleHandler *connectionLifecycleHandler) noexcept; /** * Create a new stream. @@ -302,12 +302,6 @@ namespace Aws */ bool IsOpen() const noexcept; - /** - * Returns the C connection object, if it exists. - * @return the C connection object, if it exists. - */ - struct aws_event_stream_rpc_client_connection *GetUnderlyingHandle() const noexcept; - private: std::shared_ptr m_impl; diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index e14bbdeb1..1ab76bf00 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -164,30 +164,20 @@ namespace Aws } } - static int s_fillNativeHeadersArray( + static void s_fillNativeHeadersArray( const Crt::List &headers, struct aws_array_list *headersArray, Crt::Allocator *m_allocator = Crt::g_allocator) { AWS_ZERO_STRUCT(*headersArray); /* Check if the connection has expired before attempting to send. */ - int errorCode = aws_event_stream_headers_list_init(headersArray, m_allocator); + aws_event_stream_headers_list_init(headersArray, m_allocator); - if (!errorCode) + /* Populate the array with the underlying handle of each EventStreamHeader. */ + for (auto &i : headers) { - /* Populate the array with the underlying handle of each EventStreamHeader. */ - for (auto &i : headers) - { - errorCode = aws_array_list_push_back(headersArray, i.GetUnderlyingHandle()); - - if (errorCode) - { - break; - } - } + aws_array_list_push_back(headersArray, i.GetUnderlyingHandle()); } - - return errorCode; } Crt::String RpcError::StatusToString() @@ -226,6 +216,16 @@ namespace Aws return "Unknown status code"; } + EventStreamRpcStatusCode ConnectionConfig::Validate() const noexcept + { + if (!m_hostName.has_value() || !m_port.has_value()) + { + return EVENT_STREAM_RPC_NULL_PARAMETER; + } + + return EVENT_STREAM_RPC_SUCCESS; + } + bool ConnectionLifecycleHandler::OnErrorCallback(RpcError error) { (void)error; @@ -335,17 +335,162 @@ namespace Aws return true; } - class ClientConnectionImpl final +/* + * Eventstream Connection Refactor + * + * Part 1 of an effort to refactor the eventstream bindings to conform to the latest CRT binding guidelines. + * + * For connections, we now enforce the following invariants for correctness: + * + * 1. No callback is made while a lock is held. We perform callbacks by having a transactional callback context that + * is moved out of shared state (under the lock), but the callback context does not perform its work until the lock + * is released. + * 2. No destructor blocking or synchronization. In order to provide the best behavioral backwards compatibility, we + * "synthesize" the callbacks that would occur at destruction when we kick off the async cleanup process. When the + * asynchronous events occur that would normally trigger a callback occur, we ignore them via the has_shut_down flag. + * 3. A self-reference (via shared_ptr member) guarantees the binding impl stays alive longer than the C objects. The + * public binding object also keeps a shared_ptr to the impl, so final destruction only occurs once both the public + * binding object's destructor has run and no C connection object is still alive. + */ + + /* What kind of callback should this context trigger? */ + enum class ConnectionCallbackActionType + { + None, + CompleteConnectPromise, + DisconnectionCallback + }; + + /* + * The purpose of this type is to hide much of the conditional complexity around callbacks that the + * connection implementation faces. Issues include: + * (1) When to complete a promise vs. calling a function + * (2) Tracking what promise to complete + * (3) Helping ensure callbacks always occur once and only once + * (4) Passing delayed state (like an error code) forward until the callback can safely be triggered + * + * We rely heavily on careful move semantics to ensure (2) and (3) + */ + class ConnectionCallbackContext { public: + ConnectionCallbackContext() : m_action(ConnectionCallbackActionType::None), m_error{EVENT_STREAM_RPC_SUCCESS, AWS_ERROR_SUCCESS} {} + + ConnectionCallbackContext(const std::function &disconnectionCallback, const std::function &errorCallback, const std::function &connectionSuccessCallback) : + m_action(ConnectionCallbackActionType::CompleteConnectPromise), + m_error{EVENT_STREAM_RPC_SUCCESS, AWS_ERROR_SUCCESS}, + m_connectPromise(), + m_disconnectionCallback(disconnectionCallback), + m_errorCallback(errorCallback), + m_connectionSuccessCallback(connectionSuccessCallback) + {} + + ConnectionCallbackContext(ConnectionCallbackContext &&rhs) noexcept : + m_action(rhs.m_action), + m_error(rhs.m_error), + m_connectPromise(std::move(rhs.m_connectPromise)), + m_disconnectionCallback(std::move(rhs.m_disconnectionCallback)), + m_errorCallback(std::move(rhs.m_errorCallback)), + m_connectionSuccessCallback(std::move(rhs.m_connectionSuccessCallback)) + { + rhs.ClearContext(); + } + + ConnectionCallbackContext &operator=(ConnectionCallbackContext &&rhs) noexcept + { + m_action = rhs.m_action; + m_error = rhs.m_error; + m_connectPromise = std::move(rhs.m_connectPromise); + m_disconnectionCallback = std::move(rhs.m_disconnectionCallback); + m_errorCallback = std::move(rhs.m_errorCallback); + m_connectionSuccessCallback = std::move(rhs.m_connectionSuccessCallback); + + rhs.ClearContext(); - explicit ClientConnectionImpl(Crt::Allocator *allocator = Crt::g_allocator) noexcept; + return *this; + } + + void InvokeCallbacks() + { + switch (m_action) + { + case ConnectionCallbackActionType::CompleteConnectPromise: + { + if (m_error.crtError != AWS_ERROR_SUCCESS) + { + (void)m_errorCallback(m_error); + } + else + { + m_connectionSuccessCallback(); + } + m_connectPromise.set_value(m_error); + break; + } + case ConnectionCallbackActionType::DisconnectionCallback: + { + m_disconnectionCallback(m_error); + break; + } + default: + break; + } + } + + /* + * Returns a callback context that should be invoked, and moves this context into a state that should be + * invoked when the connection is closed + */ + ConnectionCallbackContext TransitionToConnected() + { + ConnectionCallbackContext context = {}; + context.m_action = ConnectionCallbackActionType::CompleteConnectPromise; + context.m_connectPromise = std::move(m_connectPromise); + context.m_connectionSuccessCallback = m_connectionSuccessCallback; + + m_action = ConnectionCallbackActionType::DisconnectionCallback; + m_error = {EVENT_STREAM_RPC_SUCCESS, AWS_ERROR_SUCCESS}; + m_connectPromise = {}; + + return context; + } + + void SetAction(ConnectionCallbackActionType action) { m_action = action; } + void SetError(RpcError error) { m_error = error; } + + std::future GetConnectPromiseFuture() { return m_connectPromise.get_future(); } + + private: + + /* Wipes out state in a context to guarantee it does nothing if someone tries to InvokeCallbacks on it */ + void ClearContext() + { + m_action = ConnectionCallbackActionType::None; + m_error = {EVENT_STREAM_RPC_SUCCESS, AWS_ERROR_SUCCESS}; + m_connectPromise = {}; + m_disconnectionCallback = {}; + m_errorCallback = {}; + m_connectionSuccessCallback = {}; + } + + ConnectionCallbackActionType m_action; + RpcError m_error; + std::promise m_connectPromise; + std::function m_disconnectionCallback; + std::function m_errorCallback; + std::function m_connectionSuccessCallback; + }; + + class ClientConnectionImpl final : public std::enable_shared_from_this + { + public: + + explicit ClientConnectionImpl(Crt::Allocator *allocator, aws_client_bootstrap *bootstrap) noexcept; ~ClientConnectionImpl() noexcept; std::future Connect( const ConnectionConfig &connectionOptions, - ConnectionLifecycleHandler *connectionLifecycleHandler, - Crt::Io::ClientBootstrap &clientBootstrap) noexcept; + ConnectionLifecycleHandler *connectionLifecycleHandler) noexcept; ClientContinuation NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept; @@ -353,44 +498,56 @@ namespace Aws bool IsOpen() const noexcept; - struct aws_event_stream_rpc_client_connection *GetUnderlyingHandle() const noexcept; - void Shutdown() noexcept; + std::future SendProtocolMessage( + const Crt::List &headers, + const Crt::Optional &payload, + MessageType messageType, + uint32_t messageFlags, + OnMessageFlushCallback onMessageFlushCallback) noexcept; + private: - enum ClientState + void CloseInternal(bool isShutdown) noexcept; + void MoveToDisconnected(RpcError error) noexcept; + + int SendProtocolMessageAux( + const Crt::List &headers, + const Crt::Optional &payload, + MessageType messageType, + uint32_t messageFlags, + OnMessageFlushCallback &&onMessageFlushCallback, + std::promise *sendOutcomePromise, + bool takeLock) noexcept; + + enum class ClientState { - DISCONNECTED = 1, - CONNECTING_SOCKET, - WAITING_FOR_CONNECT_ACK, - CONNECTED, - DISCONNECTING, + Disconnected, + PendingConnect, + PendingConnack, + Connected, + Disconnecting, }; - /* This recursive mutex protects m_clientState & m_connectionWillSetup */ - std::recursive_mutex m_stateMutex; + Crt::Allocator *m_allocator; - struct aws_event_stream_rpc_client_connection *m_underlyingConnection; - ClientState m_clientState; - ConnectionLifecycleHandler *m_lifecycleHandler; + + ConnectionLifecycleHandler *m_lifecycleHandler; // cannot be made a shared_ptr sadly ConnectMessageAmender m_connectMessageAmender; - std::promise m_connectionSetupPromise; - bool m_connectionWillSetup; - std::promise m_connectAckedPromise; - std::promise m_closedPromise; - bool m_onConnectCalled; - RpcError m_closeReason; - OnMessageFlushCallback m_onConnectRequestCallback; - Crt::Io::SocketOptions m_socketOptions; ConnectionConfig m_connectionConfig; + std::shared_ptr m_selfReference; + aws_client_bootstrap *m_bootstrap; + aws_event_loop *m_eventLoop; - static std::future s_sendProtocolMessage( - ClientConnectionImpl *connectionImpl, - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags, - OnMessageFlushCallback onMessageFlushCallback) noexcept; + std::mutex m_sharedStateLock; + struct + { + aws_event_stream_rpc_client_connection *m_underlyingConnection; + ClientState m_currentState; + ClientState m_desiredState; + ConnectionCallbackContext m_callbackContext; + bool m_hasShutDown; + } m_sharedState; static void s_onConnectionShutdown( struct aws_event_stream_rpc_client_connection *connection, @@ -409,153 +566,176 @@ namespace Aws }; - ClientConnectionImpl::ClientConnectionImpl(Crt::Allocator *allocator) noexcept - : m_allocator(allocator), m_underlyingConnection(nullptr), m_clientState(DISCONNECTED), - m_lifecycleHandler(nullptr), m_connectMessageAmender(nullptr), m_connectionWillSetup(false), - m_onConnectCalled(false), m_closeReason{EVENT_STREAM_RPC_SUCCESS, AWS_ERROR_SUCCESS}, - m_onConnectRequestCallback(nullptr) + ClientConnectionImpl::ClientConnectionImpl(Crt::Allocator *allocator, aws_client_bootstrap *bootstrap) noexcept + : m_allocator(allocator), m_lifecycleHandler(nullptr), m_connectMessageAmender(nullptr), + m_bootstrap(aws_client_bootstrap_acquire(bootstrap)), m_eventLoop(nullptr), + m_sharedState { nullptr, ClientState::Disconnected, ClientState::Disconnected, {}, false} { + m_eventLoop = aws_event_loop_group_get_next_loop(bootstrap->event_loop_group); } ClientConnectionImpl::~ClientConnectionImpl() noexcept { - m_stateMutex.lock(); - bool waitForSetup = m_connectionWillSetup; - m_stateMutex.unlock(); + aws_client_bootstrap_release(m_bootstrap); + } - if (waitForSetup) - { - m_connectionSetupPromise.get_future().wait(); - } + // We use a task to zero out the self reference to make sure we are not in a call stack that includes + // a member function of the connection impl itself when potentially releasing the final reference. + struct AwsEventstreamConnectionImplClearSharedTask { + AwsEventstreamConnectionImplClearSharedTask(Aws::Crt::Allocator *allocator, ClientConnectionImpl *clientConnectionImpl) noexcept; - bool waitForClosed = false; - m_stateMutex.lock(); - if (m_clientState != DISCONNECTED) - { - Close(); - waitForClosed = true; - } - m_stateMutex.unlock(); + struct aws_task m_task; + struct aws_allocator *m_allocator; + std::shared_ptr m_impl; + }; - if (waitForClosed) - { - m_closedPromise.get_future().wait(); - } + static void s_zeroSharedReference(struct aws_task *task, void *arg, enum aws_task_status status) + { + auto clearSharedTask = static_cast(arg); - m_underlyingConnection = nullptr; + // implicit destructor does all the work + Aws::Crt::Delete(clearSharedTask, clearSharedTask->m_allocator); } - void ClientConnectionImpl::Shutdown() noexcept + AwsEventstreamConnectionImplClearSharedTask::AwsEventstreamConnectionImplClearSharedTask(Aws::Crt::Allocator *allocator, ClientConnectionImpl *clientConnectionImpl) noexcept : + m_task{}, + m_allocator(allocator), + m_impl(clientConnectionImpl->shared_from_this()) { - + aws_task_init(&m_task, s_zeroSharedReference, this, "AwsEventstreamConnectionImplClearSharedTask"); } - std::future ClientConnectionImpl::Connect( - const ConnectionConfig &connectionConfig, - ConnectionLifecycleHandler *connectionLifecycleHandler, - Crt::Io::ClientBootstrap &clientBootstrap) noexcept + void ClientConnectionImpl::MoveToDisconnected(RpcError error) noexcept { - EventStreamRpcStatusCode baseError = EVENT_STREAM_RPC_SUCCESS; - struct aws_event_stream_rpc_client_connection_options connOptions; - + auto *clearSharedTask = Aws::Crt::New(m_allocator, m_allocator, this); + ConnectionCallbackContext localContext = {}; { - const std::lock_guard lock(m_stateMutex); - if (m_clientState == DISCONNECTED) - { - m_clientState = CONNECTING_SOCKET; - m_onConnectCalled = false; - m_connectionSetupPromise = {}; - m_connectAckedPromise = {}; - m_closedPromise = {}; - m_closeReason = {EVENT_STREAM_RPC_UNINITIALIZED, 0}; - m_connectionConfig = connectionConfig; - m_lifecycleHandler = connectionLifecycleHandler; - } - else + std::lock_guard lock(m_sharedStateLock); + + aws_event_stream_rpc_client_connection_release(m_sharedState.m_underlyingConnection); + m_sharedState.m_underlyingConnection = nullptr; + m_sharedState.m_currentState = ClientState::Disconnected; + m_sharedState.m_desiredState = ClientState::Disconnected; + m_sharedState.m_callbackContext.SetError(error); + m_selfReference = nullptr; + if (!m_sharedState.m_hasShutDown) { - baseError = EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED; + localContext = std::move(m_sharedState.m_callbackContext); } + m_sharedState.m_callbackContext = {}; } - m_onConnectRequestCallback = m_connectionConfig.GetConnectRequestCallback(); - Crt::String hostName; + localContext.InvokeCallbacks(); + aws_event_loop_schedule_task_now(m_eventLoop, &clearSharedTask->m_task); + } - if (baseError == EVENT_STREAM_RPC_SUCCESS) + void ClientConnectionImpl::CloseInternal(bool isShutdown) noexcept + { + ConnectionCallbackContext localContext = {}; { - AWS_ZERO_STRUCT(connOptions); - if (m_connectionConfig.GetHostName().has_value()) + std::lock_guard lock(m_sharedStateLock); + m_sharedState.m_desiredState = ClientState::Disconnected; + m_sharedState.m_callbackContext.SetError({EVENT_STREAM_RPC_CONNECTION_CLOSED, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED}); + if (isShutdown) { - hostName = m_connectionConfig.GetHostName().value(); - connOptions.host_name = hostName.c_str(); + m_sharedState.m_hasShutDown = true; } - else - { - baseError = EVENT_STREAM_RPC_NULL_PARAMETER; - } - if (m_connectionConfig.GetPort().has_value()) + + if (m_sharedState.m_currentState == ClientState::Connected || m_sharedState.m_currentState == ClientState::PendingConnack) { - connOptions.port = m_connectionConfig.GetPort().value(); + m_sharedState.m_currentState = ClientState::Disconnecting; + aws_event_stream_rpc_client_connection_close(m_sharedState.m_underlyingConnection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); } - else + + if (isShutdown) { - baseError = EVENT_STREAM_RPC_NULL_PARAMETER; + localContext = std::move(m_sharedState.m_callbackContext); } + } + + localContext.InvokeCallbacks(); + } + + void ClientConnectionImpl::Shutdown() noexcept + { + CloseInternal(true); + } + + void ClientConnectionImpl::Close() noexcept + { + CloseInternal(false); + } - connOptions.bootstrap = clientBootstrap.GetUnderlyingHandle(); + std::future ClientConnectionImpl::Connect( + const ConnectionConfig &connectionConfig, + ConnectionLifecycleHandler *connectionLifecycleHandler) noexcept + { + EventStreamRpcStatusCode status = connectionConfig.Validate(); + if (status != EVENT_STREAM_RPC_SUCCESS) + { + std::promise localPromise; + localPromise.set_value({status, AWS_ERROR_INVALID_ARGUMENT}); + + return localPromise.get_future(); } - if (baseError) + std::future localFuture = {}; { - std::promise errorPromise; - errorPromise.set_value({baseError, 0}); - if (baseError == EVENT_STREAM_RPC_NULL_PARAMETER) + std::lock_guard lock(m_sharedStateLock); + if (m_sharedState.m_currentState != ClientState::Disconnected) { - const std::lock_guard lock(m_stateMutex); - m_clientState = DISCONNECTED; + std::promise localPromise; + localPromise.set_value({EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED, AWS_ERROR_SUCCESS}); + return localPromise.get_future(); } - return errorPromise.get_future(); + + m_lifecycleHandler = connectionLifecycleHandler; + std::function disconnectCallback = [this](RpcError error) { this->m_lifecycleHandler->OnDisconnectCallback(error); }; + std::function errorCallback = [this](RpcError error){ return this->m_lifecycleHandler->OnErrorCallback(error); }; + std::function connectionSuccessCallback = [this](){ this->m_lifecycleHandler->OnConnectCallback(); }; + + m_connectionConfig = connectionConfig; + m_selfReference = shared_from_this(); + m_sharedState.m_desiredState = ClientState::Connected; + m_sharedState.m_currentState = ClientState::PendingConnect; + m_sharedState.m_callbackContext = {std::move(disconnectCallback), std::move(errorCallback), std::move(connectionSuccessCallback)}; + localFuture = m_sharedState.m_callbackContext.GetConnectPromiseFuture(); } + Crt::Io::SocketOptions socketOptions; if (m_connectionConfig.GetSocketOptions().has_value()) { - m_socketOptions = m_connectionConfig.GetSocketOptions().value(); + socketOptions = m_connectionConfig.GetSocketOptions().value(); } - connOptions.socket_options = &m_socketOptions.GetImpl(); - - connOptions.on_connection_setup = ClientConnectionImpl::s_onConnectionSetup; - connOptions.on_connection_protocol_message = ClientConnectionImpl::s_onProtocolMessage; - connOptions.on_connection_shutdown = ClientConnectionImpl::s_onConnectionShutdown; - connOptions.user_data = reinterpret_cast(this); - m_lifecycleHandler = connectionLifecycleHandler; - m_connectMessageAmender = m_connectionConfig.GetConnectMessageAmender(); + struct aws_event_stream_rpc_client_connection_options connectOptions = { + .host_name = connectionConfig.GetHostName().value().c_str(), + .port = connectionConfig.GetPort().value(), + .bootstrap = m_bootstrap, + .socket_options = &socketOptions.GetImpl(), + .on_connection_setup = ClientConnectionImpl::s_onConnectionSetup, + .on_connection_protocol_message = ClientConnectionImpl::s_onProtocolMessage, + .on_connection_shutdown = ClientConnectionImpl::s_onConnectionShutdown, + .user_data = reinterpret_cast(this), + }; if (m_connectionConfig.GetTlsConnectionOptions().has_value()) { - connOptions.tls_options = m_connectionConfig.GetTlsConnectionOptions()->GetUnderlyingHandle(); + connectOptions.tls_options = m_connectionConfig.GetTlsConnectionOptions()->GetUnderlyingHandle(); } - int crtError = aws_event_stream_rpc_client_connection_connect(m_allocator, &connOptions); - - if (crtError) + if (aws_event_stream_rpc_client_connection_connect(m_allocator, &connectOptions)) { - std::promise errorPromise; - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "A CRT error occurred while attempting to establish the connection: %s", - Crt::ErrorDebugString(crtError)); - errorPromise.set_value({EVENT_STREAM_RPC_CRT_ERROR, crtError}); - const std::lock_guard lock(m_stateMutex); - m_clientState = DISCONNECTED; - return errorPromise.get_future(); - } - else - { - const std::lock_guard lock(m_stateMutex); - m_connectionWillSetup = true; + MoveToDisconnected({EVENT_STREAM_RPC_CONNECTION_SETUP_FAILED, aws_last_error()}); } - return m_connectAckedPromise.get_future(); + return localFuture; + } + + bool ClientConnectionImpl::IsOpen() const noexcept + { + std::lock_guard lock(const_cast(this)->m_sharedStateLock); + return m_sharedState.m_currentState == ClientState::Connected; } static void s_protocolMessageCallback(int errorCode, void *userData) noexcept @@ -584,43 +764,59 @@ namespace Aws Crt::Delete(callbackData, callbackData->allocator); } - std::future ClientConnectionImpl::s_sendProtocolMessage( - ClientConnectionImpl *connection, + ClientContinuation ClientConnectionImpl::NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept + { + std::lock_guard lock(m_sharedStateLock); + return {m_sharedState.m_underlyingConnection, clientContinuationHandler, m_allocator}; + } + + int ClientConnectionImpl::SendProtocolMessageAux( const Crt::List &headers, const Crt::Optional &payload, MessageType messageType, uint32_t messageFlags, - OnMessageFlushCallback onMessageFlushCallback) noexcept + OnMessageFlushCallback &&onMessageFlushCallback, + std::promise *sendOutcomePromise, + bool takeLock) noexcept { - std::promise onFlushPromise; OnMessageFlushCallbackContainer *callbackContainer = nullptr; struct aws_array_list headersArray; - /* The caller should never pass a NULL connection. */ - AWS_PRECONDITION(connection != nullptr); + s_fillNativeHeadersArray(headers, &headersArray, m_allocator); + struct aws_event_stream_rpc_message_args msg_args; + msg_args.headers = (struct aws_event_stream_header_value_pair *)headersArray.data; + msg_args.headers_count = headers.size(); + msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; + msg_args.message_type = messageType; + msg_args.message_flags = messageFlags; - int errorCode = s_fillNativeHeadersArray(headers, &headersArray, connection->m_allocator); - if (!errorCode) + callbackContainer = Crt::New(m_allocator, m_allocator); + callbackContainer->onMessageFlushCallback = std::move(onMessageFlushCallback); + if (sendOutcomePromise) { - struct aws_event_stream_rpc_message_args msg_args; - msg_args.headers = (struct aws_event_stream_header_value_pair *)headersArray.data; - msg_args.headers_count = headers.size(); - msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; - msg_args.message_type = messageType; - msg_args.message_flags = messageFlags; + callbackContainer->onFlushPromise = std::move(*sendOutcomePromise); + } - /* This heap allocation is necessary so that the flush callback can still be invoked when this function - * returns. */ - callbackContainer = - Crt::New(connection->m_allocator, connection->m_allocator); - callbackContainer->onMessageFlushCallback = onMessageFlushCallback; - callbackContainer->onFlushPromise = std::move(onFlushPromise); + int errorCode = AWS_ERROR_SUCCESS; + { + if (takeLock) + { + m_sharedStateLock.lock(); + } - errorCode = aws_event_stream_rpc_client_connection_send_protocol_message( - connection->m_underlyingConnection, + if (aws_event_stream_rpc_client_connection_send_protocol_message( + m_sharedState.m_underlyingConnection, &msg_args, s_protocolMessageCallback, - reinterpret_cast(callbackContainer)); + reinterpret_cast(callbackContainer))) + { + errorCode = aws_last_error(); + } + + if (takeLock) + { + m_sharedStateLock.unlock(); + } } /* Cleanup. */ @@ -631,59 +827,33 @@ namespace Aws if (errorCode) { - onFlushPromise = std::move(callbackContainer->onFlushPromise); AWS_LOGF_ERROR( AWS_LS_EVENT_STREAM_RPC_CLIENT, "A CRT error occurred while queueing a message to be sent on the connection: %s", Crt::ErrorDebugString(errorCode)); - onFlushPromise.set_value({EVENT_STREAM_RPC_CRT_ERROR, errorCode}); - Crt::Delete(callbackContainer, connection->m_allocator); - } - else - { - return callbackContainer->onFlushPromise.get_future(); - } - - return onFlushPromise.get_future(); - } - - void ClientConnectionImpl::Close() noexcept - { - const std::lock_guard lock(m_stateMutex); - - if (IsOpen()) - { - aws_event_stream_rpc_client_connection_close(this->m_underlyingConnection, AWS_OP_SUCCESS); - } - else if (m_clientState == CONNECTING_SOCKET && !m_connectionWillSetup) - { - m_connectAckedPromise.set_value({EVENT_STREAM_RPC_CONNECTION_CLOSED, 0}); - } + if (sendOutcomePromise) + { + sendOutcomePromise->set_value({EVENT_STREAM_RPC_CRT_ERROR, errorCode}); + } - if (m_clientState != DISCONNECTING && m_clientState != DISCONNECTED) - { - m_clientState = DISCONNECTING; + Crt::Delete(callbackContainer, m_allocator); } - if (m_closeReason.baseStatus == EVENT_STREAM_RPC_UNINITIALIZED) - { - m_closeReason = {EVENT_STREAM_RPC_CONNECTION_CLOSED, 0}; - } + return (errorCode == AWS_ERROR_SUCCESS) ? AWS_OP_SUCCESS : AWS_OP_ERR; } - bool ClientConnectionImpl::IsOpen() const noexcept + std::future ClientConnectionImpl::SendProtocolMessage( + const Crt::List &headers, + const Crt::Optional &payload, + MessageType messageType, + uint32_t messageFlags, + OnMessageFlushCallback onMessageFlushCallback) noexcept { - if (this->m_underlyingConnection == nullptr) - { - return false; - } + std::promise sendOutcomePromise; + auto sendOutcomeFuture = sendOutcomePromise.get_future(); + SendProtocolMessageAux(headers, payload, messageType, messageFlags, std::move(onMessageFlushCallback), &sendOutcomePromise, true); - return aws_event_stream_rpc_client_connection_is_open(this->m_underlyingConnection); - } - - struct aws_event_stream_rpc_client_connection *ClientConnectionImpl::GetUnderlyingHandle() const noexcept - { - return m_underlyingConnection; + return sendOutcomeFuture; } void ClientConnectionImpl::s_onConnectionSetup( @@ -691,59 +861,53 @@ namespace Aws int errorCode, void *userData) noexcept { - /* The `userData` pointer is used to pass `this` of a `ClientConnection` object. */ - auto *thisConnection = static_cast(userData); - - const std::lock_guard lock(thisConnection->m_stateMutex); - - if (errorCode) + auto *impl = static_cast(userData); + if (errorCode != AWS_ERROR_SUCCESS) { - thisConnection->m_clientState = DISCONNECTED; - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "A CRT error occurred while setting up the connection: %s", - Crt::ErrorDebugString(errorCode)); - thisConnection->m_connectAckedPromise.set_value({EVENT_STREAM_RPC_CRT_ERROR, errorCode}); - aws_event_stream_rpc_client_connection_release(connection); - thisConnection->m_underlyingConnection = nullptr; - /* No connection to close on error, so no need to check return value of the callback. */ - (void)thisConnection->m_lifecycleHandler->OnErrorCallback({EVENT_STREAM_RPC_CRT_ERROR, errorCode}); - } - else if (thisConnection->m_clientState == DISCONNECTING || thisConnection->m_clientState == DISCONNECTED) - { - thisConnection->m_underlyingConnection = connection; - thisConnection->m_closeReason = {EVENT_STREAM_RPC_CONNECTION_CLOSED, 0}; - thisConnection->Close(); + AWS_FATAL_ASSERT(connection == nullptr); + impl->MoveToDisconnected({EVENT_STREAM_RPC_CRT_ERROR, errorCode}); + return; } - else + + AWS_FATAL_ASSERT(connection != nullptr); { - thisConnection->m_clientState = WAITING_FOR_CONNECT_ACK; - thisConnection->m_underlyingConnection = connection; + std::lock_guard lock(impl->m_sharedStateLock); + AWS_FATAL_ASSERT(impl->m_sharedState.m_currentState == ClientState::PendingConnect); + impl->m_sharedState.m_underlyingConnection = connection; + if (impl->m_sharedState.m_desiredState != ClientState::Connected) + { + AWS_FATAL_ASSERT(impl->m_sharedState.m_desiredState == ClientState::Disconnected); + impl->m_sharedState.m_currentState = ClientState::Disconnecting; + aws_event_stream_rpc_client_connection_close(connection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); + return; + } + + impl->m_sharedState.m_currentState = ClientState::PendingConnack; MessageAmendment messageAmendment; - if (thisConnection->m_connectMessageAmender) + if (impl->m_connectionConfig.GetConnectAmendment().has_value()) { - MessageAmendment connectAmendment(thisConnection->m_connectMessageAmender()); - /* The version header is necessary for establishing the connection. */ + MessageAmendment connectAmendment(impl->m_connectionConfig.GetConnectAmendment().value()); + // The version header is necessary for establishing the connection. messageAmendment.AddHeader(EventStreamHeader( Crt::String(EVENTSTREAM_VERSION_HEADER), Crt::String(EVENTSTREAM_VERSION_STRING), - thisConnection->m_allocator)); + impl->m_allocator)); messageAmendment.PrependHeaders(std::move(connectAmendment).GetHeaders()); messageAmendment.SetPayload(std::move(connectAmendment).GetPayload()); } - /* Send a CONNECT packet to the server. */ - s_sendProtocolMessage( - thisConnection, - messageAmendment.GetHeaders(), + if (impl->SendProtocolMessageAux( messageAmendment.GetHeaders(), messageAmendment.GetPayload(), AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_CONNECT, 0U, - thisConnection->m_onConnectRequestCallback); + impl->m_connectionConfig.GetConnectRequestCallback(), nullptr, false)) + { + impl->m_sharedState.m_callbackContext.SetError({EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}); + impl->m_sharedState.m_currentState = ClientState::Disconnecting; + aws_event_stream_rpc_client_connection_close(connection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); + } } - - thisConnection->m_connectionSetupPromise.set_value(); } void ClientConnectionImpl::s_onConnectionShutdown( @@ -752,51 +916,9 @@ namespace Aws void *userData) noexcept { (void)connection; - /* The `userData` pointer is used to pass `this` of a `ClientConnection` object. */ - auto *thisConnection = static_cast(userData); - - const std::lock_guard lock(thisConnection->m_stateMutex); - - if (thisConnection->m_closeReason.baseStatus == EVENT_STREAM_RPC_UNINITIALIZED && errorCode) - { - thisConnection->m_closeReason = {EVENT_STREAM_RPC_CRT_ERROR, errorCode}; - } - - thisConnection->m_underlyingConnection = nullptr; - - if (thisConnection->m_closeReason.baseStatus != EVENT_STREAM_RPC_UNINITIALIZED && - !thisConnection->m_onConnectCalled) - { - thisConnection->m_connectAckedPromise.set_value(thisConnection->m_closeReason); - } - - thisConnection->m_clientState = DISCONNECTED; - - if (thisConnection->m_onConnectCalled) - { - if (errorCode) - { - thisConnection->m_lifecycleHandler->OnDisconnectCallback({EVENT_STREAM_RPC_CRT_ERROR, errorCode}); - } - else - { - thisConnection->m_lifecycleHandler->OnDisconnectCallback({EVENT_STREAM_RPC_SUCCESS, 0}); - } - thisConnection->m_onConnectCalled = false; - } + auto *impl = static_cast(userData); - if (errorCode) - { - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "A CRT error occurred while shutting down the connection: %s", - Crt::ErrorDebugString(errorCode)); - thisConnection->m_closedPromise.set_value({EVENT_STREAM_RPC_CRT_ERROR, errorCode}); - } - else - { - thisConnection->m_closedPromise.set_value({EVENT_STREAM_RPC_SUCCESS, errorCode}); - } + impl->MoveToDisconnected({EVENT_STREAM_RPC_CONNECTION_CLOSED, errorCode}); } void ClientConnectionImpl::s_onProtocolMessage( @@ -807,90 +929,73 @@ namespace Aws AWS_PRECONDITION(messageArgs != nullptr); (void)connection; - /* The `userData` pointer is used to pass `this` of a `ClientConnection` object. */ - auto *thisConnection = static_cast(userData); - Crt::List pingHeaders; - + auto *impl = static_cast(userData); switch (messageArgs->message_type) { case AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_CONNECT_ACK: - thisConnection->m_stateMutex.lock(); - if (thisConnection->m_clientState == WAITING_FOR_CONNECT_ACK) + { + ConnectionCallbackContext localCallbackContext = {}; + bool successfulAck = (messageArgs->message_flags & AWS_EVENT_STREAM_RPC_MESSAGE_FLAG_CONNECTION_ACCEPTED) != 0; { - if (messageArgs->message_flags & AWS_EVENT_STREAM_RPC_MESSAGE_FLAG_CONNECTION_ACCEPTED) + std::lock_guard lock(impl->m_sharedStateLock); + if (impl->m_sharedState.m_currentState != ClientState::PendingConnack || !successfulAck) { - thisConnection->m_clientState = CONNECTED; - thisConnection->m_onConnectCalled = true; - thisConnection->m_connectAckedPromise.set_value({EVENT_STREAM_RPC_SUCCESS, 0}); - thisConnection->m_lifecycleHandler->OnConnectCallback(); + if (!impl->m_sharedState.m_hasShutDown) + { + impl->m_sharedState.m_callbackContext.SetError( + (successfulAck) ? RpcError{EVENT_STREAM_RPC_CONNECTION_CLOSED, 0} : RpcError{EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, 0} + ); + } + impl->m_sharedState.m_desiredState = ClientState::Disconnected; + if (impl->m_sharedState.m_currentState != ClientState::Disconnecting) + { + impl->m_sharedState.m_currentState = ClientState::Disconnecting; + aws_event_stream_rpc_client_connection_close(impl->m_sharedState.m_underlyingConnection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); + } + return; } - else - { - thisConnection->m_closeReason = {EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, 0}; - thisConnection->Close(); - } - } - else - { - /* Unexpected CONNECT_ACK received. */ - } - thisConnection->m_stateMutex.unlock(); + impl->m_sharedState.m_currentState = ClientState::Connected; + localCallbackContext = impl->m_sharedState.m_callbackContext.TransitionToConnected(); + } + localCallbackContext.InvokeCallbacks(); break; + } case AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_PING: - + { + Crt::List pingHeaders; for (size_t i = 0; i < messageArgs->headers_count; ++i) { pingHeaders.emplace_back( - EventStreamHeader(messageArgs->headers[i], thisConnection->m_allocator)); + EventStreamHeader(messageArgs->headers[i], impl->m_allocator)); } if (messageArgs->payload) { - thisConnection->m_lifecycleHandler->OnPingCallback(pingHeaders, *messageArgs->payload); + impl->m_lifecycleHandler->OnPingCallback(pingHeaders, *messageArgs->payload); } else { - thisConnection->m_lifecycleHandler->OnPingCallback(pingHeaders, Crt::Optional()); + impl->m_lifecycleHandler->OnPingCallback(pingHeaders, Crt::Optional()); } break; + } case AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_PING_RESPONSE: - return; - break; - - case AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_PROTOCOL_ERROR: - case AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_INTERNAL_ERROR: - - if (thisConnection->m_lifecycleHandler->OnErrorCallback( - {EVENT_STREAM_RPC_CRT_ERROR, AWS_ERROR_EVENT_STREAM_RPC_PROTOCOL_ERROR})) - { - thisConnection->Close(); - } - break; default: - - if (thisConnection->m_lifecycleHandler->OnErrorCallback( - {EVENT_STREAM_RPC_UNKNOWN_PROTOCOL_MESSAGE, 0})) - { - thisConnection->Close(); - } - + impl->m_lifecycleHandler->OnErrorCallback( + {EVENT_STREAM_RPC_CRT_ERROR, AWS_ERROR_EVENT_STREAM_RPC_PROTOCOL_ERROR}); + impl->Close(); break; } } - ClientContinuation ClientConnectionImpl::NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept - { - return ClientContinuation(m_underlyingConnection, clientContinuationHandler, m_allocator); - } - - ClientConnection::ClientConnection(Crt::Allocator *allocator) noexcept - :m_impl(Aws::Crt::MakeShared(allocator, allocator)) + ClientConnection::ClientConnection(Crt::Allocator *allocator, aws_client_bootstrap *bootstrap) noexcept + :m_impl(Aws::Crt::MakeShared(allocator, allocator, bootstrap)) { } @@ -902,10 +1007,9 @@ namespace Aws std::future ClientConnection::Connect( const ConnectionConfig &connectionOptions, - ConnectionLifecycleHandler *connectionLifecycleHandler, - Crt::Io::ClientBootstrap &clientBootstrap) noexcept + ConnectionLifecycleHandler *connectionLifecycleHandler) noexcept { - return m_impl->Connect(connectionOptions, connectionLifecycleHandler, clientBootstrap); + return m_impl->Connect(connectionOptions, connectionLifecycleHandler); } ClientContinuation ClientConnection::NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept @@ -923,11 +1027,6 @@ namespace Aws return m_impl->IsOpen(); } - struct aws_event_stream_rpc_client_connection *ClientConnection::GetUnderlyingHandle() const noexcept - { - return m_impl->GetUnderlyingHandle(); - } - void AbstractShapeBase::s_customDeleter(AbstractShapeBase *shape) noexcept { if (shape->m_allocator != nullptr) @@ -1082,7 +1181,7 @@ namespace Aws return onFlushPromise.get_future(); } - int errorCode = s_fillNativeHeadersArray(headers, &headersArray, m_allocator); + s_fillNativeHeadersArray(headers, &headersArray, m_allocator); /* * Regardless of how the promise gets moved around (or not), this future should stay valid as a return @@ -1093,28 +1192,25 @@ namespace Aws */ std::future retValue = onFlushPromise.get_future(); - if (!errorCode) - { - struct aws_event_stream_rpc_message_args msg_args; - msg_args.headers = (struct aws_event_stream_header_value_pair *)headersArray.data; - msg_args.headers_count = headers.size(); - msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; - msg_args.message_type = messageType; - msg_args.message_flags = messageFlags; - - /* This heap allocation is necessary so that the flush callback can still be invoked when this function - * returns. */ - callbackContainer = Crt::New(m_allocator, m_allocator); - callbackContainer->onMessageFlushCallback = onMessageFlushCallback; - callbackContainer->onFlushPromise = std::move(onFlushPromise); - - errorCode = aws_event_stream_rpc_client_continuation_activate( - m_continuationToken, - Crt::ByteCursorFromCString(operationName.c_str()), - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(callbackContainer)); - } + struct aws_event_stream_rpc_message_args msg_args; + msg_args.headers = (struct aws_event_stream_header_value_pair *)headersArray.data; + msg_args.headers_count = headers.size(); + msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; + msg_args.message_type = messageType; + msg_args.message_flags = messageFlags; + + /* This heap allocation is necessary so that the flush callback can still be invoked when this function + * returns. */ + callbackContainer = Crt::New(m_allocator, m_allocator); + callbackContainer->onMessageFlushCallback = onMessageFlushCallback; + callbackContainer->onFlushPromise = std::move(onFlushPromise); + + int errorCode = aws_event_stream_rpc_client_continuation_activate( + m_continuationToken, + Crt::ByteCursorFromCString(operationName.c_str()), + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(callbackContainer)); /* Cleanup. */ if (aws_array_list_is_valid(&headersArray)) @@ -1149,30 +1245,31 @@ namespace Aws return onFlushPromise.get_future(); } - int errorCode = s_fillNativeHeadersArray(headers, &headersArray, m_allocator); + s_fillNativeHeadersArray(headers, &headersArray, m_allocator); - if (!errorCode) - { - struct aws_event_stream_rpc_message_args msg_args; - msg_args.headers = (struct aws_event_stream_header_value_pair *)headersArray.data; - msg_args.headers_count = headers.size(); - msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; - msg_args.message_type = messageType; - msg_args.message_flags = messageFlags; + struct aws_event_stream_rpc_message_args msg_args; + msg_args.headers = (struct aws_event_stream_header_value_pair *)headersArray.data; + msg_args.headers_count = headers.size(); + msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; + msg_args.message_type = messageType; + msg_args.message_flags = messageFlags; - /* This heap allocation is necessary so that the flush callback can still be invoked when this function - * returns. */ - callbackContainer = Crt::New(m_allocator, m_allocator); - callbackContainer->onMessageFlushCallback = onMessageFlushCallback; - callbackContainer->onFlushPromise = std::move(onFlushPromise); + /* This heap allocation is necessary so that the flush callback can still be invoked when this function + * returns. */ + callbackContainer = Crt::New(m_allocator, m_allocator); + callbackContainer->onMessageFlushCallback = onMessageFlushCallback; + callbackContainer->onFlushPromise = std::move(onFlushPromise); - if (m_continuationToken) + int errorCode = AWS_OP_SUCCESS; + if (m_continuationToken) + { + if (aws_event_stream_rpc_client_continuation_send_message( + m_continuationToken, + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(callbackContainer))) { - errorCode = aws_event_stream_rpc_client_continuation_send_message( - m_continuationToken, - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(callbackContainer)); + errorCode = aws_last_error(); } } diff --git a/eventstream_rpc/tests/EchoTestRpcClient.cpp b/eventstream_rpc/tests/EchoTestRpcClient.cpp index 05fe07477..ee911b0c8 100644 --- a/eventstream_rpc/tests/EchoTestRpcClient.cpp +++ b/eventstream_rpc/tests/EchoTestRpcClient.cpp @@ -14,7 +14,7 @@ namespace Awstest EchoTestRpcClient::EchoTestRpcClient( Aws::Crt::Io::ClientBootstrap &clientBootstrap, Aws::Crt::Allocator *allocator) noexcept - : m_connection(allocator), m_clientBootstrap(clientBootstrap), m_allocator(allocator), + : m_connection(allocator, clientBootstrap.GetUnderlyingHandle()), m_allocator(allocator), m_asyncLaunchMode(std::launch::deferred) { m_echoTestRpcServiceModel.AssignModelNameToErrorResponse( @@ -25,7 +25,7 @@ namespace Awstest ConnectionLifecycleHandler &lifecycleHandler, const ConnectionConfig &connectionConfig) noexcept { - return m_connection.Connect(connectionConfig, &lifecycleHandler, m_clientBootstrap); + return m_connection.Connect(connectionConfig, &lifecycleHandler); } void EchoTestRpcClient::Close() noexcept diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 05dcf2a52..9082678f2 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -131,8 +131,8 @@ static int s_TestEventStreamConnectSuccess(struct aws_allocator *allocator, void connectionConfig.SetConnectAmendment(connectionAmendment); TestLifecycleHandler lifecycleHandler; - ClientConnection connection(allocator); - auto future = connection.Connect(connectionConfig, &lifecycleHandler, *testContext.clientBootstrap); + ClientConnection connection(allocator, testContext.clientBootstrap->GetUnderlyingHandle()); + auto future = connection.Connect(connectionConfig, &lifecycleHandler); EventStreamRpcStatusCode clientStatus = future.get().baseStatus; ASSERT_INT_EQUALS(EVENT_STREAM_RPC_SUCCESS, clientStatus); @@ -159,8 +159,8 @@ static int s_TestEventStreamConnectFailureNoAuthHeader(struct aws_allocator *all connectionConfig.SetPort(testContext.echoServerPort); TestLifecycleHandler lifecycleHandler; - ClientConnection connection(allocator); - auto future = connection.Connect(connectionConfig, &lifecycleHandler, *testContext.clientBootstrap); + ClientConnection connection(allocator, testContext.clientBootstrap->GetUnderlyingHandle()); + auto future = connection.Connect(connectionConfig, &lifecycleHandler); EventStreamRpcStatusCode clientStatus = future.get().baseStatus; ASSERT_TRUE( @@ -193,8 +193,8 @@ static int s_TestEventStreamConnectFailureBadAuthHeader(struct aws_allocator *al connectionConfig.SetConnectAmendment(connectionAmendment); TestLifecycleHandler lifecycleHandler; - ClientConnection connection(allocator); - auto future = connection.Connect(connectionConfig, &lifecycleHandler, *testContext.clientBootstrap); + ClientConnection connection(allocator, testContext.clientBootstrap->GetUnderlyingHandle()); + auto future = connection.Connect(connectionConfig, &lifecycleHandler); EventStreamRpcStatusCode clientStatus = future.get().baseStatus; ASSERT_TRUE( diff --git a/eventstream_rpc/tests/include/awstest/EchoTestRpcClient.h b/eventstream_rpc/tests/include/awstest/EchoTestRpcClient.h index 0afe066f1..0f1f8b50b 100644 --- a/eventstream_rpc/tests/include/awstest/EchoTestRpcClient.h +++ b/eventstream_rpc/tests/include/awstest/EchoTestRpcClient.h @@ -77,7 +77,6 @@ namespace Awstest private: EchoTestRpcServiceModel m_echoTestRpcServiceModel; ClientConnection m_connection; - Aws::Crt::Io::ClientBootstrap &m_clientBootstrap; Aws::Crt::Allocator *m_allocator; MessageAmendment m_connectAmendment; std::launch m_asyncLaunchMode; diff --git a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcClient.h b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcClient.h index 502031d4f..393da1747 100644 --- a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcClient.h +++ b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcClient.h @@ -236,7 +236,6 @@ namespace Aws private: GreengrassCoreIpcServiceModel m_greengrassCoreIpcServiceModel; ClientConnection m_connection; - Aws::Crt::Io::ClientBootstrap &m_clientBootstrap; Aws::Crt::Allocator *m_allocator; MessageAmendment m_connectAmendment; std::launch m_asyncLaunchMode; diff --git a/greengrass_ipc/source/GreengrassCoreIpcClient.cpp b/greengrass_ipc/source/GreengrassCoreIpcClient.cpp index a1db24d5a..9afa6b197 100644 --- a/greengrass_ipc/source/GreengrassCoreIpcClient.cpp +++ b/greengrass_ipc/source/GreengrassCoreIpcClient.cpp @@ -16,7 +16,7 @@ namespace Aws GreengrassCoreIpcClient::GreengrassCoreIpcClient( Aws::Crt::Io::ClientBootstrap &clientBootstrap, Aws::Crt::Allocator *allocator) noexcept - : m_connection(allocator), m_clientBootstrap(clientBootstrap), m_allocator(allocator), + : m_connection(allocator, clientBootstrap.GetUnderlyingHandle()), m_allocator(allocator), m_asyncLaunchMode(std::launch::deferred) { m_greengrassCoreIpcServiceModel.AssignModelNameToErrorResponse( @@ -55,7 +55,7 @@ namespace Aws ConnectionLifecycleHandler &lifecycleHandler, const ConnectionConfig &connectionConfig) noexcept { - return m_connection.Connect(connectionConfig, &lifecycleHandler, m_clientBootstrap); + return m_connection.Connect(connectionConfig, &lifecycleHandler); } void GreengrassCoreIpcClient::Close() noexcept From 180f1500e4b36fa34244ee1dfcb4782633a908fc Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 14 May 2025 20:14:24 -0700 Subject: [PATCH 33/56] Fixes --- eventstream_rpc/source/EventStreamClient.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 1ab76bf00..f533b1dfb 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -456,7 +456,13 @@ namespace Aws } void SetAction(ConnectionCallbackActionType action) { m_action = action; } - void SetError(RpcError error) { m_error = error; } + void SetError(RpcError error) + { + if (m_error.baseStatus == EVENT_STREAM_RPC_SUCCESS) + { + m_error = error; + } + } std::future GetConnectPromiseFuture() { return m_connectPromise.get_future(); } @@ -873,6 +879,9 @@ namespace Aws { std::lock_guard lock(impl->m_sharedStateLock); AWS_FATAL_ASSERT(impl->m_sharedState.m_currentState == ClientState::PendingConnect); + + // the channel owns the initial ref; we have to take our own + aws_event_stream_rpc_client_connection_acquire(connection); impl->m_sharedState.m_underlyingConnection = connection; if (impl->m_sharedState.m_desiredState != ClientState::Connected) { From 83b950e9090cfdc9a496b9d4b67c7968834bd2b6 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 20 May 2025 13:21:28 -0700 Subject: [PATCH 34/56] Checkpoint --- .../aws/eventstreamrpc/EventStreamClient.h | 30 +-- eventstream_rpc/source/EventStreamClient.cpp | 235 +++++++++++------- eventstream_rpc/tests/CMakeLists.txt | 7 +- .../tests/EventStreamClientTest.cpp | 202 ++++++++++++++- 4 files changed, 359 insertions(+), 115 deletions(-) diff --git a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h index 7f87df0f1..4577e1762 100644 --- a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h +++ b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h @@ -141,19 +141,19 @@ namespace Aws enum EventStreamRpcStatusCode { - EVENT_STREAM_RPC_SUCCESS = 0, - EVENT_STREAM_RPC_NULL_PARAMETER, - EVENT_STREAM_RPC_UNINITIALIZED, - EVENT_STREAM_RPC_ALLOCATION_ERROR, - EVENT_STREAM_RPC_CONNECTION_SETUP_FAILED, - EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, - EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED, - EVENT_STREAM_RPC_CONNECTION_CLOSED, - EVENT_STREAM_RPC_CONTINUATION_CLOSED, - EVENT_STREAM_RPC_UNKNOWN_PROTOCOL_MESSAGE, - EVENT_STREAM_RPC_UNMAPPED_DATA, - EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE, - EVENT_STREAM_RPC_CRT_ERROR + EVENT_STREAM_RPC_SUCCESS = 0, + EVENT_STREAM_RPC_NULL_PARAMETER, + EVENT_STREAM_RPC_UNINITIALIZED, + EVENT_STREAM_RPC_ALLOCATION_ERROR, + EVENT_STREAM_RPC_CONNECTION_SETUP_FAILED, + EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, + EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED, + EVENT_STREAM_RPC_CONNECTION_CLOSED, + EVENT_STREAM_RPC_CONTINUATION_CLOSED, + EVENT_STREAM_RPC_UNKNOWN_PROTOCOL_MESSAGE, + EVENT_STREAM_RPC_UNMAPPED_DATA, + EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE, + EVENT_STREAM_RPC_CRT_ERROR }; /** @@ -260,7 +260,6 @@ namespace Aws const Crt::Optional &payload); }; - class ClientConnectionImpl; /** @@ -269,7 +268,6 @@ namespace Aws class AWS_EVENTSTREAMRPC_API ClientConnection final { public: - explicit ClientConnection(Crt::Allocator *allocator, aws_client_bootstrap *bootstrap) noexcept; ~ClientConnection() noexcept; @@ -303,7 +301,6 @@ namespace Aws bool IsOpen() const noexcept; private: - std::shared_ptr m_impl; }; @@ -776,6 +773,5 @@ namespace Aws std::condition_variable m_closeReady; }; - } // namespace Eventstreamrpc } // namespace Aws diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index f533b1dfb..0de055d97 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -253,6 +253,21 @@ namespace Aws Crt::Allocator *allocator) : m_allocator(allocator), m_valueByteBuf({}), m_underlyingHandle(header) { + switch (header.header_value_type) + { + case AWS_EVENT_STREAM_HEADER_STRING: + case AWS_EVENT_STREAM_HEADER_BYTE_BUF: + // Unsafe to copy C struct by value. Copy the referenced buffer and fix up pointers. + m_valueByteBuf = + Crt::ByteBufNewCopy(allocator, header.header_value.variable_len_val, header.header_value_len); + m_underlyingHandle.header_value.variable_len_val = m_valueByteBuf.buffer; + m_underlyingHandle.header_value_len = m_valueByteBuf.len; + break; + + default: + // C struct can be copied by value safely + break; + } } EventStreamHeader::EventStreamHeader( @@ -296,6 +311,10 @@ namespace Aws EventStreamHeader &EventStreamHeader::operator=(const EventStreamHeader &lhs) noexcept { m_allocator = lhs.m_allocator; + if (aws_byte_buf_is_valid(&m_valueByteBuf)) + { + Crt::ByteBufDelete(m_valueByteBuf); + } m_valueByteBuf = Crt::ByteBufNewCopy(lhs.m_allocator, lhs.m_valueByteBuf.buffer, lhs.m_valueByteBuf.len); m_underlyingHandle = lhs.m_underlyingHandle; m_underlyingHandle.header_value.variable_len_val = m_valueByteBuf.buffer; @@ -335,23 +354,24 @@ namespace Aws return true; } -/* - * Eventstream Connection Refactor - * - * Part 1 of an effort to refactor the eventstream bindings to conform to the latest CRT binding guidelines. - * - * For connections, we now enforce the following invariants for correctness: - * - * 1. No callback is made while a lock is held. We perform callbacks by having a transactional callback context that - * is moved out of shared state (under the lock), but the callback context does not perform its work until the lock - * is released. - * 2. No destructor blocking or synchronization. In order to provide the best behavioral backwards compatibility, we - * "synthesize" the callbacks that would occur at destruction when we kick off the async cleanup process. When the - * asynchronous events occur that would normally trigger a callback occur, we ignore them via the has_shut_down flag. - * 3. A self-reference (via shared_ptr member) guarantees the binding impl stays alive longer than the C objects. The - * public binding object also keeps a shared_ptr to the impl, so final destruction only occurs once both the public - * binding object's destructor has run and no C connection object is still alive. - */ + /* + * Eventstream Connection Refactor + * + * Part 1 of an effort to refactor the eventstream bindings to conform to the latest CRT binding guidelines. + * + * For connections, we now enforce the following invariants for correctness: + * + * 1. No callback is made while a lock is held. We perform callbacks by having a transactional callback context + * that is moved out of shared state (under the lock), but the callback context does not perform its work until + * the lock is released. + * 2. No destructor blocking or synchronization. In order to provide the best behavioral backwards + * compatibility, we "synthesize" the callbacks that would occur at destruction when we kick off the async + * cleanup process. When the asynchronous events occur that would normally trigger a callback occur, we ignore + * them via the has_shut_down flag. + * 3. A self-reference (via shared_ptr member) guarantees the binding impl stays alive longer than the C + * objects. The public binding object also keeps a shared_ptr to the impl, so final destruction only occurs + * once both the public binding object's destructor has run and no C connection object is still alive. + */ /* What kind of callback should this context trigger? */ enum class ConnectionCallbackActionType @@ -374,24 +394,27 @@ namespace Aws class ConnectionCallbackContext { public: - ConnectionCallbackContext() : m_action(ConnectionCallbackActionType::None), m_error{EVENT_STREAM_RPC_SUCCESS, AWS_ERROR_SUCCESS} {} - - ConnectionCallbackContext(const std::function &disconnectionCallback, const std::function &errorCallback, const std::function &connectionSuccessCallback) : - m_action(ConnectionCallbackActionType::CompleteConnectPromise), - m_error{EVENT_STREAM_RPC_SUCCESS, AWS_ERROR_SUCCESS}, - m_connectPromise(), - m_disconnectionCallback(disconnectionCallback), - m_errorCallback(errorCallback), - m_connectionSuccessCallback(connectionSuccessCallback) - {} - - ConnectionCallbackContext(ConnectionCallbackContext &&rhs) noexcept : - m_action(rhs.m_action), - m_error(rhs.m_error), - m_connectPromise(std::move(rhs.m_connectPromise)), - m_disconnectionCallback(std::move(rhs.m_disconnectionCallback)), - m_errorCallback(std::move(rhs.m_errorCallback)), - m_connectionSuccessCallback(std::move(rhs.m_connectionSuccessCallback)) + ConnectionCallbackContext() + : m_action(ConnectionCallbackActionType::None), m_error{EVENT_STREAM_RPC_SUCCESS, AWS_ERROR_SUCCESS} + { + } + + ConnectionCallbackContext( + const std::function &disconnectionCallback, + const std::function &errorCallback, + const std::function &connectionSuccessCallback) + : m_action(ConnectionCallbackActionType::CompleteConnectPromise), + m_error{EVENT_STREAM_RPC_SUCCESS, AWS_ERROR_SUCCESS}, m_connectPromise(), + m_disconnectionCallback(disconnectionCallback), m_errorCallback(errorCallback), + m_connectionSuccessCallback(connectionSuccessCallback) + { + } + + ConnectionCallbackContext(ConnectionCallbackContext &&rhs) noexcept + : m_action(rhs.m_action), m_error(rhs.m_error), m_connectPromise(std::move(rhs.m_connectPromise)), + m_disconnectionCallback(std::move(rhs.m_disconnectionCallback)), + m_errorCallback(std::move(rhs.m_errorCallback)), + m_connectionSuccessCallback(std::move(rhs.m_connectionSuccessCallback)) { rhs.ClearContext(); } @@ -466,8 +489,7 @@ namespace Aws std::future GetConnectPromiseFuture() { return m_connectPromise.get_future(); } - private: - + private: /* Wipes out state in a context to guarantee it does nothing if someone tries to InvokeCallbacks on it */ void ClearContext() { @@ -490,7 +512,6 @@ namespace Aws class ClientConnectionImpl final : public std::enable_shared_from_this { public: - explicit ClientConnectionImpl(Crt::Allocator *allocator, aws_client_bootstrap *bootstrap) noexcept; ~ClientConnectionImpl() noexcept; @@ -514,7 +535,6 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept; private: - void CloseInternal(bool isShutdown) noexcept; void MoveToDisconnected(RpcError error) noexcept; @@ -569,13 +589,12 @@ namespace Aws struct aws_event_stream_rpc_client_connection *connection, const struct aws_event_stream_rpc_message_args *messageArgs, void *userData) noexcept; - }; ClientConnectionImpl::ClientConnectionImpl(Crt::Allocator *allocator, aws_client_bootstrap *bootstrap) noexcept - : m_allocator(allocator), m_lifecycleHandler(nullptr), m_connectMessageAmender(nullptr), - m_bootstrap(aws_client_bootstrap_acquire(bootstrap)), m_eventLoop(nullptr), - m_sharedState { nullptr, ClientState::Disconnected, ClientState::Disconnected, {}, false} + : m_allocator(allocator), m_lifecycleHandler(nullptr), m_connectMessageAmender(nullptr), + m_bootstrap(aws_client_bootstrap_acquire(bootstrap)), m_eventLoop(nullptr), + m_sharedState{nullptr, ClientState::Disconnected, ClientState::Disconnected, {}, false} { m_eventLoop = aws_event_loop_group_get_next_loop(bootstrap->event_loop_group); } @@ -587,8 +606,11 @@ namespace Aws // We use a task to zero out the self reference to make sure we are not in a call stack that includes // a member function of the connection impl itself when potentially releasing the final reference. - struct AwsEventstreamConnectionImplClearSharedTask { - AwsEventstreamConnectionImplClearSharedTask(Aws::Crt::Allocator *allocator, ClientConnectionImpl *clientConnectionImpl) noexcept; + struct AwsEventstreamConnectionImplClearSharedTask + { + AwsEventstreamConnectionImplClearSharedTask( + Aws::Crt::Allocator *allocator, + ClientConnectionImpl *clientConnectionImpl) noexcept; struct aws_task m_task; struct aws_allocator *m_allocator; @@ -603,17 +625,18 @@ namespace Aws Aws::Crt::Delete(clearSharedTask, clearSharedTask->m_allocator); } - AwsEventstreamConnectionImplClearSharedTask::AwsEventstreamConnectionImplClearSharedTask(Aws::Crt::Allocator *allocator, ClientConnectionImpl *clientConnectionImpl) noexcept : - m_task{}, - m_allocator(allocator), - m_impl(clientConnectionImpl->shared_from_this()) + AwsEventstreamConnectionImplClearSharedTask::AwsEventstreamConnectionImplClearSharedTask( + Aws::Crt::Allocator *allocator, + ClientConnectionImpl *clientConnectionImpl) noexcept + : m_task{}, m_allocator(allocator), m_impl(clientConnectionImpl->shared_from_this()) { aws_task_init(&m_task, s_zeroSharedReference, this, "AwsEventstreamConnectionImplClearSharedTask"); } void ClientConnectionImpl::MoveToDisconnected(RpcError error) noexcept { - auto *clearSharedTask = Aws::Crt::New(m_allocator, m_allocator, this); + auto *clearSharedTask = + Aws::Crt::New(m_allocator, m_allocator, this); ConnectionCallbackContext localContext = {}; { std::lock_guard lock(m_sharedStateLock); @@ -641,16 +664,19 @@ namespace Aws { std::lock_guard lock(m_sharedStateLock); m_sharedState.m_desiredState = ClientState::Disconnected; - m_sharedState.m_callbackContext.SetError({EVENT_STREAM_RPC_CONNECTION_CLOSED, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED}); + m_sharedState.m_callbackContext.SetError( + {EVENT_STREAM_RPC_CONNECTION_CLOSED, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED}); if (isShutdown) { m_sharedState.m_hasShutDown = true; } - if (m_sharedState.m_currentState == ClientState::Connected || m_sharedState.m_currentState == ClientState::PendingConnack) + if (m_sharedState.m_currentState == ClientState::Connected || + m_sharedState.m_currentState == ClientState::PendingConnack) { m_sharedState.m_currentState = ClientState::Disconnecting; - aws_event_stream_rpc_client_connection_close(m_sharedState.m_underlyingConnection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); + aws_event_stream_rpc_client_connection_close( + m_sharedState.m_underlyingConnection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); } if (isShutdown) @@ -696,16 +722,20 @@ namespace Aws } m_lifecycleHandler = connectionLifecycleHandler; - std::function disconnectCallback = [this](RpcError error) { this->m_lifecycleHandler->OnDisconnectCallback(error); }; - std::function errorCallback = [this](RpcError error){ return this->m_lifecycleHandler->OnErrorCallback(error); }; - std::function connectionSuccessCallback = [this](){ this->m_lifecycleHandler->OnConnectCallback(); }; + std::function disconnectCallback = [this](RpcError error) + { this->m_lifecycleHandler->OnDisconnectCallback(error); }; + std::function errorCallback = [this](RpcError error) + { return this->m_lifecycleHandler->OnErrorCallback(error); }; + std::function connectionSuccessCallback = [this]() + { this->m_lifecycleHandler->OnConnectCallback(); }; m_connectionConfig = connectionConfig; m_selfReference = shared_from_this(); m_sharedState.m_desiredState = ClientState::Connected; m_sharedState.m_currentState = ClientState::PendingConnect; - m_sharedState.m_callbackContext = {std::move(disconnectCallback), std::move(errorCallback), std::move(connectionSuccessCallback)}; - localFuture = m_sharedState.m_callbackContext.GetConnectPromiseFuture(); + m_sharedState.m_callbackContext = { + std::move(disconnectCallback), std::move(errorCallback), std::move(connectionSuccessCallback)}; + localFuture = m_sharedState.m_callbackContext.GetConnectPromiseFuture(); } Crt::Io::SocketOptions socketOptions; @@ -770,7 +800,8 @@ namespace Aws Crt::Delete(callbackData, callbackData->allocator); } - ClientContinuation ClientConnectionImpl::NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept + ClientContinuation ClientConnectionImpl::NewStream( + ClientContinuationHandler &clientContinuationHandler) noexcept { std::lock_guard lock(m_sharedStateLock); return {m_sharedState.m_underlyingConnection, clientContinuationHandler, m_allocator}; @@ -811,10 +842,10 @@ namespace Aws } if (aws_event_stream_rpc_client_connection_send_protocol_message( - m_sharedState.m_underlyingConnection, - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(callbackContainer))) + m_sharedState.m_underlyingConnection, + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(callbackContainer))) { errorCode = aws_last_error(); } @@ -857,7 +888,14 @@ namespace Aws { std::promise sendOutcomePromise; auto sendOutcomeFuture = sendOutcomePromise.get_future(); - SendProtocolMessageAux(headers, payload, messageType, messageFlags, std::move(onMessageFlushCallback), &sendOutcomePromise, true); + SendProtocolMessageAux( + headers, + payload, + messageType, + messageFlags, + std::move(onMessageFlushCallback), + &sendOutcomePromise, + true); return sendOutcomeFuture; } @@ -887,7 +925,8 @@ namespace Aws { AWS_FATAL_ASSERT(impl->m_sharedState.m_desiredState == ClientState::Disconnected); impl->m_sharedState.m_currentState = ClientState::Disconnecting; - aws_event_stream_rpc_client_connection_close(connection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); + aws_event_stream_rpc_client_connection_close( + connection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); return; } @@ -906,15 +945,19 @@ namespace Aws messageAmendment.SetPayload(std::move(connectAmendment).GetPayload()); } - if (impl->SendProtocolMessageAux( messageAmendment.GetHeaders(), - messageAmendment.GetPayload(), - AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_CONNECT, - 0U, - impl->m_connectionConfig.GetConnectRequestCallback(), nullptr, false)) + if (impl->SendProtocolMessageAux( + messageAmendment.GetHeaders(), + messageAmendment.GetPayload(), + AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_CONNECT, + 0U, + impl->m_connectionConfig.GetConnectRequestCallback(), + nullptr, + false)) { impl->m_sharedState.m_callbackContext.SetError({EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}); impl->m_sharedState.m_currentState = ClientState::Disconnecting; - aws_event_stream_rpc_client_connection_close(connection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); + aws_event_stream_rpc_client_connection_close( + connection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); } } } @@ -944,7 +987,8 @@ namespace Aws case AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_CONNECT_ACK: { ConnectionCallbackContext localCallbackContext = {}; - bool successfulAck = (messageArgs->message_flags & AWS_EVENT_STREAM_RPC_MESSAGE_FLAG_CONNECTION_ACCEPTED) != 0; + bool successfulAck = + (messageArgs->message_flags & AWS_EVENT_STREAM_RPC_MESSAGE_FLAG_CONNECTION_ACCEPTED) != 0; { std::lock_guard lock(impl->m_sharedStateLock); if (impl->m_sharedState.m_currentState != ClientState::PendingConnack || !successfulAck) @@ -952,14 +996,16 @@ namespace Aws if (!impl->m_sharedState.m_hasShutDown) { impl->m_sharedState.m_callbackContext.SetError( - (successfulAck) ? RpcError{EVENT_STREAM_RPC_CONNECTION_CLOSED, 0} : RpcError{EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, 0} - ); + (successfulAck) ? RpcError{EVENT_STREAM_RPC_CONNECTION_CLOSED, 0} + : RpcError{EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, 0}); } impl->m_sharedState.m_desiredState = ClientState::Disconnected; if (impl->m_sharedState.m_currentState != ClientState::Disconnecting) { impl->m_sharedState.m_currentState = ClientState::Disconnecting; - aws_event_stream_rpc_client_connection_close(impl->m_sharedState.m_underlyingConnection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); + aws_event_stream_rpc_client_connection_close( + impl->m_sharedState.m_underlyingConnection, + AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); } return; } @@ -976,8 +1022,7 @@ namespace Aws Crt::List pingHeaders; for (size_t i = 0; i < messageArgs->headers_count; ++i) { - pingHeaders.emplace_back( - EventStreamHeader(messageArgs->headers[i], impl->m_allocator)); + pingHeaders.emplace_back(EventStreamHeader(messageArgs->headers[i], impl->m_allocator)); } if (messageArgs->payload) @@ -997,14 +1042,14 @@ namespace Aws default: impl->m_lifecycleHandler->OnErrorCallback( - {EVENT_STREAM_RPC_CRT_ERROR, AWS_ERROR_EVENT_STREAM_RPC_PROTOCOL_ERROR}); + {EVENT_STREAM_RPC_CRT_ERROR, AWS_ERROR_EVENT_STREAM_RPC_PROTOCOL_ERROR}); impl->Close(); break; } } ClientConnection::ClientConnection(Crt::Allocator *allocator, aws_client_bootstrap *bootstrap) noexcept - :m_impl(Aws::Crt::MakeShared(allocator, allocator, bootstrap)) + : m_impl(Aws::Crt::MakeShared(allocator, allocator, bootstrap)) { } @@ -1044,10 +1089,12 @@ namespace Aws struct RawContinuationCallbackDataWrapper { - RawContinuationCallbackDataWrapper(Aws::Crt::Allocator *allocator, const std::shared_ptr &callbackData) : - m_allocator(allocator), - m_callbackData(callbackData) - {} + RawContinuationCallbackDataWrapper( + Aws::Crt::Allocator *allocator, + const std::shared_ptr &callbackData) + : m_allocator(allocator), m_callbackData(callbackData) + { + } Aws::Crt::Allocator *m_allocator; std::shared_ptr m_callbackData; @@ -1060,7 +1107,8 @@ namespace Aws return; } - struct RawContinuationCallbackDataWrapper *wrapper = static_cast(user_data); + struct RawContinuationCallbackDataWrapper *wrapper = + static_cast(user_data); Aws::Crt::Delete(wrapper, wrapper->m_allocator); } @@ -1078,12 +1126,12 @@ namespace Aws m_callbackData = Crt::MakeShared(m_allocator, this, m_allocator); m_continuationHandler.m_callbackData = m_callbackData; - options.user_data = reinterpret_cast(Aws::Crt::New(allocator, allocator, m_callbackData)); + options.user_data = reinterpret_cast( + Aws::Crt::New(allocator, allocator, m_callbackData)); if (connection) { - m_continuationToken = - aws_event_stream_rpc_client_connection_new_stream(connection, &options); + m_continuationToken = aws_event_stream_rpc_client_connection_new_stream(connection, &options); if (m_continuationToken == nullptr) { m_continuationHandler.m_callbackData = nullptr; @@ -1273,10 +1321,10 @@ namespace Aws if (m_continuationToken) { if (aws_event_stream_rpc_client_continuation_send_message( - m_continuationToken, - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(callbackContainer))) + m_continuationToken, + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(callbackContainer))) { errorCode = aws_last_error(); } @@ -1345,9 +1393,8 @@ namespace Aws { Close().wait(); m_clientContinuation.Release(); - //std::unique_lock lock(m_continuationMutex); - //m_closeReady.wait(lock, [this] { return m_expectingClose == false; }); - + // std::unique_lock lock(m_continuationMutex); + // m_closeReady.wait(lock, [this] { return m_expectingClose == false; }); } TaggedResult::TaggedResult(Crt::ScopedResource operationResponse) noexcept diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index abf50b5a4..84a993f0a 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -30,13 +30,18 @@ file(GLOB TESTS ${TEST_HDRS} ${TEST_SRC}) set(TEST_BINARY_NAME ${PROJECT_NAME}-tests) +add_test_case(EventStreamClientCreateFailureInvalidHost) +add_test_case(EventStreamClientCreateFailureInvalidPort) add_test_case(EventStreamConnectSuccess) add_test_case(EventStreamConnectFailureNoAuthHeader) add_test_case(EventStreamConnectFailureBadAuthHeader) - add_test_case(EchoClientConnectSuccess) add_test_case(EchoClientDoubleClose) add_test_case(EchoClientMultiConnectSuccessFail) +add_test_case(EchoClientReconnect) +add_test_case(EchoClientCloseWhileConnecting) +add_test_case(EchoClientConnectWhileClosing) +add_test_case(EchoClientOpenCloseStress) #add_test_case(EchoClientOperationEchoSuccessString) #add_test_case(EchoClientOperationEchoSuccessBoolean) diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 9082678f2..ff057a56b 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -91,6 +91,7 @@ class TestLifecycleHandler : public ConnectionLifecycleHandler disconnectCrtErrorCode = error.crtError; disconnectRpcStatusCode = error.baseStatus; + isConnected = false; semaphore.notify_one(); } @@ -101,6 +102,11 @@ class TestLifecycleHandler : public ConnectionLifecycleHandler semaphore.wait(semaphoreULock, condition); } + void WaitOnDisconnected() + { + WaitOnCondition([this]() { return !isConnected; }); + } + private: std::condition_variable semaphore; std::mutex semaphoreLock; @@ -285,13 +291,205 @@ static int s_TestEchoClientMultiConnectSuccessFail(struct aws_allocator *allocat AWS_TEST_CASE(EchoClientMultiConnectSuccessFail, s_TestEchoClientMultiConnectSuccessFail); +static int s_TestEventStreamClientCreateFailureInvalidHost(struct aws_allocator *allocator, void *ctx) +{ + ApiHandle apiHandle(allocator); + + { + auto elGroup = Aws::Crt::MakeShared(allocator, 0, allocator); + auto resolver = Aws::Crt::MakeShared(allocator, *elGroup, 8, 30, allocator); + auto clientBootstrap = Aws::Crt::MakeShared(allocator, *elGroup, *resolver, allocator); + + ConnectionLifecycleHandler lifecycleHandler; + ClientConnection client(allocator, clientBootstrap->GetUnderlyingHandle()); + + ConnectionConfig config; + config.SetPort(8033); + + auto connectFuture = client.Connect(config, &lifecycleHandler); + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_NULL_PARAMETER, connectFuture.get().baseStatus); + } + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(EventStreamClientCreateFailureInvalidHost, s_TestEventStreamClientCreateFailureInvalidHost); + +static int s_TestEventStreamClientCreateFailureInvalidPort(struct aws_allocator *allocator, void *ctx) +{ + ApiHandle apiHandle(allocator); + + { + auto elGroup = Aws::Crt::MakeShared(allocator, 0, allocator); + auto resolver = Aws::Crt::MakeShared(allocator, *elGroup, 8, 30, allocator); + auto clientBootstrap = Aws::Crt::MakeShared(allocator, *elGroup, *resolver, allocator); + + ConnectionLifecycleHandler lifecycleHandler; + ClientConnection client(allocator, clientBootstrap->GetUnderlyingHandle()); + + ConnectionConfig config; + config.SetHostName("localhost"); + + auto connectFuture = client.Connect(config, &lifecycleHandler); + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_NULL_PARAMETER, connectFuture.get().baseStatus); + } + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(EventStreamClientCreateFailureInvalidPort, s_TestEventStreamClientCreateFailureInvalidPort); + +static int s_TestEchoClientReconnect(struct aws_allocator *allocator, void *ctx) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { + TestLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedStatus1 = client.Connect(lifecycleHandler).get().baseStatus; + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_SUCCESS, connectedStatus1); + + client.Close(); + lifecycleHandler.WaitOnDisconnected(); + + auto connectedStatus2 = client.Connect(lifecycleHandler).get().baseStatus; + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_SUCCESS, connectedStatus2); + + client.Close(); + } + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(EchoClientReconnect, s_TestEchoClientReconnect); + +static int s_TestEchoClientCloseWhileConnecting(struct aws_allocator *allocator, void *ctx) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { + TestLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedFuture = client.Connect(lifecycleHandler); + client.Close(); + + // Our primary concern is that + // we end up in a closed state, the connect future resolves, and nothing explodes in-between. + auto status = connectedFuture.get().baseStatus; + + // depending on race conditions, we may end up with a connection success (before the close gets triggered) + // or a connection closed + ASSERT_TRUE(status == EVENT_STREAM_RPC_CONNECTION_CLOSED || status == EVENT_STREAM_RPC_SUCCESS); + lifecycleHandler.WaitOnDisconnected(); + } + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(EchoClientCloseWhileConnecting, s_TestEchoClientCloseWhileConnecting); + +static int s_TestEchoClientConnectWhileClosing(struct aws_allocator *allocator, void *ctx) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { + TestLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedFuture = client.Connect(lifecycleHandler); + auto status = connectedFuture.get().baseStatus; + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_SUCCESS, status); + + client.Close(); + + auto reconnectFuture = client.Connect(lifecycleHandler); + auto reconnectStatus = reconnectFuture.get().baseStatus; + + // depending on race conditions, we may end up with a success (the close completed quickly) + // or an already established code (the connect arrived in the middle of close) + ASSERT_TRUE( + reconnectStatus == EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED || + reconnectStatus == EVENT_STREAM_RPC_SUCCESS); + client.Close(); + + lifecycleHandler.WaitOnDisconnected(); + } + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(EchoClientConnectWhileClosing, s_TestEchoClientConnectWhileClosing); + +static int s_TestEchoClientOpenCloseStress(struct aws_allocator *allocator, void *ctx) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { + TestLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + + for (size_t i = 0; i < 1000; ++i) + { + auto connectedFuture = client.Connect(lifecycleHandler); + + if (rand() % 2 == 0) + { + std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 10)); + } + + client.Close(); + + auto connectedStatus = connectedFuture.get().baseStatus; + ASSERT_TRUE( + connectedStatus == EVENT_STREAM_RPC_CONNECTION_CLOSED || connectedStatus == EVENT_STREAM_RPC_SUCCESS || + connectedStatus == EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED); + + if (rand() % 2 == 0) + { + std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 10)); + } + } + } + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(EchoClientOpenCloseStress, s_TestEchoClientOpenCloseStress); + +#ifdef NEVER + static void s_onMessageFlush(int errorCode) { (void)errorCode; } template -static bool s_messageDataMembersAreEqual(const Aws::Crt::Optional &expectedValue, const Aws::Crt::Optional &actualValue) +static bool s_messageDataMembersAreEqual( + const Aws::Crt::Optional &expectedValue, + const Aws::Crt::Optional &actualValue) { if (expectedValue.has_value() != actualValue.has_value()) { @@ -698,8 +896,6 @@ static int s_TestEchoClientOperationEchoFailureDisconnected(struct aws_allocator AWS_TEST_CASE(EchoClientOperationEchoFailureDisconnected, s_TestEchoClientOperationEchoFailureDisconnected); -#ifdef NEVER - AWS_TEST_CASE_FIXTURE(EchoOperation, s_testSetup, s_TestEchoOperation, s_testTeardown, &s_testContext); static int s_TestEchoOperation(struct aws_allocator *allocator, void *ctx) { From 6f6b0e1ef711d125d2e0cd9cfb1d2321a109ef6f Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 20 May 2025 13:41:11 -0700 Subject: [PATCH 35/56] Misc rewrite --- eventstream_rpc/source/EventStreamClient.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 0de055d97..2326133fe 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -744,16 +744,15 @@ namespace Aws socketOptions = m_connectionConfig.GetSocketOptions().value(); } - struct aws_event_stream_rpc_client_connection_options connectOptions = { - .host_name = connectionConfig.GetHostName().value().c_str(), - .port = connectionConfig.GetPort().value(), - .bootstrap = m_bootstrap, - .socket_options = &socketOptions.GetImpl(), - .on_connection_setup = ClientConnectionImpl::s_onConnectionSetup, - .on_connection_protocol_message = ClientConnectionImpl::s_onProtocolMessage, - .on_connection_shutdown = ClientConnectionImpl::s_onConnectionShutdown, - .user_data = reinterpret_cast(this), - }; + struct aws_event_stream_rpc_client_connection_options connectOptions = {}; + connectOptions.host_name = connectionConfig.GetHostName().value().c_str(); + connectOptions.port = connectionConfig.GetPort().value(); + connectOptions.bootstrap = m_bootstrap; + connectOptions.socket_options = &socketOptions.GetImpl(); + connectOptions.on_connection_setup = ClientConnectionImpl::s_onConnectionSetup; + connectOptions.on_connection_protocol_message = ClientConnectionImpl::s_onProtocolMessage; + connectOptions.on_connection_shutdown = ClientConnectionImpl::s_onConnectionShutdown; + connectOptions.user_data = reinterpret_cast(this); if (m_connectionConfig.GetTlsConnectionOptions().has_value()) { From 64032b58b6e54e2e20d46cbe29f239d452490d03 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 21 May 2025 10:10:00 -0700 Subject: [PATCH 36/56] Clients now track connection by shared pointer --- .../aws/eventstreamrpc/EventStreamClient.h | 2 +- eventstream_rpc/tests/EchoTestRpcClient.cpp | 21 ++--- .../tests/include/awstest/EchoTestRpcClient.h | 4 +- .../aws/greengrass/GreengrassCoreIpcClient.h | 4 +- .../source/GreengrassCoreIpcClient.cpp | 77 ++++++++++--------- 5 files changed, 55 insertions(+), 53 deletions(-) diff --git a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h index 4577e1762..f22136113 100644 --- a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h +++ b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h @@ -268,7 +268,7 @@ namespace Aws class AWS_EVENTSTREAMRPC_API ClientConnection final { public: - explicit ClientConnection(Crt::Allocator *allocator, aws_client_bootstrap *bootstrap) noexcept; + ClientConnection(Crt::Allocator *allocator, aws_client_bootstrap *bootstrap) noexcept; ~ClientConnection() noexcept; /** diff --git a/eventstream_rpc/tests/EchoTestRpcClient.cpp b/eventstream_rpc/tests/EchoTestRpcClient.cpp index ee911b0c8..871869f68 100644 --- a/eventstream_rpc/tests/EchoTestRpcClient.cpp +++ b/eventstream_rpc/tests/EchoTestRpcClient.cpp @@ -14,8 +14,9 @@ namespace Awstest EchoTestRpcClient::EchoTestRpcClient( Aws::Crt::Io::ClientBootstrap &clientBootstrap, Aws::Crt::Allocator *allocator) noexcept - : m_connection(allocator, clientBootstrap.GetUnderlyingHandle()), m_allocator(allocator), - m_asyncLaunchMode(std::launch::deferred) + : m_connection( + Aws::Crt::MakeShared(allocator, allocator, clientBootstrap.GetUnderlyingHandle())), + m_allocator(allocator), m_asyncLaunchMode(std::launch::deferred) { m_echoTestRpcServiceModel.AssignModelNameToErrorResponse( Aws::Crt::String("awstest#ServiceError"), ServiceError::s_allocateFromPayload); @@ -25,12 +26,12 @@ namespace Awstest ConnectionLifecycleHandler &lifecycleHandler, const ConnectionConfig &connectionConfig) noexcept { - return m_connection.Connect(connectionConfig, &lifecycleHandler); + return m_connection->Connect(connectionConfig, &lifecycleHandler); } void EchoTestRpcClient::Close() noexcept { - m_connection.Close(); + m_connection->Close(); } void EchoTestRpcClient::WithLaunchMode(std::launch mode) noexcept @@ -46,7 +47,7 @@ namespace Awstest std::shared_ptr EchoTestRpcClient::NewGetAllProducts() noexcept { auto operation = Aws::Crt::MakeShared( - m_allocator, m_connection, m_echoTestRpcServiceModel.m_getAllProductsOperationContext, m_allocator); + m_allocator, *m_connection, m_echoTestRpcServiceModel.m_getAllProductsOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); return operation; } @@ -54,7 +55,7 @@ namespace Awstest std::shared_ptr EchoTestRpcClient::NewCauseServiceError() noexcept { auto operation = Aws::Crt::MakeShared( - m_allocator, m_connection, m_echoTestRpcServiceModel.m_causeServiceErrorOperationContext, m_allocator); + m_allocator, *m_connection, m_echoTestRpcServiceModel.m_causeServiceErrorOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); return operation; } @@ -64,7 +65,7 @@ namespace Awstest { return Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, std::move(streamHandler), m_echoTestRpcServiceModel.m_causeStreamServiceToErrorOperationContext, m_allocator); @@ -75,7 +76,7 @@ namespace Awstest { return Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, std::move(streamHandler), m_echoTestRpcServiceModel.m_echoStreamMessagesOperationContext, m_allocator); @@ -84,7 +85,7 @@ namespace Awstest std::shared_ptr EchoTestRpcClient::NewEchoMessage() noexcept { auto operation = Aws::Crt::MakeShared( - m_allocator, m_connection, m_echoTestRpcServiceModel.m_echoMessageOperationContext, m_allocator); + m_allocator, *m_connection, m_echoTestRpcServiceModel.m_echoMessageOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); return operation; } @@ -92,7 +93,7 @@ namespace Awstest std::shared_ptr EchoTestRpcClient::NewGetAllCustomers() noexcept { auto operation = Aws::Crt::MakeShared( - m_allocator, m_connection, m_echoTestRpcServiceModel.m_getAllCustomersOperationContext, m_allocator); + m_allocator, *m_connection, m_echoTestRpcServiceModel.m_getAllCustomersOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); return operation; } diff --git a/eventstream_rpc/tests/include/awstest/EchoTestRpcClient.h b/eventstream_rpc/tests/include/awstest/EchoTestRpcClient.h index 0f1f8b50b..231ff78e7 100644 --- a/eventstream_rpc/tests/include/awstest/EchoTestRpcClient.h +++ b/eventstream_rpc/tests/include/awstest/EchoTestRpcClient.h @@ -36,7 +36,7 @@ namespace Awstest std::future Connect( ConnectionLifecycleHandler &lifecycleHandler, const ConnectionConfig &connectionConfig = DefaultConnectionConfig()) noexcept; - bool IsConnected() const noexcept { return m_connection.IsOpen(); } + bool IsConnected() const noexcept { return m_connection->IsOpen(); } void Close() noexcept; void WithLaunchMode(std::launch mode) noexcept; @@ -76,7 +76,7 @@ namespace Awstest private: EchoTestRpcServiceModel m_echoTestRpcServiceModel; - ClientConnection m_connection; + std::shared_ptr m_connection; Aws::Crt::Allocator *m_allocator; MessageAmendment m_connectAmendment; std::launch m_asyncLaunchMode; diff --git a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcClient.h b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcClient.h index 393da1747..4724e1bdc 100644 --- a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcClient.h +++ b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcClient.h @@ -38,7 +38,7 @@ namespace Aws std::future Connect( ConnectionLifecycleHandler &lifecycleHandler, const ConnectionConfig &connectionConfig = DefaultConnectionConfig()) noexcept; - bool IsConnected() const noexcept { return m_connection.IsOpen(); } + bool IsConnected() const noexcept { return m_connection->IsOpen(); } void Close() noexcept; void WithLaunchMode(std::launch mode) noexcept; @@ -235,7 +235,7 @@ namespace Aws private: GreengrassCoreIpcServiceModel m_greengrassCoreIpcServiceModel; - ClientConnection m_connection; + std::shared_ptr m_connection; Aws::Crt::Allocator *m_allocator; MessageAmendment m_connectAmendment; std::launch m_asyncLaunchMode; diff --git a/greengrass_ipc/source/GreengrassCoreIpcClient.cpp b/greengrass_ipc/source/GreengrassCoreIpcClient.cpp index 9afa6b197..1a00a3416 100644 --- a/greengrass_ipc/source/GreengrassCoreIpcClient.cpp +++ b/greengrass_ipc/source/GreengrassCoreIpcClient.cpp @@ -16,8 +16,9 @@ namespace Aws GreengrassCoreIpcClient::GreengrassCoreIpcClient( Aws::Crt::Io::ClientBootstrap &clientBootstrap, Aws::Crt::Allocator *allocator) noexcept - : m_connection(allocator, clientBootstrap.GetUnderlyingHandle()), m_allocator(allocator), - m_asyncLaunchMode(std::launch::deferred) + : m_connection( + Aws::Crt::MakeShared(allocator, allocator, clientBootstrap.GetUnderlyingHandle())), + m_allocator(allocator), m_asyncLaunchMode(std::launch::deferred) { m_greengrassCoreIpcServiceModel.AssignModelNameToErrorResponse( Aws::Crt::String("aws.greengrass#InvalidArgumentsError"), InvalidArgumentsError::s_allocateFromPayload); @@ -55,12 +56,12 @@ namespace Aws ConnectionLifecycleHandler &lifecycleHandler, const ConnectionConfig &connectionConfig) noexcept { - return m_connection.Connect(connectionConfig, &lifecycleHandler); + return m_connection->Connect(connectionConfig, &lifecycleHandler); } void GreengrassCoreIpcClient::Close() noexcept { - m_connection.Close(); + m_connection->Close(); } void GreengrassCoreIpcClient::WithLaunchMode(std::launch mode) noexcept @@ -78,7 +79,7 @@ namespace Aws { return Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, std::move(streamHandler), m_greengrassCoreIpcServiceModel.m_subscribeToIoTCoreOperationContext, m_allocator); @@ -88,7 +89,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_resumeComponentOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -99,7 +100,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_publishToIoTCoreOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -112,7 +113,7 @@ namespace Aws { return Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, std::move(streamHandler), m_greengrassCoreIpcServiceModel.m_subscribeToConfigurationUpdateOperationContext, m_allocator); @@ -122,7 +123,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_deleteThingShadowOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -133,7 +134,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_putComponentMetricOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -144,7 +145,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_deferComponentUpdateOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -157,7 +158,7 @@ namespace Aws { return Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, std::move(streamHandler), m_greengrassCoreIpcServiceModel.m_subscribeToValidateConfigurationUpdatesOperationContext, m_allocator); @@ -167,7 +168,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_getConfigurationOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -179,7 +180,7 @@ namespace Aws { return Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, std::move(streamHandler), m_greengrassCoreIpcServiceModel.m_subscribeToTopicOperationContext, m_allocator); @@ -189,7 +190,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_getComponentDetailsOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -201,7 +202,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_getClientDeviceAuthTokenOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -212,7 +213,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_publishToTopicOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -225,7 +226,7 @@ namespace Aws { return Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, std::move(streamHandler), m_greengrassCoreIpcServiceModel.m_subscribeToCertificateUpdatesOperationContext, m_allocator); @@ -236,7 +237,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_verifyClientDeviceIdentityOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -248,7 +249,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_authorizeClientDeviceActionOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -259,7 +260,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_listComponentsOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -270,7 +271,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_createDebugPasswordOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -281,7 +282,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_getThingShadowOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -293,7 +294,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_sendConfigurationValidityReportOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -304,7 +305,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_updateThingShadowOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -315,7 +316,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_updateConfigurationOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -327,7 +328,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_validateAuthorizationTokenOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -338,7 +339,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_restartComponentOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -350,7 +351,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_getLocalDeploymentStatusOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -361,7 +362,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_getSecretValueOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -371,7 +372,7 @@ namespace Aws std::shared_ptr GreengrassCoreIpcClient::NewUpdateState() noexcept { auto operation = Aws::Crt::MakeShared( - m_allocator, m_connection, m_greengrassCoreIpcServiceModel.m_updateStateOperationContext, m_allocator); + m_allocator, *m_connection, m_greengrassCoreIpcServiceModel.m_updateStateOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); return operation; } @@ -380,7 +381,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_cancelLocalDeploymentOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -392,7 +393,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_listNamedShadowsForThingOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -404,7 +405,7 @@ namespace Aws { return Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, std::move(streamHandler), m_greengrassCoreIpcServiceModel.m_subscribeToComponentUpdatesOperationContext, m_allocator); @@ -414,7 +415,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_listLocalDeploymentsOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -425,7 +426,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_stopComponentOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -436,7 +437,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_pauseComponentOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); @@ -447,7 +448,7 @@ namespace Aws { auto operation = Aws::Crt::MakeShared( m_allocator, - m_connection, + *m_connection, m_greengrassCoreIpcServiceModel.m_createLocalDeploymentOperationContext, m_allocator); operation->WithLaunchMode(m_asyncLaunchMode); From 37291b98bf4041355fda6dd2de61efdcfc0e8b81 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Fri, 30 May 2025 14:46:12 -0700 Subject: [PATCH 37/56] Checkpoint --- .../aws/eventstreamrpc/EventStreamClient.h | 94 +- eventstream_rpc/source/EventStreamClient.cpp | 1668 +++++++++++++---- eventstream_rpc/tests/CMakeLists.txt | 18 +- eventstream_rpc/tests/EchoTestRpcModel.cpp | 145 +- .../tests/EventStreamClientTest.cpp | 4 +- .../tests/include/awstest/EchoTestRpcModel.h | 97 +- .../aws/greengrass/GreengrassCoreIpcModel.h | 555 +++++- .../source/GreengrassCoreIpcModel.cpp | 848 ++++++--- 8 files changed, 2513 insertions(+), 916 deletions(-) diff --git a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h index f22136113..1cb58c76f 100644 --- a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h +++ b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h @@ -153,7 +153,9 @@ namespace Aws EVENT_STREAM_RPC_UNKNOWN_PROTOCOL_MESSAGE, EVENT_STREAM_RPC_UNMAPPED_DATA, EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE, - EVENT_STREAM_RPC_CRT_ERROR + EVENT_STREAM_RPC_CRT_ERROR, + EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED, + EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS, }; /** @@ -261,6 +263,7 @@ namespace Aws }; class ClientConnectionImpl; + class ClientContinuationImpl; /** * Class representing a connection to an RPC server. @@ -282,12 +285,10 @@ namespace Aws ConnectionLifecycleHandler *connectionLifecycleHandler) noexcept; /** - * Create a new stream. - * @note Activate() must be called on the stream for it to actually initiate the new stream. - * @param clientContinuationHandler Handler to process continuation events. + * Create a new stream (continuation). * @return A newly created continuation. */ - ClientContinuation NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept; + std::shared_ptr NewStream() noexcept; /** * Close the connection. @@ -304,6 +305,7 @@ namespace Aws std::shared_ptr m_impl; }; +#ifdef NEVER /** * User data passed to callbacks for a new stream. */ @@ -323,13 +325,16 @@ namespace Aws ClientContinuation *clientContinuation; Crt::Allocator *allocator; }; +#endif /** - * Handler interface for continuation events. + * Vestigial, do-nothing class that remains for backwards compatibility with the + * original, publicly-visible class hierarchy. */ class AWS_EVENTSTREAMRPC_API ClientContinuationHandler { public: +#ifdef NEVER /** * Invoked when a message is received on this continuation. */ @@ -346,13 +351,16 @@ namespace Aws * the TERMINATE_STREAM flag, or when the connection shuts down. */ virtual void OnContinuationClosed() = 0; +#endif virtual ~ClientContinuationHandler() noexcept = default; - +#ifdef NEVER private: friend class ClientContinuation; std::shared_ptr m_callbackData; +#endif }; +#ifdef NEVER /** * A wrapper for event-stream-rpc client continuation. */ @@ -433,7 +441,7 @@ namespace Aws struct aws_event_stream_rpc_client_continuation_token *continuationToken, void *userData) noexcept; }; - +#endif /** * Base class for types used by operations. */ @@ -478,7 +486,7 @@ namespace Aws virtual void OnStreamClosed(); protected: - friend class ClientOperation; + friend class ClientContinuationImpl; /** * Invoked when a message is received on this continuation. */ @@ -597,7 +605,7 @@ namespace Aws class AWS_EVENTSTREAMRPC_API OperationModelContext { public: - OperationModelContext(const ServiceModel &serviceModel) noexcept; + explicit OperationModelContext(const ServiceModel &serviceModel) noexcept; virtual ~OperationModelContext() noexcept = default; @@ -677,7 +685,7 @@ namespace Aws std::shared_ptr streamHandler, const OperationModelContext &operationModelContext, Crt::Allocator *allocator) noexcept; - ~ClientOperation() noexcept; + ~ClientOperation() noexcept override; ClientOperation(const ClientOperation &clientOperation) noexcept = delete; ClientOperation(ClientOperation &&clientOperation) noexcept = delete; @@ -694,12 +702,9 @@ namespace Aws std::future Close(OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; /** - * Get an operation result. - * @return Future which will be resolved when the corresponding RPC request completes. - */ - std::future GetOperationResult() noexcept; - - /** + * @deprecated This no longer does anything useful. Launch policy was added because of a + * mistake in the implementation that was attempting to chain two promises together. + * * Set the launch mode for executing operations. The mode is set to std::launch::deferred by default. * @param mode The launch mode to use. */ @@ -710,67 +715,26 @@ namespace Aws * Initiate a new client stream. Send the shape for the new stream. * @param shape A parameter for RPC operation. * @param onMessageFlushCallback Callback to invoke when the shape is flushed to the underlying transport. + * @param onResultCallback Callback to invoke with the untransformed activation result * @return Future which will be resolved once the message is sent. */ std::future Activate( const AbstractShapeBase *shape, - OnMessageFlushCallback onMessageFlushCallback) noexcept; + OnMessageFlushCallback &&onMessageFlushCallback, + std::function &&onResultCallback, + bool &synchronousSuccess) noexcept; /** * Returns the canonical model name associated with this operation across any client language. * Namespace included. * @return The model name. */ - virtual Crt::String GetModelName() const noexcept = 0; - - const OperationModelContext &m_operationModelContext; - std::launch m_asyncLaunchMode; + virtual Crt::String GetModelName() const noexcept; private: - EventStreamRpcStatusCode HandleData(const Crt::Optional &payload); - EventStreamRpcStatusCode HandleError( - const Crt::String &modelName, - const Crt::Optional &payload, - uint32_t messageFlags); - /** - * Invoked when a message is received on this continuation. - */ - void OnContinuationMessage( - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags) override; - /** - * Invoked when the continuation is closed. - * - * Once the continuation is closed, no more messages may be sent or received. - * The continuation is closed when a message is sent or received with - * the TERMINATE_STREAM flag, or when the connection shuts down. - */ - void OnContinuationClosed() override; - - const EventStreamHeader *GetHeaderByName( - const Crt::List &headers, - const Crt::String &name) noexcept; + Aws::Crt::Allocator *m_allocator; - enum CloseState - { - WONT_CLOSE = 0, - WILL_CLOSE, - ALREADY_CLOSED - }; - - uint32_t m_messageCount; - Crt::Allocator *m_allocator; - std::shared_ptr m_streamHandler; - ClientContinuation m_clientContinuation; - /* This mutex protects m_resultReceived & m_closeState. */ - std::mutex m_continuationMutex; - bool m_resultReceived; - std::promise m_initialResponsePromise; - bool m_expectingClose; - bool m_streamClosedCalled; - std::condition_variable m_closeReady; + std::shared_ptr m_impl; }; } // namespace Eventstreamrpc diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 2326133fe..488ec7f2d 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -23,15 +23,146 @@ namespace Aws { namespace Eventstreamrpc { - /* Because `std::function` cannot be typecasted to void *, we must contain it in a struct. */ - struct OnMessageFlushCallbackContainer + static void s_deleteMessageCallbackContainer(void *); + + /* + * This structure has evolved into a more complex form in order to support some additional requirements + * in the eventstream refactor. + * + * In order to maintain behavioral compatibility while removing blocking destruction, we need to be able to + * synchronously "cancel" pending callbacks/completions at the C++ level. The easiest way to accomplish + * this is by ref-counting the structure (so both the C++ and C continuations can reference it) and using + * a lock + completion state to control whether or not the completion actually happens (first one wins). + * + * Because C callbacks are just function pointers, using shared_ptrs is difficult/awkward. So instead we + * just use the C pattern of an internal ref-count that deletes on dropping to zero. + * + * We also want to support tracking the whole set of pending callbacks so that we can cancel them all + * at once while still efficiently completing then one-at-a-time, hence the intrusive linked list node. The + * linked list node is not always used (for example, the connect message callback is not added to any list). + */ + class OnMessageFlushCallbackContainer { - explicit OnMessageFlushCallbackContainer(Crt::Allocator *allocator) : allocator(allocator) {} - Crt::Allocator *allocator; - OnMessageFlushCallback onMessageFlushCallback; - std::promise onFlushPromise; + public: + OnMessageFlushCallbackContainer(Crt::Allocator *allocator, OnMessageFlushCallback &&flushCallback) + : m_allocator(allocator), m_refCount({}), m_sharedState({}) + { + aws_ref_count_init(&m_refCount, this, s_deleteMessageCallbackContainer); + aws_ref_count_acquire(&m_refCount); // always start at 2, one for C++, one for C + AWS_ZERO_STRUCT(m_sharedState.m_node); + m_sharedState.m_state = CallbackState::Incomplete; + m_sharedState.m_onMessageFlushCallback = std::move(flushCallback); + } + + OnMessageFlushCallbackContainer( + Crt::Allocator *allocator, + OnMessageFlushCallback &&flushCallback, + std::promise &&flushPromise) + : OnMessageFlushCallbackContainer(allocator, std::move(flushCallback)) + { + m_sharedState.m_onFlushPromise = std::move(flushPromise); + } + + ~OnMessageFlushCallbackContainer() = default; + + static void Complete(OnMessageFlushCallbackContainer *callback, RpcError error) + { + if (callback == nullptr) + { + return; + } + + bool performCallback = false; + OnMessageFlushCallback onMessageFlushCallback; + std::promise onFlushPromise; + { + std::lock_guard lock(callback->m_sharedStateLock); + + if (callback->m_sharedState.m_state == CallbackState::Incomplete) + { + performCallback = true; + callback->m_sharedState.m_state = CallbackState::Finished; + onMessageFlushCallback = std::move(callback->m_sharedState.m_onMessageFlushCallback); + onFlushPromise = std::move(callback->m_sharedState.m_onFlushPromise); + if (aws_linked_list_node_is_in_list(&callback->m_sharedState.m_node)) + { + aws_linked_list_remove(&callback->m_sharedState.m_node); + } + } + } + + if (performCallback) + { + if (error.crtError != AWS_ERROR_SUCCESS) + { + AWS_LOGF_ERROR( + AWS_LS_EVENT_STREAM_RPC_CLIENT, + "A CRT error occurred while attempting to send a message: %s", + Crt::ErrorDebugString(error.crtError)); + } + onFlushPromise.set_value(error); + if (onMessageFlushCallback) + { + onMessageFlushCallback(error.crtError); + } + } + } + + static void Release(OnMessageFlushCallbackContainer *callback) + { + if (callback == nullptr) + { + return; + } + + aws_ref_count_release(&callback->m_refCount); + } + + Aws::Crt::Allocator *GetAllocator() const { return m_allocator; } + + void AddToList(struct aws_linked_list *list) + { + std::lock_guard lock(m_sharedStateLock); + + aws_linked_list_push_back(list, &m_sharedState.m_node); + } + + private: + enum class CallbackState + { + Incomplete, + Finished + }; + + Crt::Allocator *m_allocator; + struct aws_ref_count m_refCount; + + std::mutex m_sharedStateLock; + struct + { + CallbackState m_state; + struct aws_linked_list_node m_node; + OnMessageFlushCallback m_onMessageFlushCallback; + std::promise m_onFlushPromise; + } m_sharedState; }; + static void s_deleteMessageCallbackContainer(void *object) + { + auto container = reinterpret_cast(object); + + Aws::Crt::Delete(container, container->GetAllocator()); + } + + static void s_protocolMessageCallback(int errorCode, void *userData) noexcept + { + auto *callbackData = static_cast(userData); + + auto rpcStatus = (errorCode == AWS_ERROR_SUCCESS) ? EVENT_STREAM_RPC_SUCCESS : EVENT_STREAM_RPC_CRT_ERROR; + OnMessageFlushCallbackContainer::Complete(callbackData, {rpcStatus, errorCode}); + OnMessageFlushCallbackContainer::Release(callbackData); + } + MessageAmendment::MessageAmendment(Crt::Allocator *allocator) noexcept : m_headers(), m_payload(), m_allocator(allocator) { @@ -209,9 +340,15 @@ namespace Aws case EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE: return "EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE"; case EVENT_STREAM_RPC_CRT_ERROR: + { Crt::String ret = "Failed with EVENT_STREAM_RPC_CRT_ERROR, the CRT error was "; ret += Crt::ErrorDebugString(crtError); return ret; + } + case EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED: + return "EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED"; + case EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS: + return "EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS"; } return "Unknown status code"; } @@ -519,7 +656,7 @@ namespace Aws const ConnectionConfig &connectionOptions, ConnectionLifecycleHandler *connectionLifecycleHandler) noexcept; - ClientContinuation NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept; + std::shared_ptr NewStream() noexcept; void Close() noexcept; @@ -527,25 +664,11 @@ namespace Aws void Shutdown() noexcept; - std::future SendProtocolMessage( - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags, - OnMessageFlushCallback onMessageFlushCallback) noexcept; - private: void CloseInternal(bool isShutdown) noexcept; void MoveToDisconnected(RpcError error) noexcept; - int SendProtocolMessageAux( - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags, - OnMessageFlushCallback &&onMessageFlushCallback, - std::promise *sendOutcomePromise, - bool takeLock) noexcept; + int SendConnectMessage(OnMessageFlushCallback &&onMessageFlushCallback) noexcept; enum class ClientState { @@ -572,6 +695,7 @@ namespace Aws ClientState m_currentState; ClientState m_desiredState; ConnectionCallbackContext m_callbackContext; + OnMessageFlushCallbackContainer *m_connectFlushContainer; bool m_hasShutDown; } m_sharedState; @@ -594,7 +718,7 @@ namespace Aws ClientConnectionImpl::ClientConnectionImpl(Crt::Allocator *allocator, aws_client_bootstrap *bootstrap) noexcept : m_allocator(allocator), m_lifecycleHandler(nullptr), m_connectMessageAmender(nullptr), m_bootstrap(aws_client_bootstrap_acquire(bootstrap)), m_eventLoop(nullptr), - m_sharedState{nullptr, ClientState::Disconnected, ClientState::Disconnected, {}, false} + m_sharedState{nullptr, ClientState::Disconnected, ClientState::Disconnected, {}, nullptr, false} { m_eventLoop = aws_event_loop_group_get_next_loop(bootstrap->event_loop_group); } @@ -661,6 +785,7 @@ namespace Aws void ClientConnectionImpl::CloseInternal(bool isShutdown) noexcept { ConnectionCallbackContext localContext = {}; + OnMessageFlushCallbackContainer *connectFlushContainer = nullptr; { std::lock_guard lock(m_sharedStateLock); m_sharedState.m_desiredState = ClientState::Disconnected; @@ -682,10 +807,17 @@ namespace Aws if (isShutdown) { localContext = std::move(m_sharedState.m_callbackContext); + connectFlushContainer = m_sharedState.m_connectFlushContainer; + m_sharedState.m_connectFlushContainer = nullptr; } } localContext.InvokeCallbacks(); + + OnMessageFlushCallbackContainer::Complete( + connectFlushContainer, + {EVENT_STREAM_RPC_CONNECTION_CLOSED, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED}); + OnMessageFlushCallbackContainer::Release(connectFlushContainer); } void ClientConnectionImpl::Shutdown() noexcept @@ -722,12 +854,12 @@ namespace Aws } m_lifecycleHandler = connectionLifecycleHandler; - std::function disconnectCallback = [this](RpcError error) - { this->m_lifecycleHandler->OnDisconnectCallback(error); }; - std::function errorCallback = [this](RpcError error) - { return this->m_lifecycleHandler->OnErrorCallback(error); }; - std::function connectionSuccessCallback = [this]() - { this->m_lifecycleHandler->OnConnectCallback(); }; + std::function disconnectCallback = [connectionLifecycleHandler](RpcError error) + { connectionLifecycleHandler->OnDisconnectCallback(error); }; + std::function errorCallback = [connectionLifecycleHandler](RpcError error) + { return connectionLifecycleHandler->OnErrorCallback(error); }; + std::function connectionSuccessCallback = [connectionLifecycleHandler]() + { connectionLifecycleHandler->OnConnectCallback(); }; m_connectionConfig = connectionConfig; m_selfReference = shared_from_this(); @@ -773,86 +905,47 @@ namespace Aws return m_sharedState.m_currentState == ClientState::Connected; } - static void s_protocolMessageCallback(int errorCode, void *userData) noexcept + int ClientConnectionImpl::SendConnectMessage(OnMessageFlushCallback &&onMessageFlushCallback) noexcept { - auto *callbackData = static_cast(userData); - - if (errorCode) - { - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "A CRT error occurred while attempting to send a message: %s", - Crt::ErrorDebugString(errorCode)); - callbackData->onFlushPromise.set_value({EVENT_STREAM_RPC_CRT_ERROR, errorCode}); - } - else - { - callbackData->onFlushPromise.set_value({EVENT_STREAM_RPC_SUCCESS, 0}); - } - - /* Call the user-provided callback. */ - if (callbackData->onMessageFlushCallback) + MessageAmendment messageAmendment; + if (m_connectionConfig.GetConnectAmendment().has_value()) { - callbackData->onMessageFlushCallback(errorCode); + MessageAmendment connectAmendment(m_connectionConfig.GetConnectAmendment().value()); + // The version header is necessary for establishing the connection. + messageAmendment.AddHeader(EventStreamHeader( + Crt::String(EVENTSTREAM_VERSION_HEADER), Crt::String(EVENTSTREAM_VERSION_STRING), m_allocator)); + messageAmendment.PrependHeaders(std::move(connectAmendment).GetHeaders()); + messageAmendment.SetPayload(std::move(connectAmendment).GetPayload()); } - Crt::Delete(callbackData, callbackData->allocator); - } - - ClientContinuation ClientConnectionImpl::NewStream( - ClientContinuationHandler &clientContinuationHandler) noexcept - { - std::lock_guard lock(m_sharedStateLock); - return {m_sharedState.m_underlyingConnection, clientContinuationHandler, m_allocator}; - } - - int ClientConnectionImpl::SendProtocolMessageAux( - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags, - OnMessageFlushCallback &&onMessageFlushCallback, - std::promise *sendOutcomePromise, - bool takeLock) noexcept - { - OnMessageFlushCallbackContainer *callbackContainer = nullptr; struct aws_array_list headersArray; - s_fillNativeHeadersArray(headers, &headersArray, m_allocator); + s_fillNativeHeadersArray(messageAmendment.GetHeaders(), &headersArray, m_allocator); struct aws_event_stream_rpc_message_args msg_args; msg_args.headers = (struct aws_event_stream_header_value_pair *)headersArray.data; - msg_args.headers_count = headers.size(); - msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; - msg_args.message_type = messageType; - msg_args.message_flags = messageFlags; + msg_args.headers_count = messageAmendment.GetHeaders().size(); + msg_args.payload = messageAmendment.GetPayload().has_value() + ? (aws_byte_buf *)(&(messageAmendment.GetPayload().value())) + : nullptr; + msg_args.message_type = AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_CONNECT; + msg_args.message_flags = 0U; - callbackContainer = Crt::New(m_allocator, m_allocator); - callbackContainer->onMessageFlushCallback = std::move(onMessageFlushCallback); - if (sendOutcomePromise) - { - callbackContainer->onFlushPromise = std::move(*sendOutcomePromise); - } + // It shouldn't be possible to interrupt a connect with another connect, but let's handle that case anyways + OnMessageFlushCallbackContainer::Complete( + m_sharedState.m_connectFlushContainer, {EVENT_STREAM_RPC_CONNECTION_SETUP_FAILED, AWS_ERROR_SUCCESS}); + OnMessageFlushCallbackContainer::Release(m_sharedState.m_connectFlushContainer); + + m_sharedState.m_connectFlushContainer = + Crt::New(m_allocator, m_allocator, std::move(onMessageFlushCallback)); int errorCode = AWS_ERROR_SUCCESS; + if (aws_event_stream_rpc_client_connection_send_protocol_message( + m_sharedState.m_underlyingConnection, + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(m_sharedState.m_connectFlushContainer))) { - if (takeLock) - { - m_sharedStateLock.lock(); - } - - if (aws_event_stream_rpc_client_connection_send_protocol_message( - m_sharedState.m_underlyingConnection, - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(callbackContainer))) - { - errorCode = aws_last_error(); - } - - if (takeLock) - { - m_sharedStateLock.unlock(); - } + errorCode = aws_last_error(); } /* Cleanup. */ @@ -867,38 +960,16 @@ namespace Aws AWS_LS_EVENT_STREAM_RPC_CLIENT, "A CRT error occurred while queueing a message to be sent on the connection: %s", Crt::ErrorDebugString(errorCode)); - if (sendOutcomePromise) - { - sendOutcomePromise->set_value({EVENT_STREAM_RPC_CRT_ERROR, errorCode}); - } - Crt::Delete(callbackContainer, m_allocator); + OnMessageFlushCallbackContainer::Complete( + m_sharedState.m_connectFlushContainer, {EVENT_STREAM_RPC_CRT_ERROR, errorCode}); + OnMessageFlushCallbackContainer::Release(m_sharedState.m_connectFlushContainer); + m_sharedState.m_connectFlushContainer = nullptr; } return (errorCode == AWS_ERROR_SUCCESS) ? AWS_OP_SUCCESS : AWS_OP_ERR; } - std::future ClientConnectionImpl::SendProtocolMessage( - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags, - OnMessageFlushCallback onMessageFlushCallback) noexcept - { - std::promise sendOutcomePromise; - auto sendOutcomeFuture = sendOutcomePromise.get_future(); - SendProtocolMessageAux( - headers, - payload, - messageType, - messageFlags, - std::move(onMessageFlushCallback), - &sendOutcomePromise, - true); - - return sendOutcomeFuture; - } - void ClientConnectionImpl::s_onConnectionSetup( struct aws_event_stream_rpc_client_connection *connection, int errorCode, @@ -930,28 +1001,8 @@ namespace Aws } impl->m_sharedState.m_currentState = ClientState::PendingConnack; - MessageAmendment messageAmendment; - - if (impl->m_connectionConfig.GetConnectAmendment().has_value()) - { - MessageAmendment connectAmendment(impl->m_connectionConfig.GetConnectAmendment().value()); - // The version header is necessary for establishing the connection. - messageAmendment.AddHeader(EventStreamHeader( - Crt::String(EVENTSTREAM_VERSION_HEADER), - Crt::String(EVENTSTREAM_VERSION_STRING), - impl->m_allocator)); - messageAmendment.PrependHeaders(std::move(connectAmendment).GetHeaders()); - messageAmendment.SetPayload(std::move(connectAmendment).GetPayload()); - } - - if (impl->SendProtocolMessageAux( - messageAmendment.GetHeaders(), - messageAmendment.GetPayload(), - AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_CONNECT, - 0U, - impl->m_connectionConfig.GetConnectRequestCallback(), - nullptr, - false)) + auto callback = impl->m_connectionConfig.GetConnectRequestCallback(); + if (impl->SendConnectMessage(std::move(callback))) { impl->m_sharedState.m_callbackContext.SetError({EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}); impl->m_sharedState.m_currentState = ClientState::Disconnecting; @@ -1065,9 +1116,9 @@ namespace Aws return m_impl->Connect(connectionOptions, connectionLifecycleHandler); } - ClientContinuation ClientConnection::NewStream(ClientContinuationHandler &clientContinuationHandler) noexcept + std::shared_ptr ClientConnection::NewStream() noexcept { - return m_impl->NewStream(clientContinuationHandler); + return m_impl->NewStream(); } void ClientConnection::Close() noexcept @@ -1080,112 +1131,239 @@ namespace Aws return m_impl->IsOpen(); } - void AbstractShapeBase::s_customDeleter(AbstractShapeBase *shape) noexcept + OperationModelContext::OperationModelContext(const ServiceModel &serviceModel) noexcept + : m_serviceModel(serviceModel) { - if (shape->m_allocator != nullptr) - Crt::Delete(shape, shape->m_allocator); } - struct RawContinuationCallbackDataWrapper - { - RawContinuationCallbackDataWrapper( - Aws::Crt::Allocator *allocator, - const std::shared_ptr &callbackData) - : m_allocator(allocator), m_callbackData(callbackData) - { - } - - Aws::Crt::Allocator *m_allocator; - std::shared_ptr m_callbackData; - }; - - static void s_onContinuationTerminated(void *user_data) + void OperationError::SerializeToJsonObject(Crt::JsonObject &payloadObject) const { - if (user_data == nullptr) - { - return; - } - - struct RawContinuationCallbackDataWrapper *wrapper = - static_cast(user_data); - Aws::Crt::Delete(wrapper, wrapper->m_allocator); + (void)payloadObject; } - ClientContinuation::ClientContinuation( - struct aws_event_stream_rpc_client_connection *connection, - ClientContinuationHandler &continuationHandler, - Crt::Allocator *allocator) noexcept - : m_allocator(allocator), m_continuationHandler(continuationHandler), m_continuationToken(nullptr) + void OperationError::s_customDeleter(OperationError *shape) noexcept { - struct aws_event_stream_rpc_client_stream_continuation_options options; - options.on_continuation = ClientContinuation::s_onContinuationMessage; - options.on_continuation_closed = ClientContinuation::s_onContinuationClosed; - options.on_continuation_terminated = s_onContinuationTerminated; - - m_callbackData = Crt::MakeShared(m_allocator, this, m_allocator); + AbstractShapeBase::s_customDeleter(shape); + } - m_continuationHandler.m_callbackData = m_callbackData; - options.user_data = reinterpret_cast( - Aws::Crt::New(allocator, allocator, m_callbackData)); + AbstractShapeBase::AbstractShapeBase() noexcept : m_allocator(nullptr) {} - if (connection) + void AbstractShapeBase::s_customDeleter(AbstractShapeBase *shape) noexcept + { + if (shape->m_allocator != nullptr) { - m_continuationToken = aws_event_stream_rpc_client_connection_new_stream(connection, &options); - if (m_continuationToken == nullptr) - { - m_continuationHandler.m_callbackData = nullptr; - m_callbackData = nullptr; - } + Crt::Delete(shape, shape->m_allocator); } } - ClientContinuation::~ClientContinuation() noexcept + TaggedResult::TaggedResult(Crt::ScopedResource operationResponse) noexcept + : m_responseType(OPERATION_RESPONSE), m_rpcError({}) { - Release(); + m_operationResult.m_response = std::move(operationResponse); } - void ClientContinuation::Release() + TaggedResult::~TaggedResult() noexcept { - if (m_callbackData != nullptr) + if (m_responseType == OPERATION_RESPONSE) { - { - const std::lock_guard lock(m_callbackData->callbackMutex); - m_callbackData->continuationDestroyed = true; - } + m_operationResult.m_response.~unique_ptr(); } - - if (m_continuationToken) + else if (m_responseType == OPERATION_ERROR) { - aws_event_stream_rpc_client_continuation_release(m_continuationToken); - m_continuationToken = nullptr; + m_operationResult.m_error.~unique_ptr(); } } - void ClientContinuation::s_onContinuationMessage( - struct aws_event_stream_rpc_client_continuation_token *continuationToken, - const struct aws_event_stream_rpc_message_args *messageArgs, - void *userData) noexcept + TaggedResult::TaggedResult(Crt::ScopedResource operationError) noexcept + : m_responseType(OPERATION_ERROR), m_rpcError({EVENT_STREAM_RPC_UNINITIALIZED, 0}) { - (void)continuationToken; - /* The `userData` pointer is used to pass a `ContinuationCallbackData` object. */ - auto *callbackData = static_cast(userData)->m_callbackData.get(); - auto *thisContinuation = callbackData->clientContinuation; + m_operationResult.m_error = std::move(operationError); + } - Crt::List continuationMessageHeaders; - for (size_t i = 0; i < messageArgs->headers_count; ++i) + TaggedResult &TaggedResult::operator=(TaggedResult &&rhs) noexcept + { + m_responseType = rhs.m_responseType; + if (m_responseType == OPERATION_RESPONSE) { - continuationMessageHeaders.emplace_back( - EventStreamHeader(messageArgs->headers[i], thisContinuation->m_allocator)); + m_operationResult.m_response = std::move(rhs.m_operationResult.m_response); } - - Crt::Optional payload; - - if (messageArgs->payload) + else if (m_responseType == OPERATION_ERROR) { - payload = Crt::Optional(*messageArgs->payload); + m_operationResult.m_error = std::move(rhs.m_operationResult.m_error); } - else - { + m_rpcError = rhs.m_rpcError; + rhs.m_rpcError = {EVENT_STREAM_RPC_UNINITIALIZED, 0}; + + return *this; + } + + TaggedResult::TaggedResult(RpcError rpcError) noexcept + : m_responseType(RPC_ERROR), m_operationResult(), m_rpcError(rpcError) + { + } + + TaggedResult::TaggedResult() noexcept + : m_responseType(RPC_ERROR), m_operationResult(), m_rpcError({EVENT_STREAM_RPC_UNINITIALIZED, 0}) + { + } + + TaggedResult::TaggedResult(TaggedResult &&rhs) noexcept + { + m_responseType = rhs.m_responseType; + if (m_responseType == OPERATION_RESPONSE) + { + m_operationResult.m_response = std::move(rhs.m_operationResult.m_response); + } + else if (m_responseType == OPERATION_ERROR) + { + m_operationResult.m_error = std::move(rhs.m_operationResult.m_error); + } + m_rpcError = rhs.m_rpcError; + rhs.m_rpcError = {EVENT_STREAM_RPC_UNINITIALIZED, 0}; + } + + TaggedResult::operator bool() const noexcept + { + return m_responseType == OPERATION_RESPONSE; + } + + AbstractShapeBase *TaggedResult::GetOperationResponse() const noexcept + { + return (m_responseType == OPERATION_RESPONSE) ? m_operationResult.m_response.get() : nullptr; + } + + OperationError *TaggedResult::GetOperationError() const noexcept + { + return (m_responseType == OPERATION_ERROR) ? m_operationResult.m_error.get() : nullptr; + } + + RpcError TaggedResult::GetRpcError() const noexcept + { + if (m_responseType == RPC_ERROR) + { + return m_rpcError; + } + else + { + /* Assume success since an application response or error was received. */ + return {EVENT_STREAM_RPC_SUCCESS, 0}; + } + } + + bool StreamResponseHandler::OnStreamError(Crt::ScopedResource operationError, RpcError rpcError) + { + (void)operationError; + (void)rpcError; + /* Note: Always returning true implies that the stream should close + * as a result of encountering this error. */ + return true; + } + + void StreamResponseHandler::OnStreamEvent(Crt::ScopedResource response) {} + + void StreamResponseHandler::OnStreamClosed() {} + +#ifdef NEVER + struct RawContinuationCallbackDataWrapper + { + RawContinuationCallbackDataWrapper( + Aws::Crt::Allocator *allocator, + const std::shared_ptr &callbackData) + : m_allocator(allocator), m_callbackData(callbackData) + { + } + + Aws::Crt::Allocator *m_allocator; + std::shared_ptr m_callbackData; + }; + + static void s_onContinuationTerminated(void *user_data) + { + if (user_data == nullptr) + { + return; + } + + struct RawContinuationCallbackDataWrapper *wrapper = + static_cast(user_data); + Aws::Crt::Delete(wrapper, wrapper->m_allocator); + } + + ClientContinuation::ClientContinuation( + struct aws_event_stream_rpc_client_connection *connection, + ClientContinuationHandler &continuationHandler, + Crt::Allocator *allocator) noexcept + : m_allocator(allocator), m_continuationHandler(continuationHandler), m_continuationToken(nullptr) + { + struct aws_event_stream_rpc_client_stream_continuation_options options; + options.on_continuation = ClientContinuation::s_onContinuationMessage; + options.on_continuation_closed = ClientContinuation::s_onContinuationClosed; + options.on_continuation_terminated = s_onContinuationTerminated; + + m_callbackData = Crt::MakeShared(m_allocator, this, m_allocator); + + m_continuationHandler.m_callbackData = m_callbackData; + options.user_data = reinterpret_cast( + Aws::Crt::New(allocator, allocator, m_callbackData)); + + if (connection) + { + m_continuationToken = aws_event_stream_rpc_client_connection_new_stream(connection, &options); + if (m_continuationToken == nullptr) + { + m_continuationHandler.m_callbackData = nullptr; + m_callbackData = nullptr; + } + } + } + + ClientContinuation::~ClientContinuation() noexcept + { + Release(); + } + + void ClientContinuation::Release() + { + if (m_callbackData != nullptr) + { + { + const std::lock_guard lock(m_callbackData->callbackMutex); + m_callbackData->continuationDestroyed = true; + } + } + + if (m_continuationToken) + { + aws_event_stream_rpc_client_continuation_release(m_continuationToken); + m_continuationToken = nullptr; + } + } + + void ClientContinuation::s_onContinuationMessage( + struct aws_event_stream_rpc_client_continuation_token *continuationToken, + const struct aws_event_stream_rpc_message_args *messageArgs, + void *userData) noexcept + { + (void)continuationToken; + /* The `userData` pointer is used to pass a `ContinuationCallbackData` object. */ + auto *callbackData = static_cast(userData)->m_callbackData.get(); + auto *thisContinuation = callbackData->clientContinuation; + + Crt::List continuationMessageHeaders; + for (size_t i = 0; i < messageArgs->headers_count; ++i) + { + continuationMessageHeaders.emplace_back( + EventStreamHeader(messageArgs->headers[i], thisContinuation->m_allocator)); + } + + Crt::Optional payload; + + if (messageArgs->payload) + { + payload = Crt::Optional(*messageArgs->payload); + } + else + { payload = Crt::Optional(); } @@ -1365,193 +1543,68 @@ namespace Aws } } - OperationModelContext::OperationModelContext(const ServiceModel &serviceModel) noexcept - : m_serviceModel(serviceModel) - { - } - - void OperationError::SerializeToJsonObject(Crt::JsonObject &payloadObject) const + std::future ClientOperation::GetOperationResult() noexcept { - (void)payloadObject; - } + { + const std::lock_guard lock(m_continuationMutex); - AbstractShapeBase::AbstractShapeBase() noexcept : m_allocator(nullptr) {} + if (m_clientContinuation.IsClosed() && !m_resultReceived) + { + AWS_LOGF_ERROR(AWS_LS_EVENT_STREAM_RPC_CLIENT, "The underlying stream is already closed."); + m_initialResponsePromise.set_value(TaggedResult({EVENT_STREAM_RPC_CONNECTION_CLOSED, 0})); + m_resultReceived = true; + } + } - ClientOperation::ClientOperation( - ClientConnection &connection, - std::shared_ptr streamHandler, - const OperationModelContext &operationModelContext, - Crt::Allocator *allocator) noexcept - : m_operationModelContext(operationModelContext), m_asyncLaunchMode(std::launch::deferred), - m_messageCount(0), m_allocator(allocator), m_streamHandler(streamHandler), - m_clientContinuation(connection.NewStream(*this)), m_expectingClose(false), m_streamClosedCalled(false) - { + return m_initialResponsePromise.get_future(); } - ClientOperation::~ClientOperation() noexcept + const EventStreamHeader *ClientOperation::GetHeaderByName( + const Crt::List &headers, + const Crt::String &name) noexcept { - Close().wait(); - m_clientContinuation.Release(); - // std::unique_lock lock(m_continuationMutex); - // m_closeReady.wait(lock, [this] { return m_expectingClose == false; }); + for (auto it = headers.begin(); it != headers.end(); ++it) + { + if (name == it->GetHeaderName()) + { + return &(*it); + } + } + return nullptr; } - TaggedResult::TaggedResult(Crt::ScopedResource operationResponse) noexcept - : m_responseType(OPERATION_RESPONSE) + EventStreamRpcStatusCode ClientOperation::HandleData(const Crt::Optional &payload) { - m_operationResult.m_response = std::move(operationResponse); - } + Crt::StringView payloadStringView; + if (payload.has_value()) + { + payloadStringView = Crt::ByteCursorToStringView(Crt::ByteCursorFromByteBuf(payload.value())); + } - TaggedResult::~TaggedResult() noexcept - { - if (m_responseType == OPERATION_RESPONSE) + /* The value of this hashmap contains the function that allocates the response object from the + * payload. */ + /* Responses after the first message don't necessarily have the same shape as the first. */ + Crt::ScopedResource response; + if (m_messageCount == 1) { - m_operationResult.m_response.~unique_ptr(); + response = m_operationModelContext.AllocateInitialResponseFromPayload(payloadStringView, m_allocator); } - else if (m_responseType == OPERATION_ERROR) + else { - m_operationResult.m_error.~unique_ptr(); + response = m_operationModelContext.AllocateStreamingResponseFromPayload(payloadStringView, m_allocator); } - } - - TaggedResult::TaggedResult(Crt::ScopedResource operationError) noexcept - : m_responseType(OPERATION_ERROR), m_rpcError({EVENT_STREAM_RPC_UNINITIALIZED, 0}) - { - m_operationResult.m_error = std::move(operationError); - } - TaggedResult &TaggedResult::operator=(TaggedResult &&rhs) noexcept - { - m_responseType = rhs.m_responseType; - if (m_responseType == OPERATION_RESPONSE) + if (response.get() == nullptr) { - m_operationResult.m_response = std::move(rhs.m_operationResult.m_response); + AWS_LOGF_ERROR(AWS_LS_EVENT_STREAM_RPC_CLIENT, "Failed to allocate a response from the payload."); + return EVENT_STREAM_RPC_ALLOCATION_ERROR; } - else if (m_responseType == OPERATION_ERROR) + + if (m_messageCount == 1) { - m_operationResult.m_error = std::move(rhs.m_operationResult.m_error); - } - m_rpcError = rhs.m_rpcError; - rhs.m_rpcError = {EVENT_STREAM_RPC_UNINITIALIZED, 0}; - - return *this; - } - - TaggedResult::TaggedResult(RpcError rpcError) noexcept - : m_responseType(RPC_ERROR), m_operationResult(), m_rpcError(rpcError) - { - } - - TaggedResult::TaggedResult() noexcept - : m_responseType(RPC_ERROR), m_operationResult(), m_rpcError({EVENT_STREAM_RPC_UNINITIALIZED, 0}) - { - } - - TaggedResult::TaggedResult(TaggedResult &&rhs) noexcept - { - m_responseType = rhs.m_responseType; - if (m_responseType == OPERATION_RESPONSE) - { - m_operationResult.m_response = std::move(rhs.m_operationResult.m_response); - } - else if (m_responseType == OPERATION_ERROR) - { - m_operationResult.m_error = std::move(rhs.m_operationResult.m_error); - } - m_rpcError = rhs.m_rpcError; - rhs.m_rpcError = {EVENT_STREAM_RPC_UNINITIALIZED, 0}; - } - - TaggedResult::operator bool() const noexcept - { - return m_responseType == OPERATION_RESPONSE; - } - - AbstractShapeBase *TaggedResult::GetOperationResponse() const noexcept - { - return (m_responseType == OPERATION_RESPONSE) ? m_operationResult.m_response.get() : nullptr; - } - - OperationError *TaggedResult::GetOperationError() const noexcept - { - return (m_responseType == OPERATION_ERROR) ? m_operationResult.m_error.get() : nullptr; - } - - RpcError TaggedResult::GetRpcError() const noexcept - { - if (m_responseType == RPC_ERROR) - { - return m_rpcError; - } - else - { - /* Assume success since an application response or error was received. */ - return {EVENT_STREAM_RPC_SUCCESS, 0}; - } - } - - std::future ClientOperation::GetOperationResult() noexcept - { - { - const std::lock_guard lock(m_continuationMutex); - - if (m_clientContinuation.IsClosed() && !m_resultReceived) - { - AWS_LOGF_ERROR(AWS_LS_EVENT_STREAM_RPC_CLIENT, "The underlying stream is already closed."); - m_initialResponsePromise.set_value(TaggedResult({EVENT_STREAM_RPC_CONNECTION_CLOSED, 0})); - m_resultReceived = true; - } - } - - return m_initialResponsePromise.get_future(); - } - - const EventStreamHeader *ClientOperation::GetHeaderByName( - const Crt::List &headers, - const Crt::String &name) noexcept - { - for (auto it = headers.begin(); it != headers.end(); ++it) - { - if (name == it->GetHeaderName()) - { - return &(*it); - } - } - return nullptr; - } - - EventStreamRpcStatusCode ClientOperation::HandleData(const Crt::Optional &payload) - { - Crt::StringView payloadStringView; - if (payload.has_value()) - { - payloadStringView = Crt::ByteCursorToStringView(Crt::ByteCursorFromByteBuf(payload.value())); - } - - /* The value of this hashmap contains the function that allocates the response object from the - * payload. */ - /* Responses after the first message don't necessarily have the same shape as the first. */ - Crt::ScopedResource response; - if (m_messageCount == 1) - { - response = m_operationModelContext.AllocateInitialResponseFromPayload(payloadStringView, m_allocator); - } - else - { - response = m_operationModelContext.AllocateStreamingResponseFromPayload(payloadStringView, m_allocator); - } - - if (response.get() == nullptr) - { - AWS_LOGF_ERROR(AWS_LS_EVENT_STREAM_RPC_CLIENT, "Failed to allocate a response from the payload."); - return EVENT_STREAM_RPC_ALLOCATION_ERROR; - } - - if (m_messageCount == 1) - { - const std::lock_guard lock(m_continuationMutex); - m_resultReceived = true; - m_initialResponsePromise.set_value(TaggedResult(std::move(response))); + const std::lock_guard lock(m_continuationMutex); + m_resultReceived = true; + m_initialResponsePromise.set_value(TaggedResult(std::move(response))); } else { @@ -1617,19 +1670,6 @@ namespace Aws return EVENT_STREAM_RPC_SUCCESS; } - bool StreamResponseHandler::OnStreamError(Crt::ScopedResource operationError, RpcError rpcError) - { - (void)operationError; - (void)rpcError; - /* Note: Always returning true implies that the stream should close - * as a result of encountering this error. */ - return true; - } - - void StreamResponseHandler::OnStreamEvent(Crt::ScopedResource response) {} - - void StreamResponseHandler::OnStreamClosed() {} - void ClientOperation::OnContinuationMessage( const Crt::List &headers, const Crt::Optional &payload, @@ -1799,6 +1839,26 @@ namespace Aws m_asyncLaunchMode = mode; } + class AWS_EVENTSTREAMRPC_API ClientOperation : public ClientContinuationHandler + { + public: + ClientOperation( + ClientConnection &connection, + std::shared_ptr streamHandler, + const OperationModelContext &operationModelContext, + Crt::Allocator *allocator) noexcept; + ~ClientOperation() noexcept override; + + std::future Close(OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + + void WithLaunchMode(std::launch mode) noexcept; + + std::future Activate( + const AbstractShapeBase *shape, + OnMessageFlushCallback onMessageFlushCallback, + std::function &&onResultCallback) noexcept; + }; + std::future ClientOperation::Close(OnMessageFlushCallback onMessageFlushCallback) noexcept { const std::lock_guard lock(m_continuationMutex); @@ -1856,10 +1916,802 @@ namespace Aws return onTerminatePromise.get_future(); } } +#endif // NEVER - void OperationError::s_customDeleter(OperationError *shape) noexcept + static const EventStreamHeader *s_GetHeaderByName( + const Crt::List &headers, + const Crt::String &name) noexcept { - AbstractShapeBase::s_customDeleter(shape); + for (const auto &header : headers) + { + if (name == header.GetHeaderName()) + { + return &header; + } + } + return nullptr; + } + + enum class EventStreamMessageRoutingType + { + Response, + Stream, + Error + }; + + struct MessageDeserialization + { + MessageDeserialization() : m_route(EventStreamMessageRoutingType::Error) {} + + MessageDeserialization(EventStreamMessageRoutingType route, Crt::ScopedResource shape) + : m_route(route), m_shape(std::move(shape)) + { + } + + MessageDeserialization(MessageDeserialization &&) = default; + + MessageDeserialization &operator=(MessageDeserialization &&) = default; + + EventStreamMessageRoutingType m_route; + Crt::ScopedResource m_shape; + }; + + struct MessageResult + { + MessageResult() : m_statusCode(EVENT_STREAM_RPC_SUCCESS) {} + + MessageResult(MessageResult &&) = default; + + MessageResult &operator=(MessageResult &&) = default; + + EventStreamRpcStatusCode m_statusCode; + Crt::Optional m_message; + }; + + enum class ContinuationStateType + { + None, + PendingActivate, + Activated, + PendingClose, + Closed, + }; + + struct ContinuationSharedState + { + ContinuationSharedState(); + + ContinuationStateType m_currentState; + ContinuationStateType m_desiredState; + struct aws_event_stream_rpc_client_continuation_token *m_continuation; + OnMessageFlushCallbackContainer *m_activationCallbackContainer; + std::function m_activationResponseCallback; + OnMessageFlushCallbackContainer *m_closeCallbackContainer; + }; + + ContinuationSharedState::ContinuationSharedState() + : m_currentState(ContinuationStateType::None), m_desiredState(ContinuationStateType::None), + m_continuation(nullptr), m_activationCallbackContainer(nullptr), m_activationResponseCallback(), + m_closeCallbackContainer(nullptr) + { + } + + class ClientContinuationImpl : public std::enable_shared_from_this + { + public: + ClientContinuationImpl( + Aws::Crt::Allocator *allocator, + struct aws_event_stream_rpc_client_connection *connection) noexcept; + virtual ~ClientContinuationImpl(); + + // Called by ClientOperation::~ClientOperation(); the returned future is completed after the + // termination callback of the underlying C continuation + std::future ShutDown() noexcept; + + std::future Activate( + const Crt::String &operation, + const Crt::List &headers, + const Crt::Optional &payload, + MessageType messageType, + uint32_t messageFlags, + std::function &&onResultCallback, + OnMessageFlushCallback &&onMessageFlushCallback, + bool &synchronousSuccess) noexcept; + + std::future Close(OnMessageFlushCallback &&onMessageFlushCallback = nullptr) noexcept; + + Crt::String GetModelName() const noexcept; + + void Initialize( + const OperationModelContext *operationModelContext, + std::shared_ptr streamHandler) noexcept + { + m_operationModelContext = operationModelContext; + m_streamHandler = std::move(streamHandler); + if (m_sharedState.m_continuation != nullptr) + { + m_selfReference = shared_from_this(); + } + } + + private: + MessageResult DeserializeRawMessage( + const struct aws_event_stream_rpc_message_args *rawMessage, + bool shouldBeActivationResponse) noexcept; + + void OnClosed() noexcept; + + void OnMessage(const struct aws_event_stream_rpc_message_args *messageArgs) noexcept; + + int SendCloseMessage( + OnMessageFlushCallback &&closeFlushCallback, + std::promise &&closeFlushPromise) noexcept; + + static void s_OnContinuationClosed( + struct aws_event_stream_rpc_client_continuation_token *token, + void *user_data) noexcept; + + static void s_OnContinuationMessage( + struct aws_event_stream_rpc_client_continuation_token *token, + const struct aws_event_stream_rpc_message_args *message_args, + void *user_data) noexcept; + + static void s_OnContinuationTerminated(void *user_data) noexcept; + + static void ReleaseContinuation( + Aws::Crt::Allocator *allocator, + const struct aws_client_bootstrap *bootstrap, + struct aws_event_stream_rpc_client_continuation_token *continuation) noexcept; + + Aws::Crt::Allocator *m_allocator; + + struct aws_client_bootstrap *m_clientBootstrap; + + std::shared_ptr m_selfReference; + + std::mutex m_sharedStateLock; + ContinuationSharedState m_sharedState; + + const OperationModelContext *m_operationModelContext; + std::shared_ptr m_streamHandler; + + std::promise m_terminationPromise; + }; + + ClientOperation::ClientOperation( + ClientConnection &connection, + std::shared_ptr streamHandler, + const OperationModelContext &operationModelContext, + Crt::Allocator *allocator) noexcept + : m_allocator(allocator), m_impl(connection.NewStream()) + { + m_impl->Initialize(&operationModelContext, std::move(streamHandler)); + } + + ClientOperation::~ClientOperation() noexcept + { + auto terminationFuture = m_impl->ShutDown(); + m_impl = nullptr; + terminationFuture.get(); + } + + std::future ClientOperation::Close(OnMessageFlushCallback onMessageFlushCallback) noexcept + { + return m_impl->Close(std::move(onMessageFlushCallback)); + } + + void ClientOperation::WithLaunchMode(std::launch mode) noexcept + { + (void)mode; + } + + Crt::String ClientOperation::GetModelName() const noexcept + { + return m_impl->GetModelName(); + } + + std::future ClientOperation::Activate( + const AbstractShapeBase *shape, + OnMessageFlushCallback &&onMessageFlushCallback, + std::function &&onResultCallback, + bool &synchronousSuccess) noexcept + { + Crt::List headers; + headers.emplace_back(EventStreamHeader( + Crt::String(CONTENT_TYPE_HEADER), Crt::String(CONTENT_TYPE_APPLICATION_JSON), m_allocator)); + headers.emplace_back( + EventStreamHeader(Crt::String(SERVICE_MODEL_TYPE_HEADER), GetModelName(), m_allocator)); + Crt::JsonObject payloadObject; + shape->SerializeToJsonObject(payloadObject); + Crt::String payloadString = payloadObject.View().WriteCompact(); + + return m_impl->Activate( + GetModelName(), + headers, + Crt::ByteBufFromCString(payloadString.c_str()), + AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE, + 0, + std::move(onResultCallback), + std::move(onMessageFlushCallback), + synchronousSuccess); + } + + ClientContinuationImpl::ClientContinuationImpl( + Aws::Crt::Allocator *allocator, + struct aws_event_stream_rpc_client_connection *connection) noexcept + : m_allocator(allocator), m_clientBootstrap(aws_client_bootstrap_acquire( + aws_event_stream_rpc_client_connection_get_client_bootstrap(connection))), + m_sharedState(), m_operationModelContext(nullptr) + { + struct aws_event_stream_rpc_client_stream_continuation_options continuation_options = { + .on_continuation = s_OnContinuationMessage, + .on_continuation_closed = s_OnContinuationClosed, + .on_continuation_terminated = s_OnContinuationTerminated, + .user_data = this, + }; + m_sharedState.m_continuation = + aws_event_stream_rpc_client_connection_new_stream(connection, &continuation_options); + + if (!m_sharedState.m_continuation) + { + m_sharedState.m_currentState = ContinuationStateType::Closed; + m_sharedState.m_desiredState = ContinuationStateType::Closed; + } + } + + ClientContinuationImpl::~ClientContinuationImpl() + { + m_terminationPromise.set_value(); + aws_client_bootstrap_release(m_clientBootstrap); + } + + // We use a task to release the C continuation to make it impossible to trigger the termination callback + // in a callstack that includes ClientContinationImpl methods or state. + // + // If we were the last ref holder then release would trigger the termination callback further down the + // callstack. This isn't necessarily unsafe, but for peace-of-mind, it's best for destruction to never + // get invoked on an object that has methods within the callstack. + struct AwsEventstreamContinuationReleaseTask + { + AwsEventstreamContinuationReleaseTask( + Aws::Crt::Allocator *allocator, + struct aws_event_stream_rpc_client_continuation_token *continuation) noexcept; + + struct aws_task m_task; + struct aws_allocator *m_allocator; + struct aws_event_stream_rpc_client_continuation_token *m_continuation; + }; + + static void s_releaseContinuation(struct aws_task *task, void *arg, enum aws_task_status status) + { + auto releaseTask = static_cast(arg); + + aws_event_stream_rpc_client_continuation_release(releaseTask->m_continuation); + + Aws::Crt::Delete(releaseTask, releaseTask->m_allocator); + } + + AwsEventstreamContinuationReleaseTask::AwsEventstreamContinuationReleaseTask( + Aws::Crt::Allocator *allocator, + struct aws_event_stream_rpc_client_continuation_token *continuation) noexcept + : m_task{}, m_allocator(allocator), m_continuation(continuation) + { + aws_task_init(&m_task, s_releaseContinuation, this, "AwsEventstreamContinuationReleaseTask"); + } + + void ClientContinuationImpl::ReleaseContinuation( + Aws::Crt::Allocator *allocator, + const struct aws_client_bootstrap *bootstrap, + struct aws_event_stream_rpc_client_continuation_token *continuation) noexcept + { + if (continuation == nullptr) + { + return; + } + + AWS_FATAL_ASSERT(bootstrap != NULL); + + struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(bootstrap->event_loop_group); + AWS_FATAL_ASSERT(event_loop != NULL); + + auto releaseTask = Aws::Crt::New(allocator, allocator, continuation); + aws_event_loop_schedule_task_now(event_loop, &releaseTask->m_task); + } + + std::future ClientContinuationImpl::ShutDown() noexcept + { + struct aws_event_stream_rpc_client_continuation_token *releaseContinuation = nullptr; + OnMessageFlushCallbackContainer *closeCallbackContainer = nullptr; + OnMessageFlushCallbackContainer *activationCallbackContainer = nullptr; + std::function activationResponseCallback; + + { + std::lock_guard lock(m_sharedStateLock); + if (m_sharedState.m_currentState == ContinuationStateType::None) + { + releaseContinuation = m_sharedState.m_continuation; + m_sharedState.m_continuation = nullptr; + m_sharedState.m_currentState = ContinuationStateType::Closed; + m_sharedState.m_desiredState = ContinuationStateType::Closed; + } + + activationCallbackContainer = m_sharedState.m_activationCallbackContainer; + m_sharedState.m_activationCallbackContainer = nullptr; + + closeCallbackContainer = m_sharedState.m_closeCallbackContainer; + m_sharedState.m_closeCallbackContainer = nullptr; + + activationResponseCallback = std::move(m_sharedState.m_activationResponseCallback); + m_sharedState.m_activationResponseCallback = nullptr; // unsure if necessary, let's be sure + } + + if (activationResponseCallback) + { + activationResponseCallback( + TaggedResult(RpcError{EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS})); + } + + /* + * Short-circuit and simulate both activate and close callbacks as necessary. Part of our contract is that + * when Shutdown returns, no further user-facing callbacks/promise completions will be performed. + */ + OnMessageFlushCallbackContainer::Complete( + activationCallbackContainer, {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); + OnMessageFlushCallbackContainer::Release(activationCallbackContainer); + + OnMessageFlushCallbackContainer::Complete( + closeCallbackContainer, {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); + OnMessageFlushCallbackContainer::Release(closeCallbackContainer); + + if (releaseContinuation != nullptr) + { + ReleaseContinuation(m_allocator, m_clientBootstrap, releaseContinuation); + } + else + { + Close(); + } + + return m_terminationPromise.get_future(); + } + + std::future ClientContinuationImpl::Activate( + const Crt::String &operation, + const Crt::List &headers, + const Crt::Optional &payload, + MessageType messageType, + uint32_t messageFlags, + std::function &&onResultCallback, + OnMessageFlushCallback &&onMessageFlushCallback, + bool &synchronousSuccess) noexcept + { + int result = AWS_OP_SUCCESS; + synchronousSuccess = false; + struct aws_array_list headersArray; // guaranteed to be zeroed or valid if we reach the end of the function + OnMessageFlushCallbackContainer *activationFailureContainer = nullptr; + std::promise activationPromise; + std::future activationFuture = activationPromise.get_future(); + { + std::lock_guard lock(m_sharedStateLock); + if (m_sharedState.m_continuation == nullptr) + { + activationPromise.set_value({EVENT_STREAM_RPC_CONNECTION_CLOSED, 0}); + return activationFuture; + } + + switch (m_sharedState.m_currentState) + { + case ContinuationStateType::PendingActivate: + case ContinuationStateType::Activated: + activationPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED, 0}); + return activationFuture; + + case ContinuationStateType::PendingClose: + case ContinuationStateType::Closed: + activationPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); + return activationFuture; + + default: + break; + } + + AWS_FATAL_ASSERT(m_sharedState.m_currentState == ContinuationStateType::None); + + // cleanup requirements mean we can't early out from here on + s_fillNativeHeadersArray(headers, &headersArray, m_allocator); + + struct aws_event_stream_rpc_message_args msg_args; + msg_args.headers = static_cast(headersArray.data); + msg_args.headers_count = headers.size(); + msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; + msg_args.message_type = messageType; + msg_args.message_flags = messageFlags; + + m_sharedState.m_activationCallbackContainer = Crt::New( + m_allocator, m_allocator, std::move(onMessageFlushCallback), std::move(activationPromise)); + m_sharedState.m_activationResponseCallback = std::move(onResultCallback); + + result = aws_event_stream_rpc_client_continuation_activate( + m_sharedState.m_continuation, + Crt::ByteCursorFromCString(operation.c_str()), + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(m_sharedState.m_activationCallbackContainer)); + + if (result != AWS_OP_SUCCESS) + { + activationFailureContainer = m_sharedState.m_activationCallbackContainer; + m_sharedState.m_activationCallbackContainer = nullptr; + m_sharedState.m_activationResponseCallback = std::function(); + } + else + { + m_sharedState.m_currentState = ContinuationStateType::PendingActivate; + m_sharedState.m_desiredState = ContinuationStateType::Activated; + synchronousSuccess = true; + } + } + + if (activationFailureContainer) + { + OnMessageFlushCallbackContainer::Complete( + activationFailureContainer, {EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}); + OnMessageFlushCallbackContainer::Release(activationFailureContainer); + OnMessageFlushCallbackContainer::Release(activationFailureContainer); + } + + if (aws_array_list_is_valid(&headersArray)) + { + aws_array_list_clean_up(&headersArray); + } + + return activationFuture; + } + + // Intentionally returns an error code and not AWS_OP_ERR/AWS_OP_SUCCESS + // shared state lock must be held before calling + int ClientContinuationImpl::SendCloseMessage( + OnMessageFlushCallback &&closeFlushCallback, + std::promise &&closeFlushPromise) noexcept + { + int errorCode = AWS_ERROR_SUCCESS; + + struct aws_event_stream_rpc_message_args msg_args; + msg_args.headers = nullptr; + msg_args.headers_count = 0; + msg_args.payload = nullptr; + msg_args.message_type = AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE; + msg_args.message_flags = AWS_EVENT_STREAM_RPC_MESSAGE_FLAG_TERMINATE_STREAM; + + m_sharedState.m_closeCallbackContainer = Crt::New( + m_allocator, m_allocator, std::move(closeFlushCallback), std::move(closeFlushPromise)); + + int result = aws_event_stream_rpc_client_continuation_send_message( + m_sharedState.m_continuation, + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(m_sharedState.m_closeCallbackContainer)); + + if (result) + { + errorCode = aws_last_error(); + AWS_LOGF_ERROR( + AWS_LS_EVENT_STREAM_RPC_CLIENT, + "A CRT error occurred while closing the stream: %s", + Crt::ErrorDebugString(errorCode)); + } + + return errorCode; + } + + std::future ClientContinuationImpl::Close(OnMessageFlushCallback &&onMessageFlushCallback) noexcept + { + int closeErrorCode = AWS_ERROR_SUCCESS; + OnMessageFlushCallbackContainer *closeFailureCallbackContainer = nullptr; + std::promise closePromise; + std::future closeFuture = closePromise.get_future(); + { + std::lock_guard lock(m_sharedStateLock); + if (m_sharedState.m_continuation == nullptr) + { + closePromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); + return closeFuture; + } + + switch (m_sharedState.m_currentState) + { + case ContinuationStateType::PendingActivate: + case ContinuationStateType::Activated: + { + closeErrorCode = SendCloseMessage(std::move(onMessageFlushCallback), std::move(closePromise)); + if (closeErrorCode != AWS_ERROR_SUCCESS) + { + closeFailureCallbackContainer = m_sharedState.m_closeCallbackContainer; + m_sharedState.m_closeCallbackContainer = nullptr; + } + else + { + m_sharedState.m_currentState = ContinuationStateType::PendingClose; + } + break; + } + + case ContinuationStateType::PendingClose: + closePromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS, 0}); + return closeFuture; + + default: + closePromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); + return closeFuture; + } + } + + if (closeFailureCallbackContainer != nullptr) + { + OnMessageFlushCallbackContainer::Complete( + closeFailureCallbackContainer, {EVENT_STREAM_RPC_CRT_ERROR, closeErrorCode}); + OnMessageFlushCallbackContainer::Release(closeFailureCallbackContainer); + OnMessageFlushCallbackContainer::Release(closeFailureCallbackContainer); + } + + return closeFuture; + } + + void ClientContinuationImpl::OnClosed() noexcept + { + struct aws_event_stream_rpc_client_continuation_token *releaseContinuation = nullptr; + OnMessageFlushCallbackContainer *closeCallbackContainer = nullptr; + OnMessageFlushCallbackContainer *activationCallbackContainer = nullptr; + std::function activationResponseCallback; + + { + std::lock_guard lock(m_sharedStateLock); + + m_sharedState.m_currentState = ContinuationStateType::Closed; + m_sharedState.m_desiredState = ContinuationStateType::Closed; + releaseContinuation = m_sharedState.m_continuation; + m_sharedState.m_continuation = nullptr; + + activationCallbackContainer = m_sharedState.m_activationCallbackContainer; + m_sharedState.m_activationCallbackContainer = nullptr; + + closeCallbackContainer = m_sharedState.m_closeCallbackContainer; + m_sharedState.m_closeCallbackContainer = nullptr; + + activationResponseCallback = std::move(m_sharedState.m_activationResponseCallback); + m_sharedState.m_activationResponseCallback = nullptr; + } + + if (activationResponseCallback) + { + activationResponseCallback( + TaggedResult(RpcError{EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS})); + } + + OnMessageFlushCallbackContainer::Complete( + activationCallbackContainer, {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); + OnMessageFlushCallbackContainer::Release(activationCallbackContainer); + + OnMessageFlushCallbackContainer::Complete( + closeCallbackContainer, {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); + OnMessageFlushCallbackContainer::Release(closeCallbackContainer); + + ReleaseContinuation(m_allocator, m_clientBootstrap, releaseContinuation); + } + + MessageResult ClientContinuationImpl::DeserializeRawMessage( + const struct aws_event_stream_rpc_message_args *rawMessage, + bool shouldBeActivationResponse) noexcept + { + MessageResult result; + + Crt::List continuationMessageHeaders; + for (size_t i = 0; i < rawMessage->headers_count; ++i) + { + continuationMessageHeaders.emplace_back(EventStreamHeader(rawMessage->headers[i], m_allocator)); + } + + Crt::Optional payload; + if (rawMessage->payload) + { + payload = Crt::Optional(*rawMessage->payload); + } + else + { + payload = Crt::Optional(); + } + + const EventStreamHeader *modelHeader = + s_GetHeaderByName(continuationMessageHeaders, Crt::String(SERVICE_MODEL_TYPE_HEADER)); + if (modelHeader == nullptr) + { + AWS_LOGF_ERROR( + AWS_LS_EVENT_STREAM_RPC_CLIENT, + "A required header (%s) could not be found in the message.", + SERVICE_MODEL_TYPE_HEADER); + result.m_statusCode = EVENT_STREAM_RPC_UNMAPPED_DATA; + return result; + } + + Crt::String modelName; + modelHeader->GetValueAsString(modelName); + if (rawMessage->message_type == AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE) + { + if (shouldBeActivationResponse) + { + if (m_operationModelContext->GetInitialResponseModelName() != modelName) + { + AWS_LOGF_ERROR( + AWS_LS_EVENT_STREAM_RPC_CLIENT, + "The model name of the initial response did not match its expected model name."); + result.m_statusCode = EVENT_STREAM_RPC_UNMAPPED_DATA; + return result; + } + } + else + { + if (m_operationModelContext->GetStreamingResponseModelName().has_value() && + m_operationModelContext->GetStreamingResponseModelName().value() != modelName) + { + AWS_LOGF_ERROR( + AWS_LS_EVENT_STREAM_RPC_CLIENT, + "The model name of a subsequent response did not match its expected model name."); + result.m_statusCode = EVENT_STREAM_RPC_UNMAPPED_DATA; + return result; + } + } + } + + const EventStreamHeader *contentHeader = + s_GetHeaderByName(continuationMessageHeaders, Crt::String(CONTENT_TYPE_HEADER)); + if (contentHeader == nullptr) + { + AWS_LOGF_ERROR( + AWS_LS_EVENT_STREAM_RPC_CLIENT, + "A required header (%s) could not be found in the message.", + CONTENT_TYPE_HEADER); + result.m_statusCode = EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE; + return result; + } + + Crt::String contentType; + if (contentHeader->GetValueAsString(contentType) && contentType != CONTENT_TYPE_APPLICATION_JSON) + { + /* Missing required content type header. */ + AWS_LOGF_ERROR( + AWS_LS_EVENT_STREAM_RPC_CLIENT, + "The content type (%s) header was specified with an unsupported value (%s).", + CONTENT_TYPE_HEADER, + contentType.c_str()); + result.m_statusCode = EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE; + return result; + } + + Crt::StringView payloadStringView; + if (payload.has_value()) + { + payloadStringView = Crt::ByteCursorToStringView(Crt::ByteCursorFromByteBuf(payload.value())); + } + + if (rawMessage->message_type == AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE) + { + if (shouldBeActivationResponse) + { + result.m_message = MessageDeserialization{ + EventStreamMessageRoutingType::Response, + m_operationModelContext->AllocateInitialResponseFromPayload(payloadStringView, m_allocator)}; + } + else + { + result.m_message = MessageDeserialization{ + EventStreamMessageRoutingType::Stream, + m_operationModelContext->AllocateStreamingResponseFromPayload(payloadStringView, m_allocator)}; + } + } + else + { + auto errorShape = m_operationModelContext + ->AllocateOperationErrorFromPayload(modelName, payloadStringView, m_allocator) + .release(); + Crt::Allocator *allocator = m_allocator; + result.m_message = MessageDeserialization{ + EventStreamMessageRoutingType::Error, + Crt::ScopedResource( + errorShape, [allocator](AbstractShapeBase *shape) { Crt::Delete(shape, allocator); })}; + } + + if (result.m_message.value().m_shape.get() == nullptr) + { + result.m_statusCode = EVENT_STREAM_RPC_UNMAPPED_DATA; + } + + return result; + } + + void ClientContinuationImpl::OnMessage(const struct aws_event_stream_rpc_message_args *messageArgs) noexcept + { + std::function activationResultCallback; + + MessageResult result; + bool isResponse = false; + { + std::lock_guard lock(m_sharedStateLock); + isResponse = static_cast(m_sharedState.m_currentState == ContinuationStateType::PendingActivate); + if (isResponse) + { + activationResultCallback = std::move(m_sharedState.m_activationResponseCallback); + m_sharedState.m_activationResponseCallback = nullptr; + m_sharedState.m_currentState = ContinuationStateType::Activated; + } + } + + result = DeserializeRawMessage(messageArgs, isResponse); + + if (activationResultCallback) + { + if (result.m_statusCode == EVENT_STREAM_RPC_SUCCESS) + { + activationResultCallback(TaggedResult(std::move(result.m_message.value().m_shape))); + } + else + { + activationResultCallback(TaggedResult(RpcError{result.m_statusCode, 0})); + } + } + else if (!isResponse) + { + if (result.m_message.has_value()) + { + AWS_FATAL_ASSERT(result.m_message.value().m_route == EventStreamMessageRoutingType::Stream); + auto shape = std::move(result.m_message.value().m_shape); + m_streamHandler->OnStreamEvent(std::move(shape)); + } + else + { + bool shouldClose = m_streamHandler->OnStreamError(nullptr, {result.m_statusCode, 0}); + if (shouldClose) + { + Close(); + } + } + } + } + + void ClientContinuationImpl::s_OnContinuationClosed( + struct aws_event_stream_rpc_client_continuation_token *token, + void *user_data) noexcept + { + auto impl = reinterpret_cast(user_data); + impl->OnClosed(); + } + + void ClientContinuationImpl::s_OnContinuationMessage( + struct aws_event_stream_rpc_client_continuation_token *token, + const struct aws_event_stream_rpc_message_args *message_args, + void *user_data) noexcept + { + auto impl = reinterpret_cast(user_data); + impl->OnMessage(message_args); + } + + void ClientContinuationImpl::s_OnContinuationTerminated(void *user_data) noexcept + { + auto impl = reinterpret_cast(user_data); + + // We don't need to put this on an event loop task since we release the continuation on an event loop task + impl->m_selfReference = nullptr; + } + + Crt::String ClientContinuationImpl::GetModelName() const noexcept + { + return m_operationModelContext->GetOperationName(); + } + + std::shared_ptr ClientConnectionImpl::NewStream() noexcept + { + std::lock_guard lock(m_sharedStateLock); + return Aws::Crt::MakeShared( + m_allocator, m_allocator, m_sharedState.m_underlyingConnection); } } /* namespace Eventstreamrpc */ diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index 84a993f0a..08dedfecb 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -43,15 +43,15 @@ add_test_case(EchoClientCloseWhileConnecting) add_test_case(EchoClientConnectWhileClosing) add_test_case(EchoClientOpenCloseStress) -#add_test_case(EchoClientOperationEchoSuccessString) -#add_test_case(EchoClientOperationEchoSuccessBoolean) -#add_test_case(EchoClientOperationEchoSuccessTime) -#add_test_case(EchoClientOperationEchoSuccessDocument) -#add_test_case(EchoClientOperationEchoSuccessEnum) -#add_test_case(EchoClientOperationEchoSuccessBlob) -#add_test_case(EchoClientOperationEchoSuccessStringList) -#add_test_case(EchoClientOperationEchoSuccessPairList) -#add_test_case(EchoClientOperationEchoSuccessProductMap) +add_test_case(EchoClientOperationEchoSuccessString) +add_test_case(EchoClientOperationEchoSuccessBoolean) +add_test_case(EchoClientOperationEchoSuccessTime) +add_test_case(EchoClientOperationEchoSuccessDocument) +add_test_case(EchoClientOperationEchoSuccessEnum) +add_test_case(EchoClientOperationEchoSuccessBlob) +add_test_case(EchoClientOperationEchoSuccessStringList) +add_test_case(EchoClientOperationEchoSuccessPairList) +add_test_case(EchoClientOperationEchoSuccessProductMap) #add_test_case(EchoClientOperationEchoSuccessMultiple) #add_test_case(EchoClientOperationEchoFailureNeverConnected) diff --git a/eventstream_rpc/tests/EchoTestRpcModel.cpp b/eventstream_rpc/tests/EchoTestRpcModel.cpp index 3220f85a0..059554ed2 100644 --- a/eventstream_rpc/tests/EchoTestRpcModel.cpp +++ b/eventstream_rpc/tests/EchoTestRpcModel.cpp @@ -1018,7 +1018,7 @@ namespace Awstest std::future GetAllProductsOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { return GetAllProductsResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } GetAllProductsOperation::GetAllProductsOperation( @@ -1033,12 +1033,22 @@ namespace Awstest const GetAllProductsRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String GetAllProductsOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(GetAllProductsResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } CauseServiceErrorOperationContext::CauseServiceErrorOperationContext( @@ -1086,7 +1096,7 @@ namespace Awstest std::future CauseServiceErrorOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { return CauseServiceErrorResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } CauseServiceErrorOperation::CauseServiceErrorOperation( @@ -1101,12 +1111,22 @@ namespace Awstest const CauseServiceErrorRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String CauseServiceErrorOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(CauseServiceErrorResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } void CauseStreamServiceToErrorStreamHandler::OnStreamEvent(Aws::Crt::ScopedResource response) @@ -1176,8 +1196,7 @@ namespace Awstest std::future CauseStreamServiceToErrorOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return CauseStreamServiceToErrorResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } CauseStreamServiceToErrorOperation::CauseStreamServiceToErrorOperation( @@ -1193,12 +1212,22 @@ namespace Awstest const EchoStreamingRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String CauseStreamServiceToErrorOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(CauseStreamServiceToErrorResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } void EchoStreamMessagesStreamHandler::OnStreamEvent(Aws::Crt::ScopedResource response) @@ -1263,7 +1292,7 @@ namespace Awstest std::future EchoStreamMessagesOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { return EchoStreamMessagesResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } EchoStreamMessagesOperation::EchoStreamMessagesOperation( @@ -1279,12 +1308,22 @@ namespace Awstest const EchoStreamingRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String EchoStreamMessagesOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(EchoStreamMessagesResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } EchoMessageOperationContext::EchoMessageOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept @@ -1330,7 +1369,7 @@ namespace Awstest std::future EchoMessageOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { return EchoMessageResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } EchoMessageOperation::EchoMessageOperation( @@ -1345,12 +1384,22 @@ namespace Awstest const EchoMessageRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String EchoMessageOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(EchoMessageResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } GetAllCustomersOperationContext::GetAllCustomersOperationContext( @@ -1397,7 +1446,7 @@ namespace Awstest std::future GetAllCustomersOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { return GetAllCustomersResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } GetAllCustomersOperation::GetAllCustomersOperation( @@ -1412,12 +1461,22 @@ namespace Awstest const GetAllCustomersRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String GetAllCustomersOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(GetAllCustomersResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } EchoTestRpcServiceModel::EchoTestRpcServiceModel() noexcept diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index ff057a56b..a49fd1332 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -479,8 +479,6 @@ static int s_TestEchoClientOpenCloseStress(struct aws_allocator *allocator, void AWS_TEST_CASE(EchoClientOpenCloseStress, s_TestEchoClientOpenCloseStress); -#ifdef NEVER - static void s_onMessageFlush(int errorCode) { (void)errorCode; @@ -778,6 +776,8 @@ static int s_TestEchoClientOperationEchoSuccessProductMap(struct aws_allocator * AWS_TEST_CASE(EchoClientOperationEchoSuccessProductMap, s_TestEchoClientOperationEchoSuccessProductMap); +#ifdef NEVER + static int s_TestEchoClientOperationEchoSuccessMultiple(struct aws_allocator *allocator, void *ctx) { ApiHandle apiHandle(allocator); diff --git a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h index ea644a271..a9cf8de9f 100644 --- a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h +++ b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h @@ -704,6 +704,7 @@ namespace Awstest { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -717,13 +718,15 @@ namespace Awstest TaggedResult m_taggedResult; }; - class AWS_ECHOTESTRPC_API GetAllProductsOperation : public ClientOperation + class AWS_ECHOTESTRPC_API GetAllProductsOperation : public ClientOperation, + public std::enable_shared_from_this { public: GetAllProductsOperation( ClientConnection &connection, const GetAllProductsOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `GetAllProductsOperation` * @param request The request used for the `GetAllProductsOperation` @@ -733,13 +736,19 @@ namespace Awstest std::future Activate( const GetAllProductsRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_ECHOTESTRPC_API CauseServiceErrorOperationContext : public OperationModelContext @@ -767,6 +776,7 @@ namespace Awstest { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -780,13 +790,16 @@ namespace Awstest TaggedResult m_taggedResult; }; - class AWS_ECHOTESTRPC_API CauseServiceErrorOperation : public ClientOperation + class AWS_ECHOTESTRPC_API CauseServiceErrorOperation + : public ClientOperation, + public std::enable_shared_from_this { public: CauseServiceErrorOperation( ClientConnection &connection, const CauseServiceErrorOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `CauseServiceErrorOperation` * @param request The request used for the `CauseServiceErrorOperation` @@ -796,13 +809,19 @@ namespace Awstest std::future Activate( const CauseServiceErrorRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_ECHOTESTRPC_API CauseStreamServiceToErrorStreamHandler : public StreamResponseHandler @@ -845,6 +864,7 @@ namespace Awstest * Invoked when a message is received on this continuation. */ void OnStreamEvent(Aws::Crt::ScopedResource response) override; + /** * Invoked when a message is received on this continuation but results in an error. * @@ -852,6 +872,7 @@ namespace Awstest */ bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; + class AWS_ECHOTESTRPC_API CauseStreamServiceToErrorOperationContext : public OperationModelContext { public: @@ -879,6 +900,7 @@ namespace Awstest { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -892,7 +914,9 @@ namespace Awstest TaggedResult m_taggedResult; }; - class AWS_ECHOTESTRPC_API CauseStreamServiceToErrorOperation : public ClientOperation + class AWS_ECHOTESTRPC_API CauseStreamServiceToErrorOperation + : public ClientOperation, + public std::enable_shared_from_this { public: CauseStreamServiceToErrorOperation( @@ -900,6 +924,7 @@ namespace Awstest std::shared_ptr streamHandler, const CauseStreamServiceToErrorOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `CauseStreamServiceToErrorOperation` * @param request The request used for the `CauseStreamServiceToErrorOperation` @@ -909,13 +934,19 @@ namespace Awstest std::future Activate( const EchoStreamingRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_ECHOTESTRPC_API EchoStreamMessagesStreamHandler : public StreamResponseHandler @@ -948,6 +979,7 @@ namespace Awstest * Invoked when a message is received on this continuation. */ void OnStreamEvent(Aws::Crt::ScopedResource response) override; + /** * Invoked when a message is received on this continuation but results in an error. * @@ -955,6 +987,7 @@ namespace Awstest */ bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; + class AWS_ECHOTESTRPC_API EchoStreamMessagesOperationContext : public OperationModelContext { public: @@ -980,6 +1013,7 @@ namespace Awstest { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -993,7 +1027,9 @@ namespace Awstest TaggedResult m_taggedResult; }; - class AWS_ECHOTESTRPC_API EchoStreamMessagesOperation : public ClientOperation + class AWS_ECHOTESTRPC_API EchoStreamMessagesOperation + : public ClientOperation, + public std::enable_shared_from_this { public: EchoStreamMessagesOperation( @@ -1001,6 +1037,7 @@ namespace Awstest std::shared_ptr streamHandler, const EchoStreamMessagesOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `EchoStreamMessagesOperation` * @param request The request used for the `EchoStreamMessagesOperation` @@ -1010,13 +1047,19 @@ namespace Awstest std::future Activate( const EchoStreamingRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_ECHOTESTRPC_API EchoMessageOperationContext : public OperationModelContext @@ -1044,6 +1087,7 @@ namespace Awstest { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -1057,13 +1101,15 @@ namespace Awstest TaggedResult m_taggedResult; }; - class AWS_ECHOTESTRPC_API EchoMessageOperation : public ClientOperation + class AWS_ECHOTESTRPC_API EchoMessageOperation : public ClientOperation, + public std::enable_shared_from_this { public: EchoMessageOperation( ClientConnection &connection, const EchoMessageOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `EchoMessageOperation` * @param request The request used for the `EchoMessageOperation` @@ -1073,13 +1119,19 @@ namespace Awstest std::future Activate( const EchoMessageRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_ECHOTESTRPC_API GetAllCustomersOperationContext : public OperationModelContext @@ -1107,6 +1159,7 @@ namespace Awstest { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -1120,13 +1173,15 @@ namespace Awstest TaggedResult m_taggedResult; }; - class AWS_ECHOTESTRPC_API GetAllCustomersOperation : public ClientOperation + class AWS_ECHOTESTRPC_API GetAllCustomersOperation : public ClientOperation, + public std::enable_shared_from_this { public: GetAllCustomersOperation( ClientConnection &connection, const GetAllCustomersOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `GetAllCustomersOperation` * @param request The request used for the `GetAllCustomersOperation` @@ -1136,13 +1191,19 @@ namespace Awstest std::future Activate( const GetAllCustomersRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_ECHOTESTRPC_API EchoTestRpcServiceModel : public ServiceModel diff --git a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h index 5884b7172..c569872ce 100644 --- a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h +++ b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h @@ -4469,6 +4469,7 @@ namespace Aws * Invoked when a message is received on this continuation. */ void OnStreamEvent(Aws::Crt::ScopedResource response) override; + /** * Invoked when a message is received on this continuation but results in an error. * @@ -4476,6 +4477,7 @@ namespace Aws */ bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; + class AWS_GREENGRASSCOREIPC_API SubscribeToIoTCoreOperationContext : public OperationModelContext { public: @@ -4501,6 +4503,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -4514,7 +4517,9 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToIoTCoreOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API SubscribeToIoTCoreOperation + : public ClientOperation, + public std::enable_shared_from_this { public: SubscribeToIoTCoreOperation( @@ -4522,6 +4527,7 @@ namespace Aws std::shared_ptr streamHandler, const SubscribeToIoTCoreOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `SubscribeToIoTCoreOperation` * @param request The request used for the `SubscribeToIoTCoreOperation` @@ -4531,13 +4537,19 @@ namespace Aws std::future Activate( const SubscribeToIoTCoreRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API ResumeComponentOperationContext : public OperationModelContext @@ -4565,6 +4577,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -4578,13 +4591,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API ResumeComponentOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API ResumeComponentOperation + : public ClientOperation, + public std::enable_shared_from_this { public: ResumeComponentOperation( ClientConnection &connection, const ResumeComponentOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `ResumeComponentOperation` * @param request The request used for the `ResumeComponentOperation` @@ -4594,13 +4610,19 @@ namespace Aws std::future Activate( const ResumeComponentRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API PublishToIoTCoreOperationContext : public OperationModelContext @@ -4628,6 +4650,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -4641,13 +4664,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API PublishToIoTCoreOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API PublishToIoTCoreOperation + : public ClientOperation, + public std::enable_shared_from_this { public: PublishToIoTCoreOperation( ClientConnection &connection, const PublishToIoTCoreOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `PublishToIoTCoreOperation` * @param request The request used for the `PublishToIoTCoreOperation` @@ -4657,13 +4683,19 @@ namespace Aws std::future Activate( const PublishToIoTCoreRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API SubscribeToConfigurationUpdateStreamHandler : public StreamResponseHandler @@ -4716,6 +4748,7 @@ namespace Aws * Invoked when a message is received on this continuation. */ void OnStreamEvent(Aws::Crt::ScopedResource response) override; + /** * Invoked when a message is received on this continuation but results in an error. * @@ -4723,6 +4756,7 @@ namespace Aws */ bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; + class AWS_GREENGRASSCOREIPC_API SubscribeToConfigurationUpdateOperationContext : public OperationModelContext { public: @@ -4751,6 +4785,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -4764,7 +4799,9 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToConfigurationUpdateOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API SubscribeToConfigurationUpdateOperation + : public ClientOperation, + public std::enable_shared_from_this { public: SubscribeToConfigurationUpdateOperation( @@ -4772,6 +4809,7 @@ namespace Aws std::shared_ptr streamHandler, const SubscribeToConfigurationUpdateOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `SubscribeToConfigurationUpdateOperation` * @param request The request used for the `SubscribeToConfigurationUpdateOperation` @@ -4781,13 +4819,19 @@ namespace Aws std::future Activate( const SubscribeToConfigurationUpdateRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API DeleteThingShadowOperationContext : public OperationModelContext @@ -4815,6 +4859,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -4828,13 +4873,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API DeleteThingShadowOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API DeleteThingShadowOperation + : public ClientOperation, + public std::enable_shared_from_this { public: DeleteThingShadowOperation( ClientConnection &connection, const DeleteThingShadowOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `DeleteThingShadowOperation` * @param request The request used for the `DeleteThingShadowOperation` @@ -4844,13 +4892,19 @@ namespace Aws std::future Activate( const DeleteThingShadowRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API PutComponentMetricOperationContext : public OperationModelContext @@ -4878,6 +4932,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -4891,13 +4946,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API PutComponentMetricOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API PutComponentMetricOperation + : public ClientOperation, + public std::enable_shared_from_this { public: PutComponentMetricOperation( ClientConnection &connection, const PutComponentMetricOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `PutComponentMetricOperation` * @param request The request used for the `PutComponentMetricOperation` @@ -4907,13 +4965,19 @@ namespace Aws std::future Activate( const PutComponentMetricRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API DeferComponentUpdateOperationContext : public OperationModelContext @@ -4943,6 +5007,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -4956,13 +5021,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API DeferComponentUpdateOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API DeferComponentUpdateOperation + : public ClientOperation, + public std::enable_shared_from_this { public: DeferComponentUpdateOperation( ClientConnection &connection, const DeferComponentUpdateOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `DeferComponentUpdateOperation` * @param request The request used for the `DeferComponentUpdateOperation` @@ -4972,13 +5040,19 @@ namespace Aws std::future Activate( const DeferComponentUpdateRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API SubscribeToValidateConfigurationUpdatesStreamHandler @@ -5022,6 +5096,7 @@ namespace Aws * Invoked when a message is received on this continuation. */ void OnStreamEvent(Aws::Crt::ScopedResource response) override; + /** * Invoked when a message is received on this continuation but results in an error. * @@ -5029,6 +5104,7 @@ namespace Aws */ bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; + class AWS_GREENGRASSCOREIPC_API SubscribeToValidateConfigurationUpdatesOperationContext : public OperationModelContext { @@ -5060,6 +5136,7 @@ namespace Aws return static_cast( m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -5073,7 +5150,9 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToValidateConfigurationUpdatesOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API SubscribeToValidateConfigurationUpdatesOperation + : public ClientOperation, + public std::enable_shared_from_this { public: SubscribeToValidateConfigurationUpdatesOperation( @@ -5081,6 +5160,7 @@ namespace Aws std::shared_ptr streamHandler, const SubscribeToValidateConfigurationUpdatesOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `SubscribeToValidateConfigurationUpdatesOperation` * @param request The request used for the `SubscribeToValidateConfigurationUpdatesOperation` @@ -5090,13 +5170,19 @@ namespace Aws std::future Activate( const SubscribeToValidateConfigurationUpdatesRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API GetConfigurationOperationContext : public OperationModelContext @@ -5124,6 +5210,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -5137,13 +5224,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API GetConfigurationOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API GetConfigurationOperation + : public ClientOperation, + public std::enable_shared_from_this { public: GetConfigurationOperation( ClientConnection &connection, const GetConfigurationOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `GetConfigurationOperation` * @param request The request used for the `GetConfigurationOperation` @@ -5153,13 +5243,19 @@ namespace Aws std::future Activate( const GetConfigurationRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API SubscribeToTopicStreamHandler : public StreamResponseHandler @@ -5222,6 +5318,7 @@ namespace Aws * Invoked when a message is received on this continuation. */ void OnStreamEvent(Aws::Crt::ScopedResource response) override; + /** * Invoked when a message is received on this continuation but results in an error. * @@ -5229,6 +5326,7 @@ namespace Aws */ bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; + class AWS_GREENGRASSCOREIPC_API SubscribeToTopicOperationContext : public OperationModelContext { public: @@ -5254,6 +5352,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -5267,7 +5366,9 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToTopicOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API SubscribeToTopicOperation + : public ClientOperation, + public std::enable_shared_from_this { public: SubscribeToTopicOperation( @@ -5275,6 +5376,7 @@ namespace Aws std::shared_ptr streamHandler, const SubscribeToTopicOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `SubscribeToTopicOperation` * @param request The request used for the `SubscribeToTopicOperation` @@ -5284,13 +5386,19 @@ namespace Aws std::future Activate( const SubscribeToTopicRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API GetComponentDetailsOperationContext : public OperationModelContext @@ -5318,6 +5426,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -5331,13 +5440,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API GetComponentDetailsOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API GetComponentDetailsOperation + : public ClientOperation, + public std::enable_shared_from_this { public: GetComponentDetailsOperation( ClientConnection &connection, const GetComponentDetailsOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `GetComponentDetailsOperation` * @param request The request used for the `GetComponentDetailsOperation` @@ -5347,13 +5459,19 @@ namespace Aws std::future Activate( const GetComponentDetailsRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API GetClientDeviceAuthTokenOperationContext : public OperationModelContext @@ -5384,6 +5502,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -5397,13 +5516,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API GetClientDeviceAuthTokenOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API GetClientDeviceAuthTokenOperation + : public ClientOperation, + public std::enable_shared_from_this { public: GetClientDeviceAuthTokenOperation( ClientConnection &connection, const GetClientDeviceAuthTokenOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `GetClientDeviceAuthTokenOperation` * @param request The request used for the `GetClientDeviceAuthTokenOperation` @@ -5413,13 +5535,19 @@ namespace Aws std::future Activate( const GetClientDeviceAuthTokenRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API PublishToTopicOperationContext : public OperationModelContext @@ -5447,6 +5575,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -5460,13 +5589,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API PublishToTopicOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API PublishToTopicOperation + : public ClientOperation, + public std::enable_shared_from_this { public: PublishToTopicOperation( ClientConnection &connection, const PublishToTopicOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `PublishToTopicOperation` * @param request The request used for the `PublishToTopicOperation` @@ -5476,13 +5608,19 @@ namespace Aws std::future Activate( const PublishToTopicRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API SubscribeToCertificateUpdatesStreamHandler : public StreamResponseHandler @@ -5545,6 +5683,7 @@ namespace Aws * Invoked when a message is received on this continuation. */ void OnStreamEvent(Aws::Crt::ScopedResource response) override; + /** * Invoked when a message is received on this continuation but results in an error. * @@ -5552,6 +5691,7 @@ namespace Aws */ bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; + class AWS_GREENGRASSCOREIPC_API SubscribeToCertificateUpdatesOperationContext : public OperationModelContext { public: @@ -5580,6 +5720,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -5593,7 +5734,9 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToCertificateUpdatesOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API SubscribeToCertificateUpdatesOperation + : public ClientOperation, + public std::enable_shared_from_this { public: SubscribeToCertificateUpdatesOperation( @@ -5601,6 +5744,7 @@ namespace Aws std::shared_ptr streamHandler, const SubscribeToCertificateUpdatesOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `SubscribeToCertificateUpdatesOperation` * @param request The request used for the `SubscribeToCertificateUpdatesOperation` @@ -5610,13 +5754,19 @@ namespace Aws std::future Activate( const SubscribeToCertificateUpdatesRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API VerifyClientDeviceIdentityOperationContext : public OperationModelContext @@ -5647,6 +5797,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -5660,13 +5811,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API VerifyClientDeviceIdentityOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API VerifyClientDeviceIdentityOperation + : public ClientOperation, + public std::enable_shared_from_this { public: VerifyClientDeviceIdentityOperation( ClientConnection &connection, const VerifyClientDeviceIdentityOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `VerifyClientDeviceIdentityOperation` * @param request The request used for the `VerifyClientDeviceIdentityOperation` @@ -5676,13 +5830,19 @@ namespace Aws std::future Activate( const VerifyClientDeviceIdentityRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API AuthorizeClientDeviceActionOperationContext : public OperationModelContext @@ -5713,6 +5873,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -5726,13 +5887,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API AuthorizeClientDeviceActionOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API AuthorizeClientDeviceActionOperation + : public ClientOperation, + public std::enable_shared_from_this { public: AuthorizeClientDeviceActionOperation( ClientConnection &connection, const AuthorizeClientDeviceActionOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `AuthorizeClientDeviceActionOperation` * @param request The request used for the `AuthorizeClientDeviceActionOperation` @@ -5742,13 +5906,19 @@ namespace Aws std::future Activate( const AuthorizeClientDeviceActionRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API ListComponentsOperationContext : public OperationModelContext @@ -5776,6 +5946,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -5789,13 +5960,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API ListComponentsOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API ListComponentsOperation + : public ClientOperation, + public std::enable_shared_from_this { public: ListComponentsOperation( ClientConnection &connection, const ListComponentsOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `ListComponentsOperation` * @param request The request used for the `ListComponentsOperation` @@ -5805,13 +5979,19 @@ namespace Aws std::future Activate( const ListComponentsRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API CreateDebugPasswordOperationContext : public OperationModelContext @@ -5839,6 +6019,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -5852,13 +6033,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API CreateDebugPasswordOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API CreateDebugPasswordOperation + : public ClientOperation, + public std::enable_shared_from_this { public: CreateDebugPasswordOperation( ClientConnection &connection, const CreateDebugPasswordOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `CreateDebugPasswordOperation` * @param request The request used for the `CreateDebugPasswordOperation` @@ -5868,13 +6052,19 @@ namespace Aws std::future Activate( const CreateDebugPasswordRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API GetThingShadowOperationContext : public OperationModelContext @@ -5902,6 +6092,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -5915,13 +6106,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API GetThingShadowOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API GetThingShadowOperation + : public ClientOperation, + public std::enable_shared_from_this { public: GetThingShadowOperation( ClientConnection &connection, const GetThingShadowOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `GetThingShadowOperation` * @param request The request used for the `GetThingShadowOperation` @@ -5931,13 +6125,19 @@ namespace Aws std::future Activate( const GetThingShadowRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API SendConfigurationValidityReportOperationContext : public OperationModelContext @@ -5968,6 +6168,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -5981,13 +6182,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SendConfigurationValidityReportOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API SendConfigurationValidityReportOperation + : public ClientOperation, + public std::enable_shared_from_this { public: SendConfigurationValidityReportOperation( ClientConnection &connection, const SendConfigurationValidityReportOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `SendConfigurationValidityReportOperation` * @param request The request used for the `SendConfigurationValidityReportOperation` @@ -5997,13 +6201,19 @@ namespace Aws std::future Activate( const SendConfigurationValidityReportRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API UpdateThingShadowOperationContext : public OperationModelContext @@ -6031,6 +6241,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6044,13 +6255,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API UpdateThingShadowOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API UpdateThingShadowOperation + : public ClientOperation, + public std::enable_shared_from_this { public: UpdateThingShadowOperation( ClientConnection &connection, const UpdateThingShadowOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `UpdateThingShadowOperation` * @param request The request used for the `UpdateThingShadowOperation` @@ -6060,13 +6274,19 @@ namespace Aws std::future Activate( const UpdateThingShadowRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API UpdateConfigurationOperationContext : public OperationModelContext @@ -6094,6 +6314,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6107,13 +6328,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API UpdateConfigurationOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API UpdateConfigurationOperation + : public ClientOperation, + public std::enable_shared_from_this { public: UpdateConfigurationOperation( ClientConnection &connection, const UpdateConfigurationOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `UpdateConfigurationOperation` * @param request The request used for the `UpdateConfigurationOperation` @@ -6123,13 +6347,19 @@ namespace Aws std::future Activate( const UpdateConfigurationRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API ValidateAuthorizationTokenOperationContext : public OperationModelContext @@ -6160,6 +6390,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6173,13 +6404,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API ValidateAuthorizationTokenOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API ValidateAuthorizationTokenOperation + : public ClientOperation, + public std::enable_shared_from_this { public: ValidateAuthorizationTokenOperation( ClientConnection &connection, const ValidateAuthorizationTokenOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `ValidateAuthorizationTokenOperation` * @param request The request used for the `ValidateAuthorizationTokenOperation` @@ -6189,13 +6423,19 @@ namespace Aws std::future Activate( const ValidateAuthorizationTokenRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API RestartComponentOperationContext : public OperationModelContext @@ -6223,6 +6463,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6236,13 +6477,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API RestartComponentOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API RestartComponentOperation + : public ClientOperation, + public std::enable_shared_from_this { public: RestartComponentOperation( ClientConnection &connection, const RestartComponentOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `RestartComponentOperation` * @param request The request used for the `RestartComponentOperation` @@ -6252,13 +6496,19 @@ namespace Aws std::future Activate( const RestartComponentRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API GetLocalDeploymentStatusOperationContext : public OperationModelContext @@ -6289,6 +6539,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6302,13 +6553,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API GetLocalDeploymentStatusOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API GetLocalDeploymentStatusOperation + : public ClientOperation, + public std::enable_shared_from_this { public: GetLocalDeploymentStatusOperation( ClientConnection &connection, const GetLocalDeploymentStatusOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `GetLocalDeploymentStatusOperation` * @param request The request used for the `GetLocalDeploymentStatusOperation` @@ -6318,13 +6572,19 @@ namespace Aws std::future Activate( const GetLocalDeploymentStatusRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API GetSecretValueOperationContext : public OperationModelContext @@ -6352,6 +6612,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6365,13 +6626,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API GetSecretValueOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API GetSecretValueOperation + : public ClientOperation, + public std::enable_shared_from_this { public: GetSecretValueOperation( ClientConnection &connection, const GetSecretValueOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `GetSecretValueOperation` * @param request The request used for the `GetSecretValueOperation` @@ -6381,13 +6645,19 @@ namespace Aws std::future Activate( const GetSecretValueRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API UpdateStateOperationContext : public OperationModelContext @@ -6415,6 +6685,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6428,13 +6699,15 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API UpdateStateOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API UpdateStateOperation : public ClientOperation, + public std::enable_shared_from_this { public: UpdateStateOperation( ClientConnection &connection, const UpdateStateOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `UpdateStateOperation` * @param request The request used for the `UpdateStateOperation` @@ -6444,13 +6717,19 @@ namespace Aws std::future Activate( const UpdateStateRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API CancelLocalDeploymentOperationContext : public OperationModelContext @@ -6480,6 +6759,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6493,13 +6773,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API CancelLocalDeploymentOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API CancelLocalDeploymentOperation + : public ClientOperation, + public std::enable_shared_from_this { public: CancelLocalDeploymentOperation( ClientConnection &connection, const CancelLocalDeploymentOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `CancelLocalDeploymentOperation` * @param request The request used for the `CancelLocalDeploymentOperation` @@ -6509,13 +6792,19 @@ namespace Aws std::future Activate( const CancelLocalDeploymentRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API ListNamedShadowsForThingOperationContext : public OperationModelContext @@ -6546,6 +6835,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6559,13 +6849,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API ListNamedShadowsForThingOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API ListNamedShadowsForThingOperation + : public ClientOperation, + public std::enable_shared_from_this { public: ListNamedShadowsForThingOperation( ClientConnection &connection, const ListNamedShadowsForThingOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `ListNamedShadowsForThingOperation` * @param request The request used for the `ListNamedShadowsForThingOperation` @@ -6575,13 +6868,19 @@ namespace Aws std::future Activate( const ListNamedShadowsForThingRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API SubscribeToComponentUpdatesStreamHandler : public StreamResponseHandler @@ -6634,6 +6933,7 @@ namespace Aws * Invoked when a message is received on this continuation. */ void OnStreamEvent(Aws::Crt::ScopedResource response) override; + /** * Invoked when a message is received on this continuation but results in an error. * @@ -6641,6 +6941,7 @@ namespace Aws */ bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; + class AWS_GREENGRASSCOREIPC_API SubscribeToComponentUpdatesOperationContext : public OperationModelContext { public: @@ -6669,6 +6970,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6682,7 +6984,9 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToComponentUpdatesOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API SubscribeToComponentUpdatesOperation + : public ClientOperation, + public std::enable_shared_from_this { public: SubscribeToComponentUpdatesOperation( @@ -6690,6 +6994,7 @@ namespace Aws std::shared_ptr streamHandler, const SubscribeToComponentUpdatesOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `SubscribeToComponentUpdatesOperation` * @param request The request used for the `SubscribeToComponentUpdatesOperation` @@ -6699,13 +7004,19 @@ namespace Aws std::future Activate( const SubscribeToComponentUpdatesRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API ListLocalDeploymentsOperationContext : public OperationModelContext @@ -6735,6 +7046,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6748,13 +7060,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API ListLocalDeploymentsOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API ListLocalDeploymentsOperation + : public ClientOperation, + public std::enable_shared_from_this { public: ListLocalDeploymentsOperation( ClientConnection &connection, const ListLocalDeploymentsOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `ListLocalDeploymentsOperation` * @param request The request used for the `ListLocalDeploymentsOperation` @@ -6764,13 +7079,19 @@ namespace Aws std::future Activate( const ListLocalDeploymentsRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API StopComponentOperationContext : public OperationModelContext @@ -6798,6 +7119,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6811,13 +7133,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API StopComponentOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API StopComponentOperation + : public ClientOperation, + public std::enable_shared_from_this { public: StopComponentOperation( ClientConnection &connection, const StopComponentOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `StopComponentOperation` * @param request The request used for the `StopComponentOperation` @@ -6827,13 +7152,19 @@ namespace Aws std::future Activate( const StopComponentRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API PauseComponentOperationContext : public OperationModelContext @@ -6861,6 +7192,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6874,13 +7206,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API PauseComponentOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API PauseComponentOperation + : public ClientOperation, + public std::enable_shared_from_this { public: PauseComponentOperation( ClientConnection &connection, const PauseComponentOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `PauseComponentOperation` * @param request The request used for the `PauseComponentOperation` @@ -6890,13 +7225,19 @@ namespace Aws std::future Activate( const PauseComponentRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API CreateLocalDeploymentOperationContext : public OperationModelContext @@ -6926,6 +7267,7 @@ namespace Aws { return static_cast(m_taggedResult.GetOperationResponse()); } + /** * @return true if the response is associated with an expected response; * false if the response is associated with an error. @@ -6939,13 +7281,16 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API CreateLocalDeploymentOperation : public ClientOperation + class AWS_GREENGRASSCOREIPC_API CreateLocalDeploymentOperation + : public ClientOperation, + public std::enable_shared_from_this { public: CreateLocalDeploymentOperation( ClientConnection &connection, const CreateLocalDeploymentOperationContext &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; + /** * Used to activate a stream for the `CreateLocalDeploymentOperation` * @param request The request used for the `CreateLocalDeploymentOperation` @@ -6955,13 +7300,19 @@ namespace Aws std::future Activate( const CreateLocalDeploymentRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** * Retrieve the result from activating the stream. */ std::future GetResult() noexcept; - protected: - Aws::Crt::String GetModelName() const noexcept override; + private: + std::promise m_resultPromise; + + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function + * object that handles the result. If we did not do this, we risk a crash if the user drops their reference + * before the future gets completed. */ + std::shared_ptr m_selfReference; }; class AWS_GREENGRASSCOREIPC_API GreengrassCoreIpcServiceModel : public ServiceModel diff --git a/greengrass_ipc/source/GreengrassCoreIpcModel.cpp b/greengrass_ipc/source/GreengrassCoreIpcModel.cpp index 272d0d146..1bff67566 100644 --- a/greengrass_ipc/source/GreengrassCoreIpcModel.cpp +++ b/greengrass_ipc/source/GreengrassCoreIpcModel.cpp @@ -7041,8 +7041,7 @@ namespace Aws std::future SubscribeToIoTCoreOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return SubscribeToIoTCoreResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } SubscribeToIoTCoreOperation::SubscribeToIoTCoreOperation( @@ -7058,12 +7057,22 @@ namespace Aws const SubscribeToIoTCoreRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String SubscribeToIoTCoreOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(SubscribeToIoTCoreResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } ResumeComponentOperationContext::ResumeComponentOperationContext( @@ -7111,8 +7120,7 @@ namespace Aws std::future ResumeComponentOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return ResumeComponentResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } ResumeComponentOperation::ResumeComponentOperation( @@ -7127,12 +7135,22 @@ namespace Aws const ResumeComponentRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String ResumeComponentOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(ResumeComponentResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } PublishToIoTCoreOperationContext::PublishToIoTCoreOperationContext( @@ -7180,8 +7198,7 @@ namespace Aws std::future PublishToIoTCoreOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return PublishToIoTCoreResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } PublishToIoTCoreOperation::PublishToIoTCoreOperation( @@ -7196,12 +7213,22 @@ namespace Aws const PublishToIoTCoreRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String PublishToIoTCoreOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(PublishToIoTCoreResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } void SubscribeToConfigurationUpdateStreamHandler::OnStreamEvent( @@ -7279,9 +7306,7 @@ namespace Aws std::future SubscribeToConfigurationUpdateOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, - [this]() { return SubscribeToConfigurationUpdateResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } SubscribeToConfigurationUpdateOperation::SubscribeToConfigurationUpdateOperation( @@ -7297,12 +7322,22 @@ namespace Aws const SubscribeToConfigurationUpdateRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String SubscribeToConfigurationUpdateOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(SubscribeToConfigurationUpdateResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } DeleteThingShadowOperationContext::DeleteThingShadowOperationContext( @@ -7350,8 +7385,7 @@ namespace Aws std::future DeleteThingShadowOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return DeleteThingShadowResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } DeleteThingShadowOperation::DeleteThingShadowOperation( @@ -7366,12 +7400,22 @@ namespace Aws const DeleteThingShadowRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String DeleteThingShadowOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(DeleteThingShadowResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } PutComponentMetricOperationContext::PutComponentMetricOperationContext( @@ -7419,8 +7463,7 @@ namespace Aws std::future PutComponentMetricOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return PutComponentMetricResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } PutComponentMetricOperation::PutComponentMetricOperation( @@ -7435,12 +7478,22 @@ namespace Aws const PutComponentMetricRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String PutComponentMetricOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(PutComponentMetricResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } DeferComponentUpdateOperationContext::DeferComponentUpdateOperationContext( @@ -7488,8 +7541,7 @@ namespace Aws std::future DeferComponentUpdateOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return DeferComponentUpdateResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } DeferComponentUpdateOperation::DeferComponentUpdateOperation( @@ -7504,12 +7556,22 @@ namespace Aws const DeferComponentUpdateRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String DeferComponentUpdateOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(DeferComponentUpdateResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } void SubscribeToValidateConfigurationUpdatesStreamHandler::OnStreamEvent( @@ -7584,9 +7646,7 @@ namespace Aws std::future SubscribeToValidateConfigurationUpdatesOperation:: GetResult() noexcept { - return std::async( - m_asyncLaunchMode, - [this]() { return SubscribeToValidateConfigurationUpdatesResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } SubscribeToValidateConfigurationUpdatesOperation::SubscribeToValidateConfigurationUpdatesOperation( @@ -7602,12 +7662,23 @@ namespace Aws const SubscribeToValidateConfigurationUpdatesRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String SubscribeToValidateConfigurationUpdatesOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value( + SubscribeToValidateConfigurationUpdatesResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } GetConfigurationOperationContext::GetConfigurationOperationContext( @@ -7655,8 +7726,7 @@ namespace Aws std::future GetConfigurationOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return GetConfigurationResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } GetConfigurationOperation::GetConfigurationOperation( @@ -7671,12 +7741,22 @@ namespace Aws const GetConfigurationRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String GetConfigurationOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(GetConfigurationResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } void SubscribeToTopicStreamHandler::OnStreamEvent(Aws::Crt::ScopedResource response) @@ -7759,8 +7839,7 @@ namespace Aws std::future SubscribeToTopicOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return SubscribeToTopicResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } SubscribeToTopicOperation::SubscribeToTopicOperation( @@ -7776,12 +7855,22 @@ namespace Aws const SubscribeToTopicRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String SubscribeToTopicOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(SubscribeToTopicResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } GetComponentDetailsOperationContext::GetComponentDetailsOperationContext( @@ -7829,8 +7918,7 @@ namespace Aws std::future GetComponentDetailsOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return GetComponentDetailsResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } GetComponentDetailsOperation::GetComponentDetailsOperation( @@ -7845,12 +7933,22 @@ namespace Aws const GetComponentDetailsRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String GetComponentDetailsOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(GetComponentDetailsResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } GetClientDeviceAuthTokenOperationContext::GetClientDeviceAuthTokenOperationContext( @@ -7898,8 +7996,7 @@ namespace Aws std::future GetClientDeviceAuthTokenOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return GetClientDeviceAuthTokenResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } GetClientDeviceAuthTokenOperation::GetClientDeviceAuthTokenOperation( @@ -7914,12 +8011,22 @@ namespace Aws const GetClientDeviceAuthTokenRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String GetClientDeviceAuthTokenOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(GetClientDeviceAuthTokenResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } PublishToTopicOperationContext::PublishToTopicOperationContext( @@ -7967,7 +8074,7 @@ namespace Aws std::future PublishToTopicOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { return PublishToTopicResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } PublishToTopicOperation::PublishToTopicOperation( @@ -7982,12 +8089,22 @@ namespace Aws const PublishToTopicRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String PublishToTopicOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(PublishToTopicResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } void SubscribeToCertificateUpdatesStreamHandler::OnStreamEvent( @@ -8071,9 +8188,7 @@ namespace Aws std::future SubscribeToCertificateUpdatesOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, - [this]() { return SubscribeToCertificateUpdatesResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } SubscribeToCertificateUpdatesOperation::SubscribeToCertificateUpdatesOperation( @@ -8089,12 +8204,22 @@ namespace Aws const SubscribeToCertificateUpdatesRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String SubscribeToCertificateUpdatesOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(SubscribeToCertificateUpdatesResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } VerifyClientDeviceIdentityOperationContext::VerifyClientDeviceIdentityOperationContext( @@ -8142,8 +8267,7 @@ namespace Aws std::future VerifyClientDeviceIdentityOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return VerifyClientDeviceIdentityResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } VerifyClientDeviceIdentityOperation::VerifyClientDeviceIdentityOperation( @@ -8158,12 +8282,22 @@ namespace Aws const VerifyClientDeviceIdentityRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String VerifyClientDeviceIdentityOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(VerifyClientDeviceIdentityResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } AuthorizeClientDeviceActionOperationContext::AuthorizeClientDeviceActionOperationContext( @@ -8211,8 +8345,7 @@ namespace Aws std::future AuthorizeClientDeviceActionOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return AuthorizeClientDeviceActionResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } AuthorizeClientDeviceActionOperation::AuthorizeClientDeviceActionOperation( @@ -8227,12 +8360,22 @@ namespace Aws const AuthorizeClientDeviceActionRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String AuthorizeClientDeviceActionOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(AuthorizeClientDeviceActionResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } ListComponentsOperationContext::ListComponentsOperationContext( @@ -8280,7 +8423,7 @@ namespace Aws std::future ListComponentsOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { return ListComponentsResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } ListComponentsOperation::ListComponentsOperation( @@ -8295,12 +8438,22 @@ namespace Aws const ListComponentsRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String ListComponentsOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(ListComponentsResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } CreateDebugPasswordOperationContext::CreateDebugPasswordOperationContext( @@ -8348,8 +8501,7 @@ namespace Aws std::future CreateDebugPasswordOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return CreateDebugPasswordResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } CreateDebugPasswordOperation::CreateDebugPasswordOperation( @@ -8364,12 +8516,22 @@ namespace Aws const CreateDebugPasswordRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String CreateDebugPasswordOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(CreateDebugPasswordResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } GetThingShadowOperationContext::GetThingShadowOperationContext( @@ -8417,7 +8579,7 @@ namespace Aws std::future GetThingShadowOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { return GetThingShadowResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } GetThingShadowOperation::GetThingShadowOperation( @@ -8432,12 +8594,22 @@ namespace Aws const GetThingShadowRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String GetThingShadowOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(GetThingShadowResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } SendConfigurationValidityReportOperationContext::SendConfigurationValidityReportOperationContext( @@ -8486,9 +8658,7 @@ namespace Aws std::future SendConfigurationValidityReportOperation:: GetResult() noexcept { - return std::async( - m_asyncLaunchMode, - [this]() { return SendConfigurationValidityReportResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } SendConfigurationValidityReportOperation::SendConfigurationValidityReportOperation( @@ -8503,12 +8673,22 @@ namespace Aws const SendConfigurationValidityReportRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String SendConfigurationValidityReportOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(SendConfigurationValidityReportResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } UpdateThingShadowOperationContext::UpdateThingShadowOperationContext( @@ -8556,8 +8736,7 @@ namespace Aws std::future UpdateThingShadowOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return UpdateThingShadowResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } UpdateThingShadowOperation::UpdateThingShadowOperation( @@ -8572,12 +8751,22 @@ namespace Aws const UpdateThingShadowRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String UpdateThingShadowOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(UpdateThingShadowResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } UpdateConfigurationOperationContext::UpdateConfigurationOperationContext( @@ -8625,8 +8814,7 @@ namespace Aws std::future UpdateConfigurationOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return UpdateConfigurationResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } UpdateConfigurationOperation::UpdateConfigurationOperation( @@ -8641,12 +8829,22 @@ namespace Aws const UpdateConfigurationRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String UpdateConfigurationOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(UpdateConfigurationResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } ValidateAuthorizationTokenOperationContext::ValidateAuthorizationTokenOperationContext( @@ -8694,8 +8892,7 @@ namespace Aws std::future ValidateAuthorizationTokenOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return ValidateAuthorizationTokenResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } ValidateAuthorizationTokenOperation::ValidateAuthorizationTokenOperation( @@ -8710,12 +8907,22 @@ namespace Aws const ValidateAuthorizationTokenRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String ValidateAuthorizationTokenOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(ValidateAuthorizationTokenResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } RestartComponentOperationContext::RestartComponentOperationContext( @@ -8763,8 +8970,7 @@ namespace Aws std::future RestartComponentOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return RestartComponentResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } RestartComponentOperation::RestartComponentOperation( @@ -8779,12 +8985,22 @@ namespace Aws const RestartComponentRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String RestartComponentOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(RestartComponentResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } GetLocalDeploymentStatusOperationContext::GetLocalDeploymentStatusOperationContext( @@ -8832,8 +9048,7 @@ namespace Aws std::future GetLocalDeploymentStatusOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return GetLocalDeploymentStatusResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } GetLocalDeploymentStatusOperation::GetLocalDeploymentStatusOperation( @@ -8848,12 +9063,22 @@ namespace Aws const GetLocalDeploymentStatusRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String GetLocalDeploymentStatusOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(GetLocalDeploymentStatusResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } GetSecretValueOperationContext::GetSecretValueOperationContext( @@ -8901,7 +9126,7 @@ namespace Aws std::future GetSecretValueOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { return GetSecretValueResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } GetSecretValueOperation::GetSecretValueOperation( @@ -8916,12 +9141,22 @@ namespace Aws const GetSecretValueRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String GetSecretValueOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(GetSecretValueResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } UpdateStateOperationContext::UpdateStateOperationContext( @@ -8968,7 +9203,7 @@ namespace Aws std::future UpdateStateOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { return UpdateStateResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } UpdateStateOperation::UpdateStateOperation( @@ -8983,12 +9218,22 @@ namespace Aws const UpdateStateRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String UpdateStateOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(UpdateStateResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } CancelLocalDeploymentOperationContext::CancelLocalDeploymentOperationContext( @@ -9036,8 +9281,7 @@ namespace Aws std::future CancelLocalDeploymentOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return CancelLocalDeploymentResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } CancelLocalDeploymentOperation::CancelLocalDeploymentOperation( @@ -9052,12 +9296,22 @@ namespace Aws const CancelLocalDeploymentRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String CancelLocalDeploymentOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(CancelLocalDeploymentResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } ListNamedShadowsForThingOperationContext::ListNamedShadowsForThingOperationContext( @@ -9105,8 +9359,7 @@ namespace Aws std::future ListNamedShadowsForThingOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return ListNamedShadowsForThingResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } ListNamedShadowsForThingOperation::ListNamedShadowsForThingOperation( @@ -9121,12 +9374,22 @@ namespace Aws const ListNamedShadowsForThingRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String ListNamedShadowsForThingOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(ListNamedShadowsForThingResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } void SubscribeToComponentUpdatesStreamHandler::OnStreamEvent( @@ -9204,8 +9467,7 @@ namespace Aws std::future SubscribeToComponentUpdatesOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return SubscribeToComponentUpdatesResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } SubscribeToComponentUpdatesOperation::SubscribeToComponentUpdatesOperation( @@ -9221,12 +9483,22 @@ namespace Aws const SubscribeToComponentUpdatesRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String SubscribeToComponentUpdatesOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(SubscribeToComponentUpdatesResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } ListLocalDeploymentsOperationContext::ListLocalDeploymentsOperationContext( @@ -9274,8 +9546,7 @@ namespace Aws std::future ListLocalDeploymentsOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return ListLocalDeploymentsResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } ListLocalDeploymentsOperation::ListLocalDeploymentsOperation( @@ -9290,12 +9561,22 @@ namespace Aws const ListLocalDeploymentsRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String ListLocalDeploymentsOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(ListLocalDeploymentsResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } StopComponentOperationContext::StopComponentOperationContext( @@ -9343,7 +9624,7 @@ namespace Aws std::future StopComponentOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { return StopComponentResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } StopComponentOperation::StopComponentOperation( @@ -9358,12 +9639,22 @@ namespace Aws const StopComponentRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String StopComponentOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(StopComponentResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } PauseComponentOperationContext::PauseComponentOperationContext( @@ -9411,7 +9702,7 @@ namespace Aws std::future PauseComponentOperation::GetResult() noexcept { - return std::async(m_asyncLaunchMode, [this]() { return PauseComponentResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } PauseComponentOperation::PauseComponentOperation( @@ -9426,12 +9717,22 @@ namespace Aws const PauseComponentRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String PauseComponentOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(PauseComponentResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } CreateLocalDeploymentOperationContext::CreateLocalDeploymentOperationContext( @@ -9479,8 +9780,7 @@ namespace Aws std::future CreateLocalDeploymentOperation::GetResult() noexcept { - return std::async( - m_asyncLaunchMode, [this]() { return CreateLocalDeploymentResult(GetOperationResult().get()); }); + return m_resultPromise.get_future(); } CreateLocalDeploymentOperation::CreateLocalDeploymentOperation( @@ -9495,12 +9795,22 @@ namespace Aws const CreateLocalDeploymentRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - return ClientOperation::Activate(static_cast(&request), onMessageFlushCallback); - } - - Aws::Crt::String CreateLocalDeploymentOperation::GetModelName() const noexcept - { - return m_operationModelContext.GetOperationName(); + bool synchronousSuccess = false; + m_selfReference = shared_from_this(); + auto activateFuture = ClientOperation::Activate( + static_cast(&request), + std::move(onMessageFlushCallback), + [this](TaggedResult &&unmodeledResult) + { + m_resultPromise.set_value(CreateLocalDeploymentResult(std::move(unmodeledResult))); + m_selfReference = nullptr; + }, + synchronousSuccess); + if (!synchronousSuccess) + { + m_selfReference = nullptr; + } + return activateFuture; } GreengrassCoreIpcServiceModel::GreengrassCoreIpcServiceModel() noexcept From 422f31587e8208654bb1a0af919218acfcadbbc9 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Fri, 30 May 2025 14:48:04 -0700 Subject: [PATCH 38/56] Remove ifdefd out stuff --- eventstream_rpc/source/EventStreamClient.cpp | 655 ------------------- 1 file changed, 655 deletions(-) diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 488ec7f2d..e11da0b88 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -1263,661 +1263,6 @@ namespace Aws void StreamResponseHandler::OnStreamClosed() {} -#ifdef NEVER - struct RawContinuationCallbackDataWrapper - { - RawContinuationCallbackDataWrapper( - Aws::Crt::Allocator *allocator, - const std::shared_ptr &callbackData) - : m_allocator(allocator), m_callbackData(callbackData) - { - } - - Aws::Crt::Allocator *m_allocator; - std::shared_ptr m_callbackData; - }; - - static void s_onContinuationTerminated(void *user_data) - { - if (user_data == nullptr) - { - return; - } - - struct RawContinuationCallbackDataWrapper *wrapper = - static_cast(user_data); - Aws::Crt::Delete(wrapper, wrapper->m_allocator); - } - - ClientContinuation::ClientContinuation( - struct aws_event_stream_rpc_client_connection *connection, - ClientContinuationHandler &continuationHandler, - Crt::Allocator *allocator) noexcept - : m_allocator(allocator), m_continuationHandler(continuationHandler), m_continuationToken(nullptr) - { - struct aws_event_stream_rpc_client_stream_continuation_options options; - options.on_continuation = ClientContinuation::s_onContinuationMessage; - options.on_continuation_closed = ClientContinuation::s_onContinuationClosed; - options.on_continuation_terminated = s_onContinuationTerminated; - - m_callbackData = Crt::MakeShared(m_allocator, this, m_allocator); - - m_continuationHandler.m_callbackData = m_callbackData; - options.user_data = reinterpret_cast( - Aws::Crt::New(allocator, allocator, m_callbackData)); - - if (connection) - { - m_continuationToken = aws_event_stream_rpc_client_connection_new_stream(connection, &options); - if (m_continuationToken == nullptr) - { - m_continuationHandler.m_callbackData = nullptr; - m_callbackData = nullptr; - } - } - } - - ClientContinuation::~ClientContinuation() noexcept - { - Release(); - } - - void ClientContinuation::Release() - { - if (m_callbackData != nullptr) - { - { - const std::lock_guard lock(m_callbackData->callbackMutex); - m_callbackData->continuationDestroyed = true; - } - } - - if (m_continuationToken) - { - aws_event_stream_rpc_client_continuation_release(m_continuationToken); - m_continuationToken = nullptr; - } - } - - void ClientContinuation::s_onContinuationMessage( - struct aws_event_stream_rpc_client_continuation_token *continuationToken, - const struct aws_event_stream_rpc_message_args *messageArgs, - void *userData) noexcept - { - (void)continuationToken; - /* The `userData` pointer is used to pass a `ContinuationCallbackData` object. */ - auto *callbackData = static_cast(userData)->m_callbackData.get(); - auto *thisContinuation = callbackData->clientContinuation; - - Crt::List continuationMessageHeaders; - for (size_t i = 0; i < messageArgs->headers_count; ++i) - { - continuationMessageHeaders.emplace_back( - EventStreamHeader(messageArgs->headers[i], thisContinuation->m_allocator)); - } - - Crt::Optional payload; - - if (messageArgs->payload) - { - payload = Crt::Optional(*messageArgs->payload); - } - else - { - payload = Crt::Optional(); - } - - const std::lock_guard lock(callbackData->callbackMutex); - if (callbackData->continuationDestroyed) - return; - thisContinuation->m_continuationHandler.OnContinuationMessage( - continuationMessageHeaders, payload, messageArgs->message_type, messageArgs->message_flags); - } - - void ClientContinuation::s_onContinuationClosed( - struct aws_event_stream_rpc_client_continuation_token *continuationToken, - void *userData) noexcept - { - (void)continuationToken; - - /* The `userData` pointer is used to pass a `ContinuationCallbackData` object. */ - auto *callbackData = static_cast(userData)->m_callbackData.get(); - - const std::lock_guard lock(callbackData->callbackMutex); - if (callbackData->continuationDestroyed) - return; - - auto *thisContinuation = callbackData->clientContinuation; - thisContinuation->m_continuationHandler.OnContinuationClosed(); - } - - std::future ClientContinuation::Activate( - const Crt::String &operationName, - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags, - OnMessageFlushCallback onMessageFlushCallback) noexcept - { - struct aws_array_list headersArray; - OnMessageFlushCallbackContainer *callbackContainer = nullptr; - std::promise onFlushPromise; - - if (m_continuationToken == nullptr) - { - onFlushPromise.set_value({EVENT_STREAM_RPC_CONNECTION_CLOSED, 0}); - return onFlushPromise.get_future(); - } - - if (IsClosed()) - { - onFlushPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); - return onFlushPromise.get_future(); - } - - s_fillNativeHeadersArray(headers, &headersArray, m_allocator); - - /* - * Regardless of how the promise gets moved around (or not), this future should stay valid as a return - * value. - * - * We pull it out early because the call to aws_event_stream_rpc_client_continuation_activate() may complete - * and delete the promise before we pull out the future afterwords. - */ - std::future retValue = onFlushPromise.get_future(); - - struct aws_event_stream_rpc_message_args msg_args; - msg_args.headers = (struct aws_event_stream_header_value_pair *)headersArray.data; - msg_args.headers_count = headers.size(); - msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; - msg_args.message_type = messageType; - msg_args.message_flags = messageFlags; - - /* This heap allocation is necessary so that the flush callback can still be invoked when this function - * returns. */ - callbackContainer = Crt::New(m_allocator, m_allocator); - callbackContainer->onMessageFlushCallback = onMessageFlushCallback; - callbackContainer->onFlushPromise = std::move(onFlushPromise); - - int errorCode = aws_event_stream_rpc_client_continuation_activate( - m_continuationToken, - Crt::ByteCursorFromCString(operationName.c_str()), - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(callbackContainer)); - - /* Cleanup. */ - if (aws_array_list_is_valid(&headersArray)) - { - aws_array_list_clean_up(&headersArray); - } - - if (errorCode) - { - onFlushPromise = std::move(callbackContainer->onFlushPromise); - onFlushPromise.set_value({EVENT_STREAM_RPC_CRT_ERROR, errorCode}); - Crt::Delete(callbackContainer, m_allocator); - } - - return retValue; - } - - std::future ClientContinuation::SendMessage( - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags, - OnMessageFlushCallback onMessageFlushCallback) noexcept - { - struct aws_array_list headersArray; - OnMessageFlushCallbackContainer *callbackContainer = nullptr; - std::promise onFlushPromise; - - if (IsClosed()) - { - onFlushPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); - return onFlushPromise.get_future(); - } - - s_fillNativeHeadersArray(headers, &headersArray, m_allocator); - - struct aws_event_stream_rpc_message_args msg_args; - msg_args.headers = (struct aws_event_stream_header_value_pair *)headersArray.data; - msg_args.headers_count = headers.size(); - msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; - msg_args.message_type = messageType; - msg_args.message_flags = messageFlags; - - /* This heap allocation is necessary so that the flush callback can still be invoked when this function - * returns. */ - callbackContainer = Crt::New(m_allocator, m_allocator); - callbackContainer->onMessageFlushCallback = onMessageFlushCallback; - callbackContainer->onFlushPromise = std::move(onFlushPromise); - - int errorCode = AWS_OP_SUCCESS; - if (m_continuationToken) - { - if (aws_event_stream_rpc_client_continuation_send_message( - m_continuationToken, - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(callbackContainer))) - { - errorCode = aws_last_error(); - } - } - - /* Cleanup. */ - if (aws_array_list_is_valid(&headersArray)) - { - aws_array_list_clean_up(&headersArray); - } - - if (errorCode) - { - onFlushPromise = std::move(callbackContainer->onFlushPromise); - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "A CRT error occurred while queueing a message to be sent on a stream: %s", - Crt::ErrorDebugString(errorCode)); - onFlushPromise.set_value({EVENT_STREAM_RPC_CRT_ERROR, errorCode}); - Crt::Delete(callbackContainer, m_allocator); - } - else - { - return callbackContainer->onFlushPromise.get_future(); - } - - return onFlushPromise.get_future(); - } - - bool ClientContinuation::IsClosed() noexcept - { - if (!m_continuationToken) - { - return true; - } - else - { - return aws_event_stream_rpc_client_continuation_is_closed(m_continuationToken); - } - } - - std::future ClientOperation::GetOperationResult() noexcept - { - { - const std::lock_guard lock(m_continuationMutex); - - if (m_clientContinuation.IsClosed() && !m_resultReceived) - { - AWS_LOGF_ERROR(AWS_LS_EVENT_STREAM_RPC_CLIENT, "The underlying stream is already closed."); - m_initialResponsePromise.set_value(TaggedResult({EVENT_STREAM_RPC_CONNECTION_CLOSED, 0})); - m_resultReceived = true; - } - } - - return m_initialResponsePromise.get_future(); - } - - const EventStreamHeader *ClientOperation::GetHeaderByName( - const Crt::List &headers, - const Crt::String &name) noexcept - { - for (auto it = headers.begin(); it != headers.end(); ++it) - { - if (name == it->GetHeaderName()) - { - return &(*it); - } - } - return nullptr; - } - - EventStreamRpcStatusCode ClientOperation::HandleData(const Crt::Optional &payload) - { - Crt::StringView payloadStringView; - if (payload.has_value()) - { - payloadStringView = Crt::ByteCursorToStringView(Crt::ByteCursorFromByteBuf(payload.value())); - } - - /* The value of this hashmap contains the function that allocates the response object from the - * payload. */ - /* Responses after the first message don't necessarily have the same shape as the first. */ - Crt::ScopedResource response; - if (m_messageCount == 1) - { - response = m_operationModelContext.AllocateInitialResponseFromPayload(payloadStringView, m_allocator); - } - else - { - response = m_operationModelContext.AllocateStreamingResponseFromPayload(payloadStringView, m_allocator); - } - - if (response.get() == nullptr) - { - AWS_LOGF_ERROR(AWS_LS_EVENT_STREAM_RPC_CLIENT, "Failed to allocate a response from the payload."); - return EVENT_STREAM_RPC_ALLOCATION_ERROR; - } - - if (m_messageCount == 1) - { - const std::lock_guard lock(m_continuationMutex); - m_resultReceived = true; - m_initialResponsePromise.set_value(TaggedResult(std::move(response))); - } - else - { - if (m_streamHandler) - m_streamHandler->OnStreamEvent(std::move(response)); - } - - return EVENT_STREAM_RPC_SUCCESS; - } - - EventStreamRpcStatusCode ClientOperation::HandleError( - const Crt::String &modelName, - const Crt::Optional &payload, - uint32_t messageFlags) - { - bool streamAlreadyTerminated = (messageFlags & AWS_EVENT_STREAM_RPC_MESSAGE_FLAG_TERMINATE_STREAM) != 0; - - Crt::StringView payloadStringView; - if (payload.has_value()) - { - payloadStringView = Crt::ByteCursorToStringView(Crt::ByteCursorFromByteBuf(payload.value())); - } - - /* The value of this hashmap contains the function that allocates the error from the - * payload. */ - Crt::ScopedResource error = - m_operationModelContext.AllocateOperationErrorFromPayload(modelName, payloadStringView, m_allocator); - if (error.get() == nullptr) - return EVENT_STREAM_RPC_UNMAPPED_DATA; - if (error->GetMessage().has_value()) - { - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "An error was received from the server: %s", - error->GetMessage().value().c_str()); - } - TaggedResult taggedResult(std::move(error)); - if (m_messageCount == 1) - { - { - const std::lock_guard lock(m_continuationMutex); - m_resultReceived = true; - m_initialResponsePromise.set_value(std::move(taggedResult)); - } - /* Close the stream unless the server already closed it for us. This condition is checked - * so that TERMINATE_STREAM messages aren't resent by the client. */ - if (!streamAlreadyTerminated && !m_clientContinuation.IsClosed()) - { - Close().wait(); - } - } - else - { - bool shouldCloseNow = true; - if (m_streamHandler) - shouldCloseNow = m_streamHandler->OnStreamError(std::move(error), {EVENT_STREAM_RPC_SUCCESS, 0}); - if (!streamAlreadyTerminated && shouldCloseNow && !m_clientContinuation.IsClosed()) - { - Close().wait(); - } - } - - return EVENT_STREAM_RPC_SUCCESS; - } - - void ClientOperation::OnContinuationMessage( - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags) - { - EventStreamRpcStatusCode errorCode = EVENT_STREAM_RPC_SUCCESS; - const EventStreamHeader *modelHeader = nullptr; - const EventStreamHeader *contentHeader = nullptr; - Crt::String modelName; - - if (messageFlags & AWS_EVENT_STREAM_RPC_MESSAGE_FLAG_TERMINATE_STREAM) - { - const std::lock_guard lock(m_continuationMutex); - m_expectingClose = true; - } - - m_messageCount += 1; - - modelHeader = GetHeaderByName(headers, Crt::String(SERVICE_MODEL_TYPE_HEADER)); - if (modelHeader == nullptr) - { - /* Missing required service model type header. */ - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "A required header (%s) could not be found in the message.", - SERVICE_MODEL_TYPE_HEADER); - errorCode = EVENT_STREAM_RPC_UNMAPPED_DATA; - } - - /* Verify that the model name matches. */ - if (!errorCode) - { - modelHeader->GetValueAsString(modelName); - if (messageType == AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE) - { - if (m_messageCount == 1 && m_operationModelContext.GetInitialResponseModelName() != modelName) - { - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "The model name of the initial response did not match its expected model name."); - errorCode = EVENT_STREAM_RPC_UNMAPPED_DATA; - } - else if ( - m_messageCount > 1 && m_operationModelContext.GetStreamingResponseModelName().has_value() && - m_operationModelContext.GetStreamingResponseModelName().value() != modelName) - { - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "The model name of a subsequent response did not match its expected model name."); - errorCode = EVENT_STREAM_RPC_UNMAPPED_DATA; - } - } - } - - if (!errorCode) - { - Crt::String contentType; - contentHeader = GetHeaderByName(headers, Crt::String(CONTENT_TYPE_HEADER)); - if (contentHeader == nullptr) - { - /* Missing required content type header. */ - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "A required header (%s) could not be found in the message.", - CONTENT_TYPE_HEADER); - errorCode = EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE; - } - else if (contentHeader->GetValueAsString(contentType) && contentType != CONTENT_TYPE_APPLICATION_JSON) - { - /* Missing required content type header. */ - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "The content type (%s) header was specified with an unsupported value (%s).", - CONTENT_TYPE_HEADER, - contentType.c_str()); - errorCode = EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE; - } - } - - if (!errorCode) - { - if (messageType == AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE) - { - errorCode = HandleData(payload); - } - else - { - errorCode = HandleError(modelName, payload, messageFlags); - } - } - - if (errorCode) - { - if (m_messageCount == 1) - { - const std::lock_guard lock(m_continuationMutex); - m_resultReceived = true; - RpcError promiseValue = {(EventStreamRpcStatusCode)errorCode, 0}; - m_initialResponsePromise.set_value(TaggedResult(promiseValue)); - } - else - { - bool shouldClose = true; - if (m_streamHandler) - shouldClose = m_streamHandler->OnStreamError(nullptr, {errorCode, 0}); - if (!m_clientContinuation.IsClosed() && shouldClose) - { - Close().wait(); - } - } - } - } - - std::future ClientOperation::Activate( - const AbstractShapeBase *shape, - OnMessageFlushCallback onMessageFlushCallback) noexcept - { - /* Promises must be reset in case the client would like to send a subsequent request with the same - * `ClientOperation`. */ - m_initialResponsePromise = {}; - { - const std::lock_guard lock(m_continuationMutex); - m_resultReceived = false; - } - - Crt::List headers; - headers.emplace_back(EventStreamHeader( - Crt::String(CONTENT_TYPE_HEADER), Crt::String(CONTENT_TYPE_APPLICATION_JSON), m_allocator)); - headers.emplace_back( - EventStreamHeader(Crt::String(SERVICE_MODEL_TYPE_HEADER), GetModelName(), m_allocator)); - Crt::JsonObject payloadObject; - shape->SerializeToJsonObject(payloadObject); - Crt::String payloadString = payloadObject.View().WriteCompact(); - return m_clientContinuation.Activate( - GetModelName(), - headers, - Crt::ByteBufFromCString(payloadString.c_str()), - AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE, - 0, - onMessageFlushCallback); - } - - void ClientOperation::OnContinuationClosed() - { - const std::lock_guard lock(m_continuationMutex); - if (!m_resultReceived) - { - m_initialResponsePromise.set_value(TaggedResult({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0})); - m_resultReceived = true; - } - - if (m_expectingClose) - { - m_expectingClose = false; - if (!m_streamClosedCalled && m_streamHandler) - { - m_streamHandler->OnStreamClosed(); - m_streamClosedCalled = true; - } - m_closeReady.notify_one(); - } - } - - void ClientOperation::WithLaunchMode(std::launch mode) noexcept - { - m_asyncLaunchMode = mode; - } - - class AWS_EVENTSTREAMRPC_API ClientOperation : public ClientContinuationHandler - { - public: - ClientOperation( - ClientConnection &connection, - std::shared_ptr streamHandler, - const OperationModelContext &operationModelContext, - Crt::Allocator *allocator) noexcept; - ~ClientOperation() noexcept override; - - std::future Close(OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; - - void WithLaunchMode(std::launch mode) noexcept; - - std::future Activate( - const AbstractShapeBase *shape, - OnMessageFlushCallback onMessageFlushCallback, - std::function &&onResultCallback) noexcept; - }; - - std::future ClientOperation::Close(OnMessageFlushCallback onMessageFlushCallback) noexcept - { - const std::lock_guard lock(m_continuationMutex); - if (m_expectingClose || m_clientContinuation.IsClosed()) - { - std::promise errorPromise; - errorPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); - return errorPromise.get_future(); - } - else - { - std::promise onTerminatePromise; - - int errorCode = AWS_OP_ERR; - struct aws_event_stream_rpc_message_args msg_args; - msg_args.headers = nullptr; - msg_args.headers_count = 0; - msg_args.payload = nullptr; - msg_args.message_type = AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE; - msg_args.message_flags = AWS_EVENT_STREAM_RPC_MESSAGE_FLAG_TERMINATE_STREAM; - - /* This heap allocation is necessary so that the flush callback can still be invoked when this function - * returns. */ - OnMessageFlushCallbackContainer *callbackContainer = - Crt::New(m_allocator, m_allocator); - callbackContainer->onMessageFlushCallback = onMessageFlushCallback; - callbackContainer->onFlushPromise = std::move(onTerminatePromise); - - if (m_clientContinuation.m_continuationToken) - { - errorCode = aws_event_stream_rpc_client_continuation_send_message( - m_clientContinuation.m_continuationToken, - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(callbackContainer)); - } - - if (errorCode) - { - onTerminatePromise = std::move(callbackContainer->onFlushPromise); - std::promise errorPromise; - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "A CRT error occurred while closing the stream: %s", - Crt::ErrorDebugString(errorCode)); - onTerminatePromise.set_value({EVENT_STREAM_RPC_CRT_ERROR, errorCode}); - Crt::Delete(callbackContainer, m_allocator); - } - else - { - m_expectingClose = true; - return callbackContainer->onFlushPromise.get_future(); - } - - return onTerminatePromise.get_future(); - } - } -#endif // NEVER - static const EventStreamHeader *s_GetHeaderByName( const Crt::List &headers, const Crt::String &name) noexcept From cdb0a7ab7ae02d5f84f6e8bbbbcef29c5a45a307 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Mon, 2 Jun 2025 13:20:51 -0700 Subject: [PATCH 39/56] Outbound streaming --- .../aws/eventstreamrpc/EventStreamClient.h | 13 ++ eventstream_rpc/source/EventStreamClient.cpp | 122 ++++++++++++++++-- eventstream_rpc/tests/EchoTestRpcModel.cpp | 16 +++ .../tests/include/awstest/EchoTestRpcModel.h | 24 ++++ 4 files changed, 161 insertions(+), 14 deletions(-) diff --git a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h index 1cb58c76f..59517d3ab 100644 --- a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h +++ b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h @@ -156,6 +156,7 @@ namespace Aws EVENT_STREAM_RPC_CRT_ERROR, EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED, EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS, + EVENT_STREAM_RPC_CONTINUATION_NOT_YET_OPENED, }; /** @@ -724,6 +725,18 @@ namespace Aws std::function &&onResultCallback, bool &synchronousSuccess) noexcept; + /** + * Sends a message on the stream + * + * @param shape Modeled representation of the message to send + * @param onMessageFlushCallback Optional callback to invoke when the message is written or fails to send + * + * @return Future which will be resolved once the message is sent. + */ + std::future SendStreamMessage( + const AbstractShapeBase *shape, + OnMessageFlushCallback &&onMessageFlushCallback) noexcept; + /** * Returns the canonical model name associated with this operation across any client language. * Namespace included. diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index e11da0b88..c3bb31b56 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -49,7 +49,6 @@ namespace Aws { aws_ref_count_init(&m_refCount, this, s_deleteMessageCallbackContainer); aws_ref_count_acquire(&m_refCount); // always start at 2, one for C++, one for C - AWS_ZERO_STRUCT(m_sharedState.m_node); m_sharedState.m_state = CallbackState::Incomplete; m_sharedState.m_onMessageFlushCallback = std::move(flushCallback); } @@ -84,10 +83,6 @@ namespace Aws callback->m_sharedState.m_state = CallbackState::Finished; onMessageFlushCallback = std::move(callback->m_sharedState.m_onMessageFlushCallback); onFlushPromise = std::move(callback->m_sharedState.m_onFlushPromise); - if (aws_linked_list_node_is_in_list(&callback->m_sharedState.m_node)) - { - aws_linked_list_remove(&callback->m_sharedState.m_node); - } } } @@ -120,13 +115,6 @@ namespace Aws Aws::Crt::Allocator *GetAllocator() const { return m_allocator; } - void AddToList(struct aws_linked_list *list) - { - std::lock_guard lock(m_sharedStateLock); - - aws_linked_list_push_back(list, &m_sharedState.m_node); - } - private: enum class CallbackState { @@ -141,7 +129,6 @@ namespace Aws struct { CallbackState m_state; - struct aws_linked_list_node m_node; OnMessageFlushCallback m_onMessageFlushCallback; std::promise m_onFlushPromise; } m_sharedState; @@ -349,6 +336,8 @@ namespace Aws return "EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED"; case EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS: return "EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS"; + case EVENT_STREAM_RPC_CONTINUATION_NOT_YET_OPENED: + return "EVENT_STREAM_RPC_CONTINUATION_NOT_YET_OPENED"; } return "Unknown status code"; } @@ -1363,6 +1352,13 @@ namespace Aws OnMessageFlushCallback &&onMessageFlushCallback, bool &synchronousSuccess) noexcept; + std::future SendStreamMessage( + const Crt::List &headers, + const Crt::Optional &payload, + MessageType messageType, + uint32_t messageFlags, + OnMessageFlushCallback &&onMessageFlushCallback); + std::future Close(OnMessageFlushCallback &&onMessageFlushCallback = nullptr) noexcept; Crt::String GetModelName() const noexcept; @@ -1481,6 +1477,27 @@ namespace Aws synchronousSuccess); } + std::future ClientOperation::SendStreamMessage( + const AbstractShapeBase *shape, + OnMessageFlushCallback &&onMessageFlushCallback) noexcept + { + Crt::List headers; + headers.emplace_back(EventStreamHeader( + Crt::String(CONTENT_TYPE_HEADER), Crt::String(CONTENT_TYPE_APPLICATION_JSON), m_allocator)); + headers.emplace_back( + EventStreamHeader(Crt::String(SERVICE_MODEL_TYPE_HEADER), GetModelName(), m_allocator)); + Crt::JsonObject payloadObject; + shape->SerializeToJsonObject(payloadObject); + Crt::String payloadString = payloadObject.View().WriteCompact(); + + return m_impl->SendStreamMessage( + headers, + Crt::ByteBufFromCString(payloadString.c_str()), + AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE, + 0, + std::move(onMessageFlushCallback)); + } + ClientContinuationImpl::ClientContinuationImpl( Aws::Crt::Allocator *allocator, struct aws_event_stream_rpc_client_connection *connection) noexcept @@ -1640,7 +1657,7 @@ namespace Aws std::lock_guard lock(m_sharedStateLock); if (m_sharedState.m_continuation == nullptr) { - activationPromise.set_value({EVENT_STREAM_RPC_CONNECTION_CLOSED, 0}); + activationPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); return activationFuture; } @@ -1713,6 +1730,83 @@ namespace Aws return activationFuture; } + std::future ClientContinuationImpl::SendStreamMessage( + const Crt::List &headers, + const Crt::Optional &payload, + MessageType messageType, + uint32_t messageFlags, + OnMessageFlushCallback &&onMessageFlushCallback) + { + int result = AWS_OP_SUCCESS; + struct aws_array_list headersArray; // guaranteed to be zeroed or valid if we reach the end of the function + OnMessageFlushCallbackContainer *sendFailureContainer = nullptr; + std::promise sendPromise; + std::future sendFuture = sendPromise.get_future(); + { + std::lock_guard lock(m_sharedStateLock); + if (m_sharedState.m_continuation == nullptr) + { + sendPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); + return sendFuture; + } + + switch (m_sharedState.m_currentState) + { + case ContinuationStateType::PendingActivate: + case ContinuationStateType::None: + sendPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_NOT_YET_OPENED, 0}); + return sendFuture; + + case ContinuationStateType::PendingClose: + case ContinuationStateType::Closed: + sendPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); + return sendFuture; + + default: + break; + } + + // cleanup requirements mean we can't early out from here on + s_fillNativeHeadersArray(headers, &headersArray, m_allocator); + + struct aws_event_stream_rpc_message_args msg_args; + msg_args.headers = static_cast(headersArray.data); + msg_args.headers_count = headers.size(); + msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; + msg_args.message_type = messageType; + msg_args.message_flags = messageFlags; + + auto sendContainer = Crt::New( + m_allocator, m_allocator, std::move(onMessageFlushCallback), std::move(sendPromise)); + OnMessageFlushCallbackContainer::Release(sendContainer); // release our ref + + result = aws_event_stream_rpc_client_continuation_send_message( + m_sharedState.m_continuation, + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(sendContainer)); + + if (result != AWS_OP_SUCCESS) + { + sendFailureContainer = sendContainer; + } + } + + if (sendFailureContainer) + { + OnMessageFlushCallbackContainer::Complete( + sendFailureContainer, {EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}); + OnMessageFlushCallbackContainer::Release(sendFailureContainer); + } + + if (aws_array_list_is_valid(&headersArray)) + { + aws_array_list_clean_up(&headersArray); + } + + return sendFuture; + } + // Intentionally returns an error code and not AWS_OP_ERR/AWS_OP_SUCCESS // shared state lock must be held before calling int ClientContinuationImpl::SendCloseMessage( diff --git a/eventstream_rpc/tests/EchoTestRpcModel.cpp b/eventstream_rpc/tests/EchoTestRpcModel.cpp index 059554ed2..63d3472c6 100644 --- a/eventstream_rpc/tests/EchoTestRpcModel.cpp +++ b/eventstream_rpc/tests/EchoTestRpcModel.cpp @@ -1230,6 +1230,14 @@ namespace Awstest return activateFuture; } + std::future CauseStreamServiceToErrorOperation::SendStreamMessage( + const EchoStreamingMessage &message, + OnMessageFlushCallback onMessageFlushCallback) + { + return ClientOperation::SendStreamMessage( + static_cast(&message), std::move(onMessageFlushCallback)); + } + void EchoStreamMessagesStreamHandler::OnStreamEvent(Aws::Crt::ScopedResource response) { OnStreamEvent(static_cast(response.get())); @@ -1326,6 +1334,14 @@ namespace Awstest return activateFuture; } + std::future EchoStreamMessagesOperation::SendStreamMessage( + const EchoStreamingMessage &message, + OnMessageFlushCallback onMessageFlushCallback) + { + return ClientOperation::SendStreamMessage( + static_cast(&message), std::move(onMessageFlushCallback)); + } + EchoMessageOperationContext::EchoMessageOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) { diff --git a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h index a9cf8de9f..19cdc201c 100644 --- a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h +++ b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h @@ -935,6 +935,18 @@ namespace Awstest const EchoStreamingRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** + * Send a EchoStreamingMessage stream event. + * + * Activate() must have completed before calling SendMessage(). + * + * Returns a Future which completes with a value indicating message + * flush success or what went wrong. + **/ + std::future SendStreamMessage( + const EchoStreamingMessage &event, + OnMessageFlushCallback onMessageFlushCallback = nullptr); + /** * Retrieve the result from activating the stream. */ @@ -1048,6 +1060,18 @@ namespace Awstest const EchoStreamingRequest &request, OnMessageFlushCallback onMessageFlushCallback = nullptr) noexcept; + /** + * Send a EchoStreamingMessage stream event. + * + * Activate() must have completed before calling SendMessage(). + * + * Returns a Future which completes with a value indicating message + * flush success or what went wrong. + **/ + std::future SendStreamMessage( + const EchoStreamingMessage &event, + OnMessageFlushCallback onMessageFlushCallback = nullptr); + /** * Retrieve the result from activating the stream. */ From a217deda04289cd6a15359d3100344b11022d6aa Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Fri, 6 Jun 2025 13:37:10 -0700 Subject: [PATCH 40/56] Checkpoint before branching --- eventstream_rpc/source/EventStreamClient.cpp | 400 +++++++++--------- eventstream_rpc/tests/CMakeLists.txt | 33 +- eventstream_rpc/tests/EchoTestRpcModel.cpp | 48 ++- .../tests/EventStreamClientTest.cpp | 228 +++++++++- .../tests/include/awstest/EchoTestRpcModel.h | 18 + .../aws/greengrass/GreengrassCoreIpcModel.h | 102 +++++ .../source/GreengrassCoreIpcModel.cpp | 272 +++++++----- 7 files changed, 776 insertions(+), 325 deletions(-) diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index c3bb31b56..196370a34 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -1335,6 +1335,7 @@ namespace Aws public: ClientContinuationImpl( Aws::Crt::Allocator *allocator, + struct aws_client_bootstrap *bootstrap, struct aws_event_stream_rpc_client_connection *connection) noexcept; virtual ~ClientContinuationImpl(); @@ -1384,10 +1385,6 @@ namespace Aws void OnMessage(const struct aws_event_stream_rpc_message_args *messageArgs) noexcept; - int SendCloseMessage( - OnMessageFlushCallback &&closeFlushCallback, - std::promise &&closeFlushPromise) noexcept; - static void s_OnContinuationClosed( struct aws_event_stream_rpc_client_continuation_token *token, void *user_data) noexcept; @@ -1500,19 +1497,22 @@ namespace Aws ClientContinuationImpl::ClientContinuationImpl( Aws::Crt::Allocator *allocator, + struct aws_client_bootstrap *bootstrap, struct aws_event_stream_rpc_client_connection *connection) noexcept - : m_allocator(allocator), m_clientBootstrap(aws_client_bootstrap_acquire( - aws_event_stream_rpc_client_connection_get_client_bootstrap(connection))), - m_sharedState(), m_operationModelContext(nullptr) - { - struct aws_event_stream_rpc_client_stream_continuation_options continuation_options = { - .on_continuation = s_OnContinuationMessage, - .on_continuation_closed = s_OnContinuationClosed, - .on_continuation_terminated = s_OnContinuationTerminated, - .user_data = this, - }; - m_sharedState.m_continuation = - aws_event_stream_rpc_client_connection_new_stream(connection, &continuation_options); + : m_allocator(allocator), m_clientBootstrap(aws_client_bootstrap_acquire(bootstrap)), m_sharedState(), + m_operationModelContext(nullptr) + { + if (connection != nullptr) + { + struct aws_event_stream_rpc_client_stream_continuation_options continuation_options = { + .on_continuation = s_OnContinuationMessage, + .on_continuation_closed = s_OnContinuationClosed, + .on_continuation_terminated = s_OnContinuationTerminated, + .user_data = this, + }; + m_sharedState.m_continuation = + aws_event_stream_rpc_client_connection_new_stream(connection, &continuation_options); + } if (!m_sharedState.m_continuation) { @@ -1583,10 +1583,11 @@ namespace Aws std::future ClientContinuationImpl::ShutDown() noexcept { struct aws_event_stream_rpc_client_continuation_token *releaseContinuation = nullptr; +#ifdef NEVER OnMessageFlushCallbackContainer *closeCallbackContainer = nullptr; OnMessageFlushCallbackContainer *activationCallbackContainer = nullptr; std::function activationResponseCallback; - +#endif { std::lock_guard lock(m_sharedStateLock); if (m_sharedState.m_currentState == ContinuationStateType::None) @@ -1596,7 +1597,7 @@ namespace Aws m_sharedState.m_currentState = ContinuationStateType::Closed; m_sharedState.m_desiredState = ContinuationStateType::Closed; } - +#ifdef NEVER activationCallbackContainer = m_sharedState.m_activationCallbackContainer; m_sharedState.m_activationCallbackContainer = nullptr; @@ -1605,8 +1606,9 @@ namespace Aws activationResponseCallback = std::move(m_sharedState.m_activationResponseCallback); m_sharedState.m_activationResponseCallback = nullptr; // unsure if necessary, let's be sure +#endif } - +#ifdef NEVER if (activationResponseCallback) { activationResponseCallback( @@ -1614,8 +1616,7 @@ namespace Aws } /* - * Short-circuit and simulate both activate and close callbacks as necessary. Part of our contract is that - * when Shutdown returns, no further user-facing callbacks/promise completions will be performed. + * Short-circuit and simulate both activate and close callbacks as necessary. */ OnMessageFlushCallbackContainer::Complete( activationCallbackContainer, {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); @@ -1624,7 +1625,7 @@ namespace Aws OnMessageFlushCallbackContainer::Complete( closeCallbackContainer, {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); OnMessageFlushCallbackContainer::Release(closeCallbackContainer); - +#endif if (releaseContinuation != nullptr) { ReleaseContinuation(m_allocator, m_clientBootstrap, releaseContinuation); @@ -1647,79 +1648,89 @@ namespace Aws OnMessageFlushCallback &&onMessageFlushCallback, bool &synchronousSuccess) noexcept { + AWS_FATAL_ASSERT(static_cast(onResultCallback)); + int result = AWS_OP_SUCCESS; synchronousSuccess = false; struct aws_array_list headersArray; // guaranteed to be zeroed or valid if we reach the end of the function - OnMessageFlushCallbackContainer *activationFailureContainer = nullptr; std::promise activationPromise; std::future activationFuture = activationPromise.get_future(); + auto activationContainer = Crt::New( + m_allocator, m_allocator, std::move(onMessageFlushCallback), std::move(activationPromise)); + RpcError activationError = {}; + { std::lock_guard lock(m_sharedStateLock); - if (m_sharedState.m_continuation == nullptr) - { - activationPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); - return activationFuture; - } - - switch (m_sharedState.m_currentState) + if (m_sharedState.m_continuation != nullptr) { - case ContinuationStateType::PendingActivate: - case ContinuationStateType::Activated: - activationPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED, 0}); - return activationFuture; - - case ContinuationStateType::PendingClose: - case ContinuationStateType::Closed: - activationPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); - return activationFuture; - - default: - break; - } - - AWS_FATAL_ASSERT(m_sharedState.m_currentState == ContinuationStateType::None); - - // cleanup requirements mean we can't early out from here on - s_fillNativeHeadersArray(headers, &headersArray, m_allocator); - - struct aws_event_stream_rpc_message_args msg_args; - msg_args.headers = static_cast(headersArray.data); - msg_args.headers_count = headers.size(); - msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; - msg_args.message_type = messageType; - msg_args.message_flags = messageFlags; - - m_sharedState.m_activationCallbackContainer = Crt::New( - m_allocator, m_allocator, std::move(onMessageFlushCallback), std::move(activationPromise)); - m_sharedState.m_activationResponseCallback = std::move(onResultCallback); - - result = aws_event_stream_rpc_client_continuation_activate( - m_sharedState.m_continuation, - Crt::ByteCursorFromCString(operation.c_str()), - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(m_sharedState.m_activationCallbackContainer)); + if (m_sharedState.m_currentState == ContinuationStateType::None) + { + // cleanup requirements mean we can't early out from here on + s_fillNativeHeadersArray(headers, &headersArray, m_allocator); + + struct aws_event_stream_rpc_message_args msg_args; + msg_args.headers = static_cast(headersArray.data); + msg_args.headers_count = headers.size(); + msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; + msg_args.message_type = messageType; + msg_args.message_flags = messageFlags; + + result = aws_event_stream_rpc_client_continuation_activate( + m_sharedState.m_continuation, + Crt::ByteCursorFromCString(operation.c_str()), + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(activationContainer)); + + if (result == AWS_OP_SUCCESS) + { + m_sharedState.m_currentState = ContinuationStateType::PendingActivate; + m_sharedState.m_desiredState = ContinuationStateType::Activated; - if (result != AWS_OP_SUCCESS) - { - activationFailureContainer = m_sharedState.m_activationCallbackContainer; - m_sharedState.m_activationCallbackContainer = nullptr; - m_sharedState.m_activationResponseCallback = std::function(); + m_sharedState.m_activationCallbackContainer = activationContainer; + activationContainer = nullptr; + m_sharedState.m_activationResponseCallback = std::move(onResultCallback); + synchronousSuccess = true; + } + else + { + activationError = {EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}; + } + } + else + { + switch (m_sharedState.m_currentState) + { + case ContinuationStateType::PendingActivate: + case ContinuationStateType::Activated: + activationError = {EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED, 0}; + break; + + case ContinuationStateType::PendingClose: + case ContinuationStateType::Closed: + activationError = {EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}; + break; + + default: + AWS_FATAL_ASSERT(false); + break; + } + } } else { - m_sharedState.m_currentState = ContinuationStateType::PendingActivate; - m_sharedState.m_desiredState = ContinuationStateType::Activated; - synchronousSuccess = true; + // null continuation is only if the connection didn't exist at creation time + activationError = {EVENT_STREAM_RPC_CONNECTION_CLOSED, 0}; } } - if (activationFailureContainer) + if (!synchronousSuccess) { - OnMessageFlushCallbackContainer::Complete( - activationFailureContainer, {EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}); - OnMessageFlushCallbackContainer::Release(activationFailureContainer); - OnMessageFlushCallbackContainer::Release(activationFailureContainer); + AWS_FATAL_ASSERT(activationContainer != nullptr); + + OnMessageFlushCallbackContainer::Complete(activationContainer, activationError); + OnMessageFlushCallbackContainer::Release(activationContainer); + OnMessageFlushCallbackContainer::Release(activationContainer); } if (aws_array_list_is_valid(&headersArray)) @@ -1737,66 +1748,76 @@ namespace Aws uint32_t messageFlags, OnMessageFlushCallback &&onMessageFlushCallback) { - int result = AWS_OP_SUCCESS; + int result = AWS_OP_ERR; struct aws_array_list headersArray; // guaranteed to be zeroed or valid if we reach the end of the function - OnMessageFlushCallbackContainer *sendFailureContainer = nullptr; std::promise sendPromise; std::future sendFuture = sendPromise.get_future(); + auto sendContainer = Crt::New( + m_allocator, m_allocator, std::move(onMessageFlushCallback), std::move(sendPromise)); + RpcError sendError = {}; { std::lock_guard lock(m_sharedStateLock); - if (m_sharedState.m_continuation == nullptr) - { - sendPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); - return sendFuture; - } - - switch (m_sharedState.m_currentState) + if (m_sharedState.m_continuation != nullptr) { - case ContinuationStateType::PendingActivate: - case ContinuationStateType::None: - sendPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_NOT_YET_OPENED, 0}); - return sendFuture; - - case ContinuationStateType::PendingClose: - case ContinuationStateType::Closed: - sendPromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); - return sendFuture; - - default: - break; + if (m_sharedState.m_currentState == ContinuationStateType::Activated) + { + // cleanup requirements mean we can't early out from here on + s_fillNativeHeadersArray(headers, &headersArray, m_allocator); + + struct aws_event_stream_rpc_message_args msg_args; + msg_args.headers = static_cast(headersArray.data); + msg_args.headers_count = headers.size(); + msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; + msg_args.message_type = messageType; + msg_args.message_flags = messageFlags; + + result = aws_event_stream_rpc_client_continuation_send_message( + m_sharedState.m_continuation, + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(sendContainer)); + + if (result != AWS_OP_SUCCESS) + { + sendError = {EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}; + } + else + { + OnMessageFlushCallbackContainer::Release(sendContainer); // release our ref + } + } + else + { + switch (m_sharedState.m_currentState) + { + case ContinuationStateType::PendingActivate: + case ContinuationStateType::None: + sendError = {EVENT_STREAM_RPC_CONTINUATION_NOT_YET_OPENED, 0}; + break; + + case ContinuationStateType::PendingClose: + case ContinuationStateType::Closed: + sendError = {EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}; + break; + + default: + AWS_FATAL_ASSERT(false); + break; + } + } } - - // cleanup requirements mean we can't early out from here on - s_fillNativeHeadersArray(headers, &headersArray, m_allocator); - - struct aws_event_stream_rpc_message_args msg_args; - msg_args.headers = static_cast(headersArray.data); - msg_args.headers_count = headers.size(); - msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; - msg_args.message_type = messageType; - msg_args.message_flags = messageFlags; - - auto sendContainer = Crt::New( - m_allocator, m_allocator, std::move(onMessageFlushCallback), std::move(sendPromise)); - OnMessageFlushCallbackContainer::Release(sendContainer); // release our ref - - result = aws_event_stream_rpc_client_continuation_send_message( - m_sharedState.m_continuation, - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(sendContainer)); - - if (result != AWS_OP_SUCCESS) + else { - sendFailureContainer = sendContainer; + // null continuation is only if the connection didn't exist at creation time + sendError = {EVENT_STREAM_RPC_CONNECTION_CLOSED, 0}; } } - if (sendFailureContainer) + if (result == AWS_OP_ERR) { - OnMessageFlushCallbackContainer::Complete( - sendFailureContainer, {EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}); - OnMessageFlushCallbackContainer::Release(sendFailureContainer); + OnMessageFlushCallbackContainer::Complete(sendContainer, sendError); + OnMessageFlushCallbackContainer::Release(sendContainer); + OnMessageFlushCallbackContainer::Release(sendContainer); } if (aws_array_list_is_valid(&headersArray)) @@ -1807,90 +1828,68 @@ namespace Aws return sendFuture; } - // Intentionally returns an error code and not AWS_OP_ERR/AWS_OP_SUCCESS - // shared state lock must be held before calling - int ClientContinuationImpl::SendCloseMessage( - OnMessageFlushCallback &&closeFlushCallback, - std::promise &&closeFlushPromise) noexcept - { - int errorCode = AWS_ERROR_SUCCESS; - - struct aws_event_stream_rpc_message_args msg_args; - msg_args.headers = nullptr; - msg_args.headers_count = 0; - msg_args.payload = nullptr; - msg_args.message_type = AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE; - msg_args.message_flags = AWS_EVENT_STREAM_RPC_MESSAGE_FLAG_TERMINATE_STREAM; - - m_sharedState.m_closeCallbackContainer = Crt::New( - m_allocator, m_allocator, std::move(closeFlushCallback), std::move(closeFlushPromise)); - - int result = aws_event_stream_rpc_client_continuation_send_message( - m_sharedState.m_continuation, - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(m_sharedState.m_closeCallbackContainer)); - - if (result) - { - errorCode = aws_last_error(); - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "A CRT error occurred while closing the stream: %s", - Crt::ErrorDebugString(errorCode)); - } - - return errorCode; - } - std::future ClientContinuationImpl::Close(OnMessageFlushCallback &&onMessageFlushCallback) noexcept { - int closeErrorCode = AWS_ERROR_SUCCESS; - OnMessageFlushCallbackContainer *closeFailureCallbackContainer = nullptr; + int closeResult = AWS_OP_ERR; std::promise closePromise; std::future closeFuture = closePromise.get_future(); + auto closeCallbackContainer = Crt::New( + m_allocator, m_allocator, std::move(onMessageFlushCallback), std::move(closePromise)); + RpcError closeError = {}; + { std::lock_guard lock(m_sharedStateLock); - if (m_sharedState.m_continuation == nullptr) - { - closePromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); - return closeFuture; - } - - switch (m_sharedState.m_currentState) + if (m_sharedState.m_continuation != nullptr) { - case ContinuationStateType::PendingActivate: - case ContinuationStateType::Activated: + if (m_sharedState.m_currentState == ContinuationStateType::PendingActivate || + m_sharedState.m_currentState == ContinuationStateType::Activated) { - closeErrorCode = SendCloseMessage(std::move(onMessageFlushCallback), std::move(closePromise)); - if (closeErrorCode != AWS_ERROR_SUCCESS) + struct aws_event_stream_rpc_message_args msg_args; + msg_args.headers = nullptr; + msg_args.headers_count = 0; + msg_args.payload = nullptr; + msg_args.message_type = AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE; + msg_args.message_flags = AWS_EVENT_STREAM_RPC_MESSAGE_FLAG_TERMINATE_STREAM; + + closeResult = aws_event_stream_rpc_client_continuation_send_message( + m_sharedState.m_continuation, + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(closeCallbackContainer)); + + if (closeResult == AWS_OP_ERR) { - closeFailureCallbackContainer = m_sharedState.m_closeCallbackContainer; - m_sharedState.m_closeCallbackContainer = nullptr; + closeError = {EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}; } else { m_sharedState.m_currentState = ContinuationStateType::PendingClose; } - break; } - - case ContinuationStateType::PendingClose: - closePromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS, 0}); - return closeFuture; - - default: - closePromise.set_value({EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}); - return closeFuture; + else + { + if (m_sharedState.m_currentState == ContinuationStateType::PendingClose) + { + closeError = {EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS, 0}; + } + else + { + closeError = {EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}; + } + } + } + else + { + // null continuation is only if the connection didn't exist at creation time + closeError = {EVENT_STREAM_RPC_CONNECTION_CLOSED, 0}; } } - if (closeFailureCallbackContainer != nullptr) + if (closeResult != AWS_OP_SUCCESS) { - OnMessageFlushCallbackContainer::Complete( - closeFailureCallbackContainer, {EVENT_STREAM_RPC_CRT_ERROR, closeErrorCode}); - OnMessageFlushCallbackContainer::Release(closeFailureCallbackContainer); - OnMessageFlushCallbackContainer::Release(closeFailureCallbackContainer); + OnMessageFlushCallbackContainer::Complete(closeCallbackContainer, closeError); + OnMessageFlushCallbackContainer::Release(closeCallbackContainer); + OnMessageFlushCallbackContainer::Release(closeCallbackContainer); } return closeFuture; @@ -2090,7 +2089,20 @@ namespace Aws { if (result.m_statusCode == EVENT_STREAM_RPC_SUCCESS) { - activationResultCallback(TaggedResult(std::move(result.m_message.value().m_shape))); + const auto &message = result.m_message.value(); + if (message.m_route == EventStreamMessageRoutingType::Response) + { + activationResultCallback(TaggedResult(std::move(result.m_message.value().m_shape))); + } + else + { + Crt::Allocator *allocator = m_allocator; + auto errorResponse = Crt::ScopedResource( + static_cast(result.m_message.value().m_shape.release()), + [allocator](OperationError *shape) { Crt::Delete(shape, allocator); }); + + activationResultCallback(TaggedResult(std::move(errorResponse))); + } } else { @@ -2150,7 +2162,7 @@ namespace Aws { std::lock_guard lock(m_sharedStateLock); return Aws::Crt::MakeShared( - m_allocator, m_allocator, m_sharedState.m_underlyingConnection); + m_allocator, m_allocator, m_bootstrap, m_sharedState.m_underlyingConnection); } } /* namespace Eventstreamrpc */ diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index 08dedfecb..3d7e02e82 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -30,6 +30,7 @@ file(GLOB TESTS ${TEST_HDRS} ${TEST_SRC}) set(TEST_BINARY_NAME ${PROJECT_NAME}-tests) +# Connectivity tests add_test_case(EventStreamClientCreateFailureInvalidHost) add_test_case(EventStreamClientCreateFailureInvalidPort) add_test_case(EventStreamConnectSuccess) @@ -43,6 +44,7 @@ add_test_case(EchoClientCloseWhileConnecting) add_test_case(EchoClientConnectWhileClosing) add_test_case(EchoClientOpenCloseStress) +# Basic non-streaming operation tests add_test_case(EchoClientOperationEchoSuccessString) add_test_case(EchoClientOperationEchoSuccessBoolean) add_test_case(EchoClientOperationEchoSuccessTime) @@ -52,14 +54,37 @@ add_test_case(EchoClientOperationEchoSuccessBlob) add_test_case(EchoClientOperationEchoSuccessStringList) add_test_case(EchoClientOperationEchoSuccessPairList) add_test_case(EchoClientOperationEchoSuccessProductMap) +add_test_case(EchoClientOperationEchoSuccessMultiple) +add_test_case(EchoClientOperationGetAllProductsSuccess) +add_test_case(EchoClientOperationGetAllCustomersSuccess) +add_test_case(EchoClientOperationCauseServiceErrorSuccess) +add_test_case(EchoClientOperationEchoFailureNeverConnected) +add_test_case(EchoClientOperationEchoFailureDisconnected) -#add_test_case(EchoClientOperationEchoSuccessMultiple) -#add_test_case(EchoClientOperationEchoFailureNeverConnected) -#add_test_case(EchoClientOperationEchoFailureDisconnected) +# Non-streaming race condition tests +add_test_case(EchoClientOperationUnactivatedShutdown) +add_test_case(EchoClientOperationUnactivatedClose) +add_test_case(EchoClientOperationUnactivatedCloseDropFuture) +add_test_case(EchoClientOperationActivateActivate) +#add_test_case(EchoClientOperationActivateWaitActivate) +#add_test_case(EchoClientOperationActivateCloseActivate) +#add_test_case(EchoClientOperationActivateClosedActivate) +#add_test_case(EchoClientOperationActivateCloseConnection) +#add_test_case(EchoClientOperationActivateCloseContinuation) +#add_test_case(EchoClientOperationActivateDoubleCloseContinuation) +#add_test_case(EchoClientOperationActivateWaitDoubleCloseContinuation) +#add_test_case(EchoClientOperationActivateWaitCloseContinuationWaitCloseContinuation) +#add_test_case(EchoClientOperationActivateShutdown) +#add_test_case(EchoClientOperationActivateShutdownDropFuture) +#add_test_case(EchoClientOperationActivateWaitCloseShutdown) +#add_test_case(EchoClientOperationActivateWaitCloseShutdownDropFuture) +# streaming echo messages tests +# streaming failure/error tests + +# streaming race condition tests -#add_test_case(StressTestClient) generate_cpp_test_driver(${TEST_BINARY_NAME}) aws_add_sanitizers(${TEST_BINARY_NAME}) target_include_directories(${TEST_BINARY_NAME} PUBLIC diff --git a/eventstream_rpc/tests/EchoTestRpcModel.cpp b/eventstream_rpc/tests/EchoTestRpcModel.cpp index 63d3472c6..567786fe3 100644 --- a/eventstream_rpc/tests/EchoTestRpcModel.cpp +++ b/eventstream_rpc/tests/EchoTestRpcModel.cpp @@ -1034,19 +1034,21 @@ namespace Awstest OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(GetAllProductsResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -1112,19 +1114,21 @@ namespace Awstest OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(CauseServiceErrorResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -1213,19 +1217,21 @@ namespace Awstest OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(CauseStreamServiceToErrorResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -1317,19 +1323,21 @@ namespace Awstest OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(EchoStreamMessagesResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -1401,19 +1409,21 @@ namespace Awstest OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(EchoMessageResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -1478,19 +1488,21 @@ namespace Awstest OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(GetAllCustomersResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index a49fd1332..42be63c5c 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -776,8 +776,6 @@ static int s_TestEchoClientOperationEchoSuccessProductMap(struct aws_allocator * AWS_TEST_CASE(EchoClientOperationEchoSuccessProductMap, s_TestEchoClientOperationEchoSuccessProductMap); -#ifdef NEVER - static int s_TestEchoClientOperationEchoSuccessMultiple(struct aws_allocator *allocator, void *ctx) { ApiHandle apiHandle(allocator); @@ -820,6 +818,98 @@ static int s_TestEchoClientOperationEchoSuccessMultiple(struct aws_allocator *al AWS_TEST_CASE(EchoClientOperationEchoSuccessMultiple, s_TestEchoClientOperationEchoSuccessMultiple); +static int s_DoSimpleRequestWhileConnectedTest( + struct aws_allocator *allocator, + std::function testFunction) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { + ConnectionLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedStatus = client.Connect(lifecycleHandler); + ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); + + return testFunction(testContext, client); + } +} + +static int s_TestEchoClientOperationGetAllProductsSuccess(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestWhileConnectedTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllProducts = client.NewGetAllProducts(); + GetAllProductsRequest getAllProductsRequest; + + auto requestFuture = getAllProducts->Activate(getAllProductsRequest, s_onMessageFlush); + requestFuture.wait(); + auto result = getAllProducts->GetResult().get(); + ASSERT_TRUE(result); + auto response = result.GetOperationResponse(); + ASSERT_NOT_NULL(response); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationGetAllProductsSuccess, s_TestEchoClientOperationGetAllProductsSuccess); + +static int s_TestEchoClientOperationGetAllCustomersSuccess(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestWhileConnectedTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllCustomers = client.NewGetAllCustomers(); + GetAllCustomersRequest getAllCustomersRequest; + + auto requestFuture = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + requestFuture.wait(); + auto result = getAllCustomers->GetResult().get(); + ASSERT_TRUE(result); + auto response = result.GetOperationResponse(); + ASSERT_NOT_NULL(response); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationGetAllCustomersSuccess, s_TestEchoClientOperationGetAllCustomersSuccess); + +static int s_TestEchoClientOperationCauseServiceErrorSuccess(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestWhileConnectedTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto causeServiceError = client.NewCauseServiceError(); + CauseServiceErrorRequest causeServiceErrorRequest; + + auto requestFuture = causeServiceError->Activate(causeServiceErrorRequest, s_onMessageFlush); + requestFuture.wait(); + auto result = causeServiceError->GetResult().get(); + ASSERT_FALSE(result); + ASSERT_NOT_NULL(result.GetOperationError()); + auto error = result.GetOperationError(); + const auto &errorMessage = error->GetMessage().value(); + ASSERT_TRUE(errorMessage == "Intentionally thrown ServiceError"); + const auto &modelName = error->GetModelName(); + ASSERT_TRUE(modelName == "awstest#ServiceError"); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationCauseServiceErrorSuccess, s_TestEchoClientOperationCauseServiceErrorSuccess); + static int s_TestEchoClientOperationEchoFailureNeverConnected(struct aws_allocator *allocator, void *ctx) { ApiHandle apiHandle(allocator); @@ -844,7 +934,7 @@ static int s_TestEchoClientOperationEchoFailureNeverConnected(struct aws_allocat auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_CLOSED, requestFuture.get().baseStatus); - auto result = echoMessage->GetOperationResult().get(); + auto result = echoMessage->GetResult().get(); ASSERT_FALSE(result); auto error = result.GetRpcError(); @@ -882,13 +972,15 @@ static int s_TestEchoClientOperationEchoFailureDisconnected(struct aws_allocator echoMessageRequest.SetMessage(messageData); auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_CLOSED, requestFuture.get().baseStatus); + auto activateStatus = requestFuture.get().baseStatus; + ASSERT_TRUE( + activateStatus == EVENT_STREAM_RPC_CONNECTION_CLOSED || activateStatus == EVENT_STREAM_RPC_CRT_ERROR); - auto result = echoMessage->GetOperationResult().get(); + auto result = echoMessage->GetResult().get(); ASSERT_FALSE(result); - auto error = result.GetRpcError(); - ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_CLOSED, error.baseStatus); + auto resultStatus = result.GetRpcError().baseStatus; + ASSERT_TRUE(resultStatus == EVENT_STREAM_RPC_CONNECTION_CLOSED || resultStatus == EVENT_STREAM_RPC_CRT_ERROR); } return AWS_OP_SUCCESS; @@ -896,6 +988,128 @@ static int s_TestEchoClientOperationEchoFailureDisconnected(struct aws_allocator AWS_TEST_CASE(EchoClientOperationEchoFailureDisconnected, s_TestEchoClientOperationEchoFailureDisconnected); +static int s_DoSimpleRequestRaceCheckTest( + struct aws_allocator *allocator, + std::function testFunction) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { + ConnectionLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedStatus = client.Connect(lifecycleHandler); + ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); + + for (size_t i = 0; i < 1000; ++i) + { + ASSERT_SUCCESS(testFunction(testContext, client)); + } + + return AWS_OP_SUCCESS; + } +} + +static int s_TestEchoClientOperationUnactivatedShutdown(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto echoMessage = client.NewEchoMessage(); + + // Drop the operation, invoking shutdown + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationUnactivatedShutdown, s_TestEchoClientOperationUnactivatedShutdown); + +static int s_TestEchoClientOperationUnactivatedClose(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto echoMessage = client.NewEchoMessage(); + + auto closeFuture = echoMessage->Close(); + auto closeStatus = closeFuture.get().baseStatus; + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONTINUATION_CLOSED, closeStatus); + + // Drop the operation, invoking shutdown + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationUnactivatedClose, s_TestEchoClientOperationUnactivatedClose); + +static int s_TestEchoClientOperationUnactivatedCloseDropFuture(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto echoMessage = client.NewEchoMessage(); + + auto closeFuture = echoMessage->Close(); + + // Drop the operation and the close future, invoking shutdown + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationUnactivatedCloseDropFuture, s_TestEchoClientOperationUnactivatedCloseDropFuture); + +static int s_TestEchoClientOperationActivateActivate(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllCustomers = client.NewGetAllCustomers(); + GetAllCustomersRequest getAllCustomersRequest; + + auto requestFuture = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + // auto requestFuture2 = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + // requestFuture2.wait(); + requestFuture.wait(); + auto result = getAllCustomers->GetResult().get(); + ASSERT_TRUE(result); + auto response = result.GetOperationResponse(); + ASSERT_NOT_NULL(response); + + // auto flush2ErrorStatus = requestFuture2.get().baseStatus; + // ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED, flush2ErrorStatus); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationActivateActivate, s_TestEchoClientOperationActivateActivate); + +// Non-streaming race condition tests +// add_test_case(EchoClientOperationActivateActivate) +// add_test_case(EchoClientOperationActivateWaitActivate) +// add_test_case(EchoClientOperationActivateCloseActivate) +// add_test_case(EchoClientOperationActivateClosedActivate) +// add_test_case(EchoClientOperationActivateCloseConnection) +// add_test_case(EchoClientOperationActivateCloseContinuation) +// add_test_case(EchoClientOperationActivateDoubleCloseContinuation) +// add_test_case(EchoClientOperationActivateWaitDoubleCloseContinuation) +// add_test_case(EchoClientOperationActivateWaitCloseContinuationWaitCloseContinuation) +// add_test_case(EchoClientOperationActivateShutdown) +// add_test_case(EchoClientOperationActivateShutdownDropFuture) +// add_test_case(EchoClientOperationActivateWaitCloseShutdown) +// add_test_case(EchoClientOperationActivateWaitCloseShutdownDropFuture) + +#ifdef NEVER + AWS_TEST_CASE_FIXTURE(EchoOperation, s_testSetup, s_TestEchoOperation, s_testTeardown, &s_testContext); static int s_TestEchoOperation(struct aws_allocator *allocator, void *ctx) { diff --git a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h index 19cdc201c..1fb4b3b66 100644 --- a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h +++ b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h @@ -745,6 +745,9 @@ namespace Awstest private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -818,6 +821,9 @@ namespace Awstest private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -955,6 +961,9 @@ namespace Awstest private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -1080,6 +1089,9 @@ namespace Awstest private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -1152,6 +1164,9 @@ namespace Awstest private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -1224,6 +1239,9 @@ namespace Awstest private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ diff --git a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h index c569872ce..8cdba9b4d 100644 --- a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h +++ b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h @@ -4546,6 +4546,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -4619,6 +4622,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -4692,6 +4698,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -4828,6 +4837,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -4901,6 +4913,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -4974,6 +4989,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -5049,6 +5067,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -5179,6 +5200,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -5252,6 +5276,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -5395,6 +5422,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -5468,6 +5498,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -5544,6 +5577,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -5617,6 +5653,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -5763,6 +5802,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -5839,6 +5881,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -5915,6 +5960,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -5988,6 +6036,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -6061,6 +6112,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -6134,6 +6188,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -6210,6 +6267,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -6283,6 +6343,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -6356,6 +6419,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -6432,6 +6498,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -6505,6 +6574,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -6581,6 +6653,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -6654,6 +6729,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -6726,6 +6804,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -6801,6 +6882,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -6877,6 +6961,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -7013,6 +7100,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -7088,6 +7178,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -7161,6 +7254,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -7234,6 +7330,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ @@ -7309,6 +7408,9 @@ namespace Aws private: std::promise m_resultPromise; + /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ + std::mutex m_selfReferenceLock; + /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function * object that handles the result. If we did not do this, we risk a crash if the user drops their reference * before the future gets completed. */ diff --git a/greengrass_ipc/source/GreengrassCoreIpcModel.cpp b/greengrass_ipc/source/GreengrassCoreIpcModel.cpp index 1bff67566..c39dfddfc 100644 --- a/greengrass_ipc/source/GreengrassCoreIpcModel.cpp +++ b/greengrass_ipc/source/GreengrassCoreIpcModel.cpp @@ -7058,19 +7058,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(SubscribeToIoTCoreResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -7136,19 +7138,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(ResumeComponentResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -7214,19 +7218,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(PublishToIoTCoreResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -7323,19 +7329,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(SubscribeToConfigurationUpdateResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -7401,19 +7409,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(DeleteThingShadowResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -7479,19 +7489,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(PutComponentMetricResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -7557,19 +7569,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(DeferComponentUpdateResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -7663,20 +7677,22 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value( SubscribeToValidateConfigurationUpdatesResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -7742,19 +7758,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(GetConfigurationResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -7856,19 +7874,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(SubscribeToTopicResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -7934,19 +7954,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(GetComponentDetailsResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -8012,19 +8034,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(GetClientDeviceAuthTokenResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -8090,19 +8114,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(PublishToTopicResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -8205,19 +8231,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(SubscribeToCertificateUpdatesResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -8283,19 +8311,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(VerifyClientDeviceIdentityResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -8361,19 +8391,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(AuthorizeClientDeviceActionResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -8439,19 +8471,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(ListComponentsResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -8517,19 +8551,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(CreateDebugPasswordResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -8595,19 +8631,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(GetThingShadowResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -8674,19 +8712,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(SendConfigurationValidityReportResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -8752,19 +8792,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(UpdateThingShadowResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -8830,19 +8872,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(UpdateConfigurationResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -8908,19 +8952,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(ValidateAuthorizationTokenResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -8986,19 +9032,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(RestartComponentResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -9064,19 +9112,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(GetLocalDeploymentStatusResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -9142,19 +9192,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(GetSecretValueResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -9219,19 +9271,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(UpdateStateResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -9297,19 +9351,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(CancelLocalDeploymentResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -9375,19 +9431,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(ListNamedShadowsForThingResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -9484,19 +9542,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(SubscribeToComponentUpdatesResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -9562,19 +9622,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(ListLocalDeploymentsResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -9640,19 +9702,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(StopComponentResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -9718,19 +9782,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(PauseComponentResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } @@ -9796,19 +9862,21 @@ namespace Aws OnMessageFlushCallback onMessageFlushCallback) noexcept { bool synchronousSuccess = false; - m_selfReference = shared_from_this(); + std::lock_guard selfReferenceLock(m_selfReferenceLock); auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), [this](TaggedResult &&unmodeledResult) { + std::lock_guard selfReferenceLock(m_selfReferenceLock); m_resultPromise.set_value(CreateLocalDeploymentResult(std::move(unmodeledResult))); m_selfReference = nullptr; }, synchronousSuccess); - if (!synchronousSuccess) + if (synchronousSuccess) { - m_selfReference = nullptr; + m_selfReference = shared_from_this(); + ; } return activateFuture; } From b4342492ca5e703f111e4741826a8baf2c6115fa Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Fri, 13 Jun 2025 14:02:11 -0700 Subject: [PATCH 41/56] Full synthetic callback solution --- .../aws/eventstreamrpc/EventStreamClient.h | 137 +-- eventstream_rpc/source/EventStreamClient.cpp | 693 ++++++++------- eventstream_rpc/tests/CMakeLists.txt | 9 +- eventstream_rpc/tests/EchoTestRpcModel.cpp | 144 +-- .../tests/EventStreamClientTest.cpp | 185 +++- .../tests/include/awstest/EchoTestRpcModel.h | 81 +- .../aws/greengrass/GreengrassCoreIpcModel.h | 475 ++-------- .../source/GreengrassCoreIpcModel.cpp | 818 ++++++------------ 8 files changed, 971 insertions(+), 1571 deletions(-) diff --git a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h index 59517d3ab..4bdbe0f2c 100644 --- a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h +++ b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h @@ -10,20 +10,13 @@ #include #include #include -#include -#include #include #include -#include - #include -#include -#include #include #include -#include namespace Aws { @@ -306,28 +299,6 @@ namespace Aws std::shared_ptr m_impl; }; -#ifdef NEVER - /** - * User data passed to callbacks for a new stream. - */ - class AWS_EVENTSTREAMRPC_API ContinuationCallbackData - { - public: - ContinuationCallbackData( - ClientContinuation *clientContinuation, - Crt::Allocator *allocator = Crt::g_allocator) noexcept - : clientContinuation(clientContinuation), allocator(allocator) - { - continuationDestroyed = false; - } - ContinuationCallbackData(const ContinuationCallbackData &lhs) noexcept = delete; - bool continuationDestroyed; - std::mutex callbackMutex; - ClientContinuation *clientContinuation; - Crt::Allocator *allocator; - }; -#endif - /** * Vestigial, do-nothing class that remains for backwards compatibility with the * original, publicly-visible class hierarchy. @@ -335,114 +306,9 @@ namespace Aws class AWS_EVENTSTREAMRPC_API ClientContinuationHandler { public: -#ifdef NEVER - /** - * Invoked when a message is received on this continuation. - */ - virtual void OnContinuationMessage( - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags) = 0; - /** - * Invoked when the continuation is closed. - * - * Once the continuation is closed, no more messages may be sent or received. - * The continuation is closed when a message is sent or received with - * the TERMINATE_STREAM flag, or when the connection shuts down. - */ - virtual void OnContinuationClosed() = 0; -#endif virtual ~ClientContinuationHandler() noexcept = default; -#ifdef NEVER - private: - friend class ClientContinuation; - std::shared_ptr m_callbackData; -#endif }; -#ifdef NEVER - /** - * A wrapper for event-stream-rpc client continuation. - */ - class AWS_EVENTSTREAMRPC_API ClientContinuation final - { - public: - /** - * Create a new continuation. - * - * @note continuation_option's callbacks will not be invoked, and nothing will be sent across - * the wire until Activate() is invoked. - * @param connection Connection on which open a new stream. - * @param continuationHandler A set of callbacks that will be invoked for continuation events. - * @param allocator Allocator to use. - */ - ClientContinuation( - struct aws_event_stream_rpc_client_connection *connection, - ClientContinuationHandler &continuationHandler, - Crt::Allocator *allocator) noexcept; - ~ClientContinuation() noexcept; - - /** - * Initiate a new client stream. Send new message for the new stream. - * @param operation Name for the operation to be invoked by the peer endpoint. - * @param headers Headers for the eventstream message. - * @param payload Payload for the eventstream message. - * @param messageType Message type for the message. - * @param messageFlags Bitmask of aws_event_stream_rpc_message_flag values. - * @param onMessageFlushCallback Callback to be invoked upon the message being flushed to the underlying - * transport. - * @return Future that will be resolved when the message has either been written to the wire or it fails. - */ - std::future Activate( - const Crt::String &operation, - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags, - OnMessageFlushCallback onMessageFlushCallback) noexcept; - - /** - * Check if the continuation has been closed. - * @return True if the continuation has been closed, false otherwise. - */ - bool IsClosed() noexcept; - - /** - * Send message on the continuation. - * @param headers List of additional event stream headers to include on the message. - * @param payload Message payload. - * @param messageType Message type for the message. - * @param messageFlags Bitmask of aws_event_stream_rpc_message_flag values. - * @param onMessageFlushCallback Callback to be invoked upon the message being flushed to the underlying - * transport. - * @return Future that will be resolved when the message has either been written to the wire or it fails. - */ - std::future SendMessage( - const Crt::List &headers, - const Crt::Optional &payload, - MessageType messageType, - uint32_t messageFlags, - OnMessageFlushCallback onMessageFlushCallback) noexcept; - - private: - friend class ClientOperation; - Crt::Allocator *m_allocator; - ClientContinuationHandler &m_continuationHandler; - struct aws_event_stream_rpc_client_continuation_token *m_continuationToken; - std::shared_ptr m_callbackData; - - void Release(); - - static void s_onContinuationMessage( - struct aws_event_stream_rpc_client_continuation_token *continuationToken, - const struct aws_event_stream_rpc_message_args *messageArgs, - void *userData) noexcept; - static void s_onContinuationClosed( - struct aws_event_stream_rpc_client_continuation_token *continuationToken, - void *userData) noexcept; - }; -#endif /** * Base class for types used by operations. */ @@ -722,8 +588,7 @@ namespace Aws std::future Activate( const AbstractShapeBase *shape, OnMessageFlushCallback &&onMessageFlushCallback, - std::function &&onResultCallback, - bool &synchronousSuccess) noexcept; + std::function &&onResultCallback) noexcept; /** * Sends a message on the stream diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 196370a34..5273b60f9 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -23,32 +23,12 @@ namespace Aws { namespace Eventstreamrpc { - static void s_deleteMessageCallbackContainer(void *); - - /* - * This structure has evolved into a more complex form in order to support some additional requirements - * in the eventstream refactor. - * - * In order to maintain behavioral compatibility while removing blocking destruction, we need to be able to - * synchronously "cancel" pending callbacks/completions at the C++ level. The easiest way to accomplish - * this is by ref-counting the structure (so both the C++ and C continuations can reference it) and using - * a lock + completion state to control whether or not the completion actually happens (first one wins). - * - * Because C callbacks are just function pointers, using shared_ptrs is difficult/awkward. So instead we - * just use the C pattern of an internal ref-count that deletes on dropping to zero. - * - * We also want to support tracking the whole set of pending callbacks so that we can cancel them all - * at once while still efficiently completing then one-at-a-time, hence the intrusive linked list node. The - * linked list node is not always used (for example, the connect message callback is not added to any list). - */ class OnMessageFlushCallbackContainer { public: OnMessageFlushCallbackContainer(Crt::Allocator *allocator, OnMessageFlushCallback &&flushCallback) - : m_allocator(allocator), m_refCount({}), m_sharedState({}) + : m_sharedState({}) { - aws_ref_count_init(&m_refCount, this, s_deleteMessageCallbackContainer); - aws_ref_count_acquire(&m_refCount); // always start at 2, one for C++, one for C m_sharedState.m_state = CallbackState::Incomplete; m_sharedState.m_onMessageFlushCallback = std::move(flushCallback); } @@ -103,18 +83,6 @@ namespace Aws } } - static void Release(OnMessageFlushCallbackContainer *callback) - { - if (callback == nullptr) - { - return; - } - - aws_ref_count_release(&callback->m_refCount); - } - - Aws::Crt::Allocator *GetAllocator() const { return m_allocator; } - private: enum class CallbackState { @@ -122,9 +90,6 @@ namespace Aws Finished }; - Crt::Allocator *m_allocator; - struct aws_ref_count m_refCount; - std::mutex m_sharedStateLock; struct { @@ -134,20 +99,56 @@ namespace Aws } m_sharedState; }; - static void s_deleteMessageCallbackContainer(void *object) + class OnMessageFlushCallbackContainerWrapper { - auto container = reinterpret_cast(object); + public: + OnMessageFlushCallbackContainerWrapper(Crt::Allocator *allocator, OnMessageFlushCallback &&flushCallback) + : m_allocator(allocator), m_container(Aws::Crt::MakeShared( + allocator, + allocator, + std::move(flushCallback))) + { + } - Aws::Crt::Delete(container, container->GetAllocator()); - } + OnMessageFlushCallbackContainerWrapper( + Crt::Allocator *allocator, + OnMessageFlushCallback &&flushCallback, + std::promise &&flushPromise) + : m_allocator(allocator), m_container(Aws::Crt::MakeShared( + allocator, + allocator, + std::move(flushCallback), + std::move(flushPromise))) + { + } + + ~OnMessageFlushCallbackContainerWrapper() = default; + + static void Complete(OnMessageFlushCallbackContainerWrapper *wrapper, RpcError error) + { + if (wrapper == nullptr) + { + return; + } + + OnMessageFlushCallbackContainer::Complete(wrapper->GetContainer().get(), error); + } + + std::shared_ptr GetContainer() const { return m_container; } + Crt::Allocator *GetAllocator() { return m_allocator; } + + private: + Crt::Allocator *m_allocator; + std::shared_ptr m_container; + }; static void s_protocolMessageCallback(int errorCode, void *userData) noexcept { - auto *callbackData = static_cast(userData); + auto *wrapper = static_cast(userData); auto rpcStatus = (errorCode == AWS_ERROR_SUCCESS) ? EVENT_STREAM_RPC_SUCCESS : EVENT_STREAM_RPC_CRT_ERROR; - OnMessageFlushCallbackContainer::Complete(callbackData, {rpcStatus, errorCode}); - OnMessageFlushCallbackContainer::Release(callbackData); + OnMessageFlushCallbackContainerWrapper::Complete(wrapper, {rpcStatus, errorCode}); + Aws::Crt::Delete(wrapper, wrapper->GetAllocator()); } MessageAmendment::MessageAmendment(Crt::Allocator *allocator) noexcept @@ -490,11 +491,14 @@ namespace Aws * 1. No callback is made while a lock is held. We perform callbacks by having a transactional callback context * that is moved out of shared state (under the lock), but the callback context does not perform its work until * the lock is released. - * 2. No destructor blocking or synchronization. In order to provide the best behavioral backwards + * 2. No C API call is made while the lock is held. TODO: explain the pattern + * Lock-OptimisticExclusiveStateChange-Unlock-APICall-OnFailureUndoStateChange + * + * 3. No destructor blocking or synchronization. In order to provide the best behavioral backwards * compatibility, we "synthesize" the callbacks that would occur at destruction when we kick off the async - * cleanup process. When the asynchronous events occur that would normally trigger a callback occur, we ignore - * them via the has_shut_down flag. - * 3. A self-reference (via shared_ptr member) guarantees the binding impl stays alive longer than the C + * cleanup process. Later, when the asynchronous events occur that would normally trigger a callback occur, we + * ignore them. + * 4. A self-reference (via shared_ptr member) guarantees the binding impl stays alive longer than the C * objects. The public binding object also keeps a shared_ptr to the impl, so final destruction only occurs * once both the public binding object's destructor has run and no C connection object is still alive. */ @@ -567,18 +571,27 @@ namespace Aws { if (m_error.crtError != AWS_ERROR_SUCCESS) { - (void)m_errorCallback(m_error); + if (m_errorCallback) + { + (void)m_errorCallback(m_error); + } } else { - m_connectionSuccessCallback(); + if (m_connectionSuccessCallback) + { + m_connectionSuccessCallback(); + } } m_connectPromise.set_value(m_error); break; } case ConnectionCallbackActionType::DisconnectionCallback: { - m_disconnectionCallback(m_error); + if (m_disconnectionCallback) + { + m_disconnectionCallback(m_error); + } break; } default: @@ -657,7 +670,9 @@ namespace Aws void CloseInternal(bool isShutdown) noexcept; void MoveToDisconnected(RpcError error) noexcept; - int SendConnectMessage(OnMessageFlushCallback &&onMessageFlushCallback) noexcept; + void ConstructConnectMessage( + struct aws_event_stream_rpc_message_args *msg_args, + struct aws_array_list *headersArray) noexcept; enum class ClientState { @@ -684,7 +699,7 @@ namespace Aws ClientState m_currentState; ClientState m_desiredState; ConnectionCallbackContext m_callbackContext; - OnMessageFlushCallbackContainer *m_connectFlushContainer; + std::shared_ptr m_connectFlushContainer; bool m_hasShutDown; } m_sharedState; @@ -759,12 +774,13 @@ namespace Aws m_sharedState.m_currentState = ClientState::Disconnected; m_sharedState.m_desiredState = ClientState::Disconnected; m_sharedState.m_callbackContext.SetError(error); - m_selfReference = nullptr; + m_selfReference = nullptr; // impossible to drop, since the clear shared task just took a ref if (!m_sharedState.m_hasShutDown) { localContext = std::move(m_sharedState.m_callbackContext); } m_sharedState.m_callbackContext = {}; + m_sharedState.m_connectFlushContainer = nullptr; } localContext.InvokeCallbacks(); @@ -773,8 +789,9 @@ namespace Aws void ClientConnectionImpl::CloseInternal(bool isShutdown) noexcept { + struct aws_event_stream_rpc_client_connection *closeConnection = nullptr; ConnectionCallbackContext localContext = {}; - OnMessageFlushCallbackContainer *connectFlushContainer = nullptr; + std::shared_ptr connectFlushContainer = nullptr; { std::lock_guard lock(m_sharedStateLock); m_sharedState.m_desiredState = ClientState::Disconnected; @@ -789,8 +806,8 @@ namespace Aws m_sharedState.m_currentState == ClientState::PendingConnack) { m_sharedState.m_currentState = ClientState::Disconnecting; - aws_event_stream_rpc_client_connection_close( - m_sharedState.m_underlyingConnection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); + closeConnection = m_sharedState.m_underlyingConnection; + aws_event_stream_rpc_client_connection_acquire(closeConnection); } if (isShutdown) @@ -804,9 +821,15 @@ namespace Aws localContext.InvokeCallbacks(); OnMessageFlushCallbackContainer::Complete( - connectFlushContainer, + connectFlushContainer.get(), {EVENT_STREAM_RPC_CONNECTION_CLOSED, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED}); - OnMessageFlushCallbackContainer::Release(connectFlushContainer); + + if (closeConnection != nullptr) + { + aws_event_stream_rpc_client_connection_close( + closeConnection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); + aws_event_stream_rpc_client_connection_release(closeConnection); + } } void ClientConnectionImpl::Shutdown() noexcept @@ -823,23 +846,22 @@ namespace Aws const ConnectionConfig &connectionConfig, ConnectionLifecycleHandler *connectionLifecycleHandler) noexcept { + std::promise localPromise; + std::future localFuture = localPromise.get_future(); + EventStreamRpcStatusCode status = connectionConfig.Validate(); if (status != EVENT_STREAM_RPC_SUCCESS) { - std::promise localPromise; localPromise.set_value({status, AWS_ERROR_INVALID_ARGUMENT}); - - return localPromise.get_future(); + return localFuture; } - std::future localFuture = {}; { std::lock_guard lock(m_sharedStateLock); if (m_sharedState.m_currentState != ClientState::Disconnected) { - std::promise localPromise; localPromise.set_value({EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED, AWS_ERROR_SUCCESS}); - return localPromise.get_future(); + return localFuture; } m_lifecycleHandler = connectionLifecycleHandler; @@ -894,69 +916,31 @@ namespace Aws return m_sharedState.m_currentState == ClientState::Connected; } - int ClientConnectionImpl::SendConnectMessage(OnMessageFlushCallback &&onMessageFlushCallback) noexcept + void ClientConnectionImpl::ConstructConnectMessage( + struct aws_event_stream_rpc_message_args *msg_args, + struct aws_array_list *headersArray) noexcept { MessageAmendment messageAmendment; + // The version header is necessary for establishing the connection. + messageAmendment.AddHeader(EventStreamHeader( + Crt::String(EVENTSTREAM_VERSION_HEADER), Crt::String(EVENTSTREAM_VERSION_STRING), m_allocator)); + if (m_connectionConfig.GetConnectAmendment().has_value()) { MessageAmendment connectAmendment(m_connectionConfig.GetConnectAmendment().value()); - // The version header is necessary for establishing the connection. - messageAmendment.AddHeader(EventStreamHeader( - Crt::String(EVENTSTREAM_VERSION_HEADER), Crt::String(EVENTSTREAM_VERSION_STRING), m_allocator)); messageAmendment.PrependHeaders(std::move(connectAmendment).GetHeaders()); messageAmendment.SetPayload(std::move(connectAmendment).GetPayload()); } - struct aws_array_list headersArray; + s_fillNativeHeadersArray(messageAmendment.GetHeaders(), headersArray, m_allocator); - s_fillNativeHeadersArray(messageAmendment.GetHeaders(), &headersArray, m_allocator); - struct aws_event_stream_rpc_message_args msg_args; - msg_args.headers = (struct aws_event_stream_header_value_pair *)headersArray.data; - msg_args.headers_count = messageAmendment.GetHeaders().size(); - msg_args.payload = messageAmendment.GetPayload().has_value() - ? (aws_byte_buf *)(&(messageAmendment.GetPayload().value())) - : nullptr; - msg_args.message_type = AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_CONNECT; - msg_args.message_flags = 0U; - - // It shouldn't be possible to interrupt a connect with another connect, but let's handle that case anyways - OnMessageFlushCallbackContainer::Complete( - m_sharedState.m_connectFlushContainer, {EVENT_STREAM_RPC_CONNECTION_SETUP_FAILED, AWS_ERROR_SUCCESS}); - OnMessageFlushCallbackContainer::Release(m_sharedState.m_connectFlushContainer); - - m_sharedState.m_connectFlushContainer = - Crt::New(m_allocator, m_allocator, std::move(onMessageFlushCallback)); - - int errorCode = AWS_ERROR_SUCCESS; - if (aws_event_stream_rpc_client_connection_send_protocol_message( - m_sharedState.m_underlyingConnection, - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(m_sharedState.m_connectFlushContainer))) - { - errorCode = aws_last_error(); - } - - /* Cleanup. */ - if (aws_array_list_is_valid(&headersArray)) - { - aws_array_list_clean_up(&headersArray); - } - - if (errorCode) - { - AWS_LOGF_ERROR( - AWS_LS_EVENT_STREAM_RPC_CLIENT, - "A CRT error occurred while queueing a message to be sent on the connection: %s", - Crt::ErrorDebugString(errorCode)); - - OnMessageFlushCallbackContainer::Complete( - m_sharedState.m_connectFlushContainer, {EVENT_STREAM_RPC_CRT_ERROR, errorCode}); - OnMessageFlushCallbackContainer::Release(m_sharedState.m_connectFlushContainer); - m_sharedState.m_connectFlushContainer = nullptr; - } - - return (errorCode == AWS_ERROR_SUCCESS) ? AWS_OP_SUCCESS : AWS_OP_ERR; + msg_args->headers = (struct aws_event_stream_header_value_pair *)headersArray->data; + msg_args->headers_count = messageAmendment.GetHeaders().size(); + msg_args->payload = messageAmendment.GetPayload().has_value() + ? (aws_byte_buf *)(&(messageAmendment.GetPayload().value())) + : nullptr; + msg_args->message_type = AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_CONNECT; + msg_args->message_flags = 0U; } void ClientConnectionImpl::s_onConnectionSetup( @@ -972,33 +956,90 @@ namespace Aws return; } + struct aws_event_stream_rpc_client_connection *closeConnection = nullptr; + struct aws_event_stream_rpc_client_connection *connectConnection = nullptr; + OnMessageFlushCallbackContainerWrapper *connectCallbackWrapper = nullptr; + AWS_FATAL_ASSERT(connection != nullptr); { std::lock_guard lock(impl->m_sharedStateLock); AWS_FATAL_ASSERT(impl->m_sharedState.m_currentState == ClientState::PendingConnect); + AWS_FATAL_ASSERT(impl->m_sharedState.m_connectFlushContainer == nullptr); // the channel owns the initial ref; we have to take our own aws_event_stream_rpc_client_connection_acquire(connection); impl->m_sharedState.m_underlyingConnection = connection; + + // we also temporarily take a reference because either closeConnection or clientConnection will + // also hold a local reference outside the lock. Not truly needed in this case due to event loop + // pinning, but do it anyways as a pattern to follow. + aws_event_stream_rpc_client_connection_acquire(connection); + if (impl->m_sharedState.m_desiredState != ClientState::Connected) { AWS_FATAL_ASSERT(impl->m_sharedState.m_desiredState == ClientState::Disconnected); impl->m_sharedState.m_currentState = ClientState::Disconnecting; - aws_event_stream_rpc_client_connection_close( - connection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); - return; + closeConnection = connection; + } + else + { + impl->m_sharedState.m_currentState = ClientState::PendingConnack; + connectConnection = connection; + + auto callback = impl->m_connectionConfig.GetConnectRequestCallback(); + connectCallbackWrapper = Aws::Crt::New( + impl->m_allocator, impl->m_allocator, std::move(callback)); + impl->m_sharedState.m_connectFlushContainer = connectCallbackWrapper->GetContainer(); + } + } + + if (connectConnection) + { + AWS_FATAL_ASSERT(connectCallbackWrapper); + + struct aws_event_stream_rpc_message_args msgArgs; + struct aws_array_list headersArray; + + impl->ConstructConnectMessage(&msgArgs, &headersArray); + + int connectErrorCode = AWS_ERROR_SUCCESS; + if (aws_event_stream_rpc_client_connection_send_protocol_message( + connectConnection, + &msgArgs, + s_protocolMessageCallback, + reinterpret_cast(connectCallbackWrapper))) + { + connectErrorCode = aws_last_error(); + } + + if (aws_array_list_is_valid(&headersArray)) + { + aws_array_list_clean_up(&headersArray); } - impl->m_sharedState.m_currentState = ClientState::PendingConnack; - auto callback = impl->m_connectionConfig.GetConnectRequestCallback(); - if (impl->SendConnectMessage(std::move(callback))) + if (connectErrorCode != AWS_ERROR_SUCCESS) { - impl->m_sharedState.m_callbackContext.SetError({EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}); + std::lock_guard lock(impl->m_sharedStateLock); + + impl->m_sharedState.m_callbackContext.SetError({EVENT_STREAM_RPC_CRT_ERROR, connectErrorCode}); impl->m_sharedState.m_currentState = ClientState::Disconnecting; - aws_event_stream_rpc_client_connection_close( - connection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); + closeConnection = connection; + + impl->m_sharedState.m_connectFlushContainer = nullptr; + Aws::Crt::Delete(connectCallbackWrapper, connectCallbackWrapper->GetAllocator()); + } + else + { + aws_event_stream_rpc_client_connection_release(connectConnection); } } + + if (closeConnection) + { + aws_event_stream_rpc_client_connection_close( + closeConnection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); + aws_event_stream_rpc_client_connection_release(closeConnection); + } } void ClientConnectionImpl::s_onConnectionShutdown( @@ -1020,6 +1061,7 @@ namespace Aws AWS_PRECONDITION(messageArgs != nullptr); (void)connection; + struct aws_event_stream_rpc_client_connection *closeConnection = nullptr; auto *impl = static_cast(userData); switch (messageArgs->message_type) { @@ -1034,25 +1076,33 @@ namespace Aws { if (!impl->m_sharedState.m_hasShutDown) { - impl->m_sharedState.m_callbackContext.SetError( - (successfulAck) ? RpcError{EVENT_STREAM_RPC_CONNECTION_CLOSED, 0} - : RpcError{EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, 0}); + impl->m_sharedState.m_callbackContext.SetError(RpcError{ + successfulAck ? EVENT_STREAM_RPC_CONNECTION_CLOSED + : EVENT_STREAM_RPC_CONNECTION_ACCESS_DENIED, + 0}); } impl->m_sharedState.m_desiredState = ClientState::Disconnected; if (impl->m_sharedState.m_currentState != ClientState::Disconnecting) { impl->m_sharedState.m_currentState = ClientState::Disconnecting; - aws_event_stream_rpc_client_connection_close( - impl->m_sharedState.m_underlyingConnection, - AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); + closeConnection = connection; + aws_event_stream_rpc_client_connection_acquire(closeConnection); } - return; } - - impl->m_sharedState.m_currentState = ClientState::Connected; - localCallbackContext = impl->m_sharedState.m_callbackContext.TransitionToConnected(); + else + { + impl->m_sharedState.m_currentState = ClientState::Connected; + localCallbackContext = impl->m_sharedState.m_callbackContext.TransitionToConnected(); + } } localCallbackContext.InvokeCallbacks(); + + if (closeConnection) + { + aws_event_stream_rpc_client_connection_close( + closeConnection, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED); + aws_event_stream_rpc_client_connection_release(closeConnection); + } break; } @@ -1318,9 +1368,9 @@ namespace Aws ContinuationStateType m_currentState; ContinuationStateType m_desiredState; struct aws_event_stream_rpc_client_continuation_token *m_continuation; - OnMessageFlushCallbackContainer *m_activationCallbackContainer; + std::shared_ptr m_activationCallbackContainer; std::function m_activationResponseCallback; - OnMessageFlushCallbackContainer *m_closeCallbackContainer; + std::shared_ptr m_closeCallbackContainer; }; ContinuationSharedState::ContinuationSharedState() @@ -1339,9 +1389,7 @@ namespace Aws struct aws_event_stream_rpc_client_connection *connection) noexcept; virtual ~ClientContinuationImpl(); - // Called by ClientOperation::~ClientOperation(); the returned future is completed after the - // termination callback of the underlying C continuation - std::future ShutDown() noexcept; + void ShutDown() noexcept; std::future Activate( const Crt::String &operation, @@ -1350,8 +1398,7 @@ namespace Aws MessageType messageType, uint32_t messageFlags, std::function &&onResultCallback, - OnMessageFlushCallback &&onMessageFlushCallback, - bool &synchronousSuccess) noexcept; + OnMessageFlushCallback &&onMessageFlushCallback) noexcept; std::future SendStreamMessage( const Crt::List &headers, @@ -1385,6 +1432,8 @@ namespace Aws void OnMessage(const struct aws_event_stream_rpc_message_args *messageArgs) noexcept; + EventStreamRpcStatusCode GetEmptyContinuationStatusCode() const; + static void s_OnContinuationClosed( struct aws_event_stream_rpc_client_continuation_token *token, void *user_data) noexcept; @@ -1413,7 +1462,17 @@ namespace Aws const OperationModelContext *m_operationModelContext; std::shared_ptr m_streamHandler; - std::promise m_terminationPromise; + /* + * An unfortunate bit of state needed to differentiate between two cases: + * (1) Failure to create the original continuation for any reason + * (2) A fully-closed continuation + * + * We want to differentiate these cases in order to communicate clear error codes when attempting + * to operate on the continuation. + * + * This is always true in case (2) and false in case (1) + */ + bool m_continuationValid; }; ClientOperation::ClientOperation( @@ -1428,9 +1487,8 @@ namespace Aws ClientOperation::~ClientOperation() noexcept { - auto terminationFuture = m_impl->ShutDown(); + m_impl->ShutDown(); m_impl = nullptr; - terminationFuture.get(); } std::future ClientOperation::Close(OnMessageFlushCallback onMessageFlushCallback) noexcept @@ -1451,8 +1509,7 @@ namespace Aws std::future ClientOperation::Activate( const AbstractShapeBase *shape, OnMessageFlushCallback &&onMessageFlushCallback, - std::function &&onResultCallback, - bool &synchronousSuccess) noexcept + std::function &&onResultCallback) noexcept { Crt::List headers; headers.emplace_back(EventStreamHeader( @@ -1470,8 +1527,7 @@ namespace Aws AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE, 0, std::move(onResultCallback), - std::move(onMessageFlushCallback), - synchronousSuccess); + std::move(onMessageFlushCallback)); } std::future ClientOperation::SendStreamMessage( @@ -1500,7 +1556,7 @@ namespace Aws struct aws_client_bootstrap *bootstrap, struct aws_event_stream_rpc_client_connection *connection) noexcept : m_allocator(allocator), m_clientBootstrap(aws_client_bootstrap_acquire(bootstrap)), m_sharedState(), - m_operationModelContext(nullptr) + m_operationModelContext(nullptr), m_continuationValid(true) { if (connection != nullptr) { @@ -1516,6 +1572,7 @@ namespace Aws if (!m_sharedState.m_continuation) { + m_continuationValid = false; m_sharedState.m_currentState = ContinuationStateType::Closed; m_sharedState.m_desiredState = ContinuationStateType::Closed; } @@ -1523,7 +1580,6 @@ namespace Aws ClientContinuationImpl::~ClientContinuationImpl() { - m_terminationPromise.set_value(); aws_client_bootstrap_release(m_clientBootstrap); } @@ -1580,14 +1636,13 @@ namespace Aws aws_event_loop_schedule_task_now(event_loop, &releaseTask->m_task); } - std::future ClientContinuationImpl::ShutDown() noexcept + void ClientContinuationImpl::ShutDown() noexcept { struct aws_event_stream_rpc_client_continuation_token *releaseContinuation = nullptr; -#ifdef NEVER - OnMessageFlushCallbackContainer *closeCallbackContainer = nullptr; - OnMessageFlushCallbackContainer *activationCallbackContainer = nullptr; - std::function activationResponseCallback; -#endif + std::shared_ptr closeCallbackContainer = nullptr; + std::shared_ptr activationCallbackContainer = nullptr; + std::function activationResponseCallback = nullptr; + { std::lock_guard lock(m_sharedStateLock); if (m_sharedState.m_currentState == ContinuationStateType::None) @@ -1597,7 +1652,7 @@ namespace Aws m_sharedState.m_currentState = ContinuationStateType::Closed; m_sharedState.m_desiredState = ContinuationStateType::Closed; } -#ifdef NEVER + activationCallbackContainer = m_sharedState.m_activationCallbackContainer; m_sharedState.m_activationCallbackContainer = nullptr; @@ -1605,10 +1660,9 @@ namespace Aws m_sharedState.m_closeCallbackContainer = nullptr; activationResponseCallback = std::move(m_sharedState.m_activationResponseCallback); - m_sharedState.m_activationResponseCallback = nullptr; // unsure if necessary, let's be sure -#endif + m_sharedState.m_activationResponseCallback = nullptr; } -#ifdef NEVER + if (activationResponseCallback) { activationResponseCallback( @@ -1619,13 +1673,11 @@ namespace Aws * Short-circuit and simulate both activate and close callbacks as necessary. */ OnMessageFlushCallbackContainer::Complete( - activationCallbackContainer, {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); - OnMessageFlushCallbackContainer::Release(activationCallbackContainer); + activationCallbackContainer.get(), {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); OnMessageFlushCallbackContainer::Complete( - closeCallbackContainer, {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); - OnMessageFlushCallbackContainer::Release(closeCallbackContainer); -#endif + closeCallbackContainer.get(), {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); + if (releaseContinuation != nullptr) { ReleaseContinuation(m_allocator, m_clientBootstrap, releaseContinuation); @@ -1634,8 +1686,18 @@ namespace Aws { Close(); } + } - return m_terminationPromise.get_future(); + EventStreamRpcStatusCode ClientContinuationImpl::GetEmptyContinuationStatusCode() const + { + if (m_continuationValid) + { + return EVENT_STREAM_RPC_CONTINUATION_CLOSED; + } + else + { + return EVENT_STREAM_RPC_CONNECTION_CLOSED; + } } std::future ClientContinuationImpl::Activate( @@ -1645,19 +1707,17 @@ namespace Aws MessageType messageType, uint32_t messageFlags, std::function &&onResultCallback, - OnMessageFlushCallback &&onMessageFlushCallback, - bool &synchronousSuccess) noexcept + OnMessageFlushCallback &&onMessageFlushCallback) noexcept { AWS_FATAL_ASSERT(static_cast(onResultCallback)); - int result = AWS_OP_SUCCESS; - synchronousSuccess = false; - struct aws_array_list headersArray; // guaranteed to be zeroed or valid if we reach the end of the function + int result = AWS_OP_ERR; std::promise activationPromise; std::future activationFuture = activationPromise.get_future(); - auto activationContainer = Crt::New( + auto activationContainerWrapper = Crt::New( m_allocator, m_allocator, std::move(onMessageFlushCallback), std::move(activationPromise)); RpcError activationError = {}; + struct aws_event_stream_rpc_client_continuation_token *activateContinuation = nullptr; { std::lock_guard lock(m_sharedStateLock); @@ -1665,37 +1725,12 @@ namespace Aws { if (m_sharedState.m_currentState == ContinuationStateType::None) { - // cleanup requirements mean we can't early out from here on - s_fillNativeHeadersArray(headers, &headersArray, m_allocator); - - struct aws_event_stream_rpc_message_args msg_args; - msg_args.headers = static_cast(headersArray.data); - msg_args.headers_count = headers.size(); - msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; - msg_args.message_type = messageType; - msg_args.message_flags = messageFlags; - - result = aws_event_stream_rpc_client_continuation_activate( - m_sharedState.m_continuation, - Crt::ByteCursorFromCString(operation.c_str()), - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(activationContainer)); - - if (result == AWS_OP_SUCCESS) - { - m_sharedState.m_currentState = ContinuationStateType::PendingActivate; - m_sharedState.m_desiredState = ContinuationStateType::Activated; - - m_sharedState.m_activationCallbackContainer = activationContainer; - activationContainer = nullptr; - m_sharedState.m_activationResponseCallback = std::move(onResultCallback); - synchronousSuccess = true; - } - else - { - activationError = {EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}; - } + activateContinuation = m_sharedState.m_continuation; + aws_event_stream_rpc_client_continuation_acquire(activateContinuation); + m_sharedState.m_currentState = ContinuationStateType::PendingActivate; + m_sharedState.m_desiredState = ContinuationStateType::Activated; + m_sharedState.m_activationCallbackContainer = activationContainerWrapper->GetContainer(); + m_sharedState.m_activationResponseCallback = std::move(onResultCallback); } else { @@ -1708,7 +1743,7 @@ namespace Aws case ContinuationStateType::PendingClose: case ContinuationStateType::Closed: - activationError = {EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}; + activationError = {GetEmptyContinuationStatusCode(), 0}; break; default: @@ -1720,22 +1755,57 @@ namespace Aws else { // null continuation is only if the connection didn't exist at creation time - activationError = {EVENT_STREAM_RPC_CONNECTION_CLOSED, 0}; + activationError = {GetEmptyContinuationStatusCode(), 0}; } } - if (!synchronousSuccess) + if (activateContinuation) { - AWS_FATAL_ASSERT(activationContainer != nullptr); + struct aws_array_list + headersArray; // guaranteed to be zeroed or valid if we reach the end of the function + + // cleanup requirements mean we can't early out from here on + s_fillNativeHeadersArray(headers, &headersArray, m_allocator); + + struct aws_event_stream_rpc_message_args msg_args; + msg_args.headers = static_cast(headersArray.data); + msg_args.headers_count = headers.size(); + msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; + msg_args.message_type = messageType; + msg_args.message_flags = messageFlags; + + result = aws_event_stream_rpc_client_continuation_activate( + activateContinuation, + Crt::ByteCursorFromCString(operation.c_str()), + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(activationContainerWrapper)); + + if (result != AWS_OP_SUCCESS) + { + std::lock_guard lock(m_sharedStateLock); + m_sharedState.m_currentState = ContinuationStateType::None; + m_sharedState.m_desiredState = ContinuationStateType::None; + m_sharedState.m_activationCallbackContainer = nullptr; + m_sharedState.m_activationResponseCallback = nullptr; + + activationError = {EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}; + } - OnMessageFlushCallbackContainer::Complete(activationContainer, activationError); - OnMessageFlushCallbackContainer::Release(activationContainer); - OnMessageFlushCallbackContainer::Release(activationContainer); + if (aws_array_list_is_valid(&headersArray)) + { + aws_array_list_clean_up(&headersArray); + } + + aws_event_stream_rpc_client_continuation_release(activateContinuation); } - if (aws_array_list_is_valid(&headersArray)) + if (result != AWS_OP_SUCCESS) { - aws_array_list_clean_up(&headersArray); + AWS_FATAL_ASSERT(activationContainerWrapper != nullptr); + + OnMessageFlushCallbackContainerWrapper::Complete(activationContainerWrapper, activationError); + Aws::Crt::Delete(activationContainerWrapper, activationContainerWrapper->GetAllocator()); } return activationFuture; @@ -1749,42 +1819,20 @@ namespace Aws OnMessageFlushCallback &&onMessageFlushCallback) { int result = AWS_OP_ERR; - struct aws_array_list headersArray; // guaranteed to be zeroed or valid if we reach the end of the function std::promise sendPromise; std::future sendFuture = sendPromise.get_future(); - auto sendContainer = Crt::New( + auto sendContainerWrapper = Crt::New( m_allocator, m_allocator, std::move(onMessageFlushCallback), std::move(sendPromise)); RpcError sendError = {}; + struct aws_event_stream_rpc_client_continuation_token *sendContinuation = nullptr; { std::lock_guard lock(m_sharedStateLock); if (m_sharedState.m_continuation != nullptr) { if (m_sharedState.m_currentState == ContinuationStateType::Activated) { - // cleanup requirements mean we can't early out from here on - s_fillNativeHeadersArray(headers, &headersArray, m_allocator); - - struct aws_event_stream_rpc_message_args msg_args; - msg_args.headers = static_cast(headersArray.data); - msg_args.headers_count = headers.size(); - msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; - msg_args.message_type = messageType; - msg_args.message_flags = messageFlags; - - result = aws_event_stream_rpc_client_continuation_send_message( - m_sharedState.m_continuation, - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(sendContainer)); - - if (result != AWS_OP_SUCCESS) - { - sendError = {EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}; - } - else - { - OnMessageFlushCallbackContainer::Release(sendContainer); // release our ref - } + sendContinuation = m_sharedState.m_continuation; + aws_event_stream_rpc_client_continuation_acquire(sendContinuation); } else { @@ -1813,16 +1861,41 @@ namespace Aws } } - if (result == AWS_OP_ERR) + if (sendContinuation) { - OnMessageFlushCallbackContainer::Complete(sendContainer, sendError); - OnMessageFlushCallbackContainer::Release(sendContainer); - OnMessageFlushCallbackContainer::Release(sendContainer); + struct aws_array_list headersArray; + s_fillNativeHeadersArray(headers, &headersArray, m_allocator); + + struct aws_event_stream_rpc_message_args msg_args; + msg_args.headers = static_cast(headersArray.data); + msg_args.headers_count = headers.size(); + msg_args.payload = payload.has_value() ? (aws_byte_buf *)(&(payload.value())) : nullptr; + msg_args.message_type = messageType; + msg_args.message_flags = messageFlags; + + result = aws_event_stream_rpc_client_continuation_send_message( + sendContinuation, + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(sendContainerWrapper)); + + if (result != AWS_OP_SUCCESS) + { + sendError = {EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}; + } + + if (aws_array_list_is_valid(&headersArray)) + { + aws_array_list_clean_up(&headersArray); + } + + aws_event_stream_rpc_client_continuation_release(sendContinuation); } - if (aws_array_list_is_valid(&headersArray)) + if (result == AWS_OP_ERR) { - aws_array_list_clean_up(&headersArray); + OnMessageFlushCallbackContainerWrapper::Complete(sendContainerWrapper, sendError); + Aws::Crt::Delete(sendContainerWrapper, sendContainerWrapper->GetAllocator()); } return sendFuture; @@ -1833,38 +1906,27 @@ namespace Aws int closeResult = AWS_OP_ERR; std::promise closePromise; std::future closeFuture = closePromise.get_future(); - auto closeCallbackContainer = Crt::New( + auto closeCallbackContainerWrapper = Crt::New( m_allocator, m_allocator, std::move(onMessageFlushCallback), std::move(closePromise)); RpcError closeError = {}; + struct aws_event_stream_rpc_client_continuation_token *closeContinuation = nullptr; + ContinuationStateType previousState = ContinuationStateType::PendingClose; { std::lock_guard lock(m_sharedStateLock); + previousState = m_sharedState.m_currentState; + if (m_sharedState.m_continuation != nullptr) { if (m_sharedState.m_currentState == ContinuationStateType::PendingActivate || m_sharedState.m_currentState == ContinuationStateType::Activated) { - struct aws_event_stream_rpc_message_args msg_args; - msg_args.headers = nullptr; - msg_args.headers_count = 0; - msg_args.payload = nullptr; - msg_args.message_type = AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE; - msg_args.message_flags = AWS_EVENT_STREAM_RPC_MESSAGE_FLAG_TERMINATE_STREAM; - - closeResult = aws_event_stream_rpc_client_continuation_send_message( - m_sharedState.m_continuation, - &msg_args, - s_protocolMessageCallback, - reinterpret_cast(closeCallbackContainer)); - - if (closeResult == AWS_OP_ERR) - { - closeError = {EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}; - } - else - { - m_sharedState.m_currentState = ContinuationStateType::PendingClose; - } + m_sharedState.m_currentState = ContinuationStateType::PendingClose; + + closeContinuation = m_sharedState.m_continuation; + aws_event_stream_rpc_client_continuation_acquire(closeContinuation); + + m_sharedState.m_closeCallbackContainer = closeCallbackContainerWrapper->GetContainer(); } else { @@ -1885,11 +1947,40 @@ namespace Aws } } + if (closeContinuation) + { + struct aws_event_stream_rpc_message_args msg_args; + msg_args.headers = nullptr; + msg_args.headers_count = 0; + msg_args.payload = nullptr; + msg_args.message_type = AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE; + msg_args.message_flags = AWS_EVENT_STREAM_RPC_MESSAGE_FLAG_TERMINATE_STREAM; + + closeResult = aws_event_stream_rpc_client_continuation_send_message( + closeContinuation, + &msg_args, + s_protocolMessageCallback, + reinterpret_cast(closeCallbackContainerWrapper)); + + if (closeResult == AWS_OP_ERR) + { + closeError = {EVENT_STREAM_RPC_CRT_ERROR, aws_last_error()}; + + std::lock_guard lock(m_sharedStateLock); + m_sharedState.m_closeCallbackContainer = nullptr; + if (m_sharedState.m_currentState != ContinuationStateType::Closed) + { + m_sharedState.m_currentState = previousState; + } + } + + aws_event_stream_rpc_client_continuation_release(closeContinuation); + } + if (closeResult != AWS_OP_SUCCESS) { - OnMessageFlushCallbackContainer::Complete(closeCallbackContainer, closeError); - OnMessageFlushCallbackContainer::Release(closeCallbackContainer); - OnMessageFlushCallbackContainer::Release(closeCallbackContainer); + OnMessageFlushCallbackContainerWrapper::Complete(closeCallbackContainerWrapper, closeError); + Aws::Crt::Delete(closeCallbackContainerWrapper, closeCallbackContainerWrapper->GetAllocator()); } return closeFuture; @@ -1898,8 +1989,8 @@ namespace Aws void ClientContinuationImpl::OnClosed() noexcept { struct aws_event_stream_rpc_client_continuation_token *releaseContinuation = nullptr; - OnMessageFlushCallbackContainer *closeCallbackContainer = nullptr; - OnMessageFlushCallbackContainer *activationCallbackContainer = nullptr; + std::shared_ptr closeCallbackContainer = nullptr; + std::shared_ptr activationCallbackContainer = nullptr; std::function activationResponseCallback; { @@ -1927,12 +2018,10 @@ namespace Aws } OnMessageFlushCallbackContainer::Complete( - activationCallbackContainer, {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); - OnMessageFlushCallbackContainer::Release(activationCallbackContainer); + activationCallbackContainer.get(), {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); OnMessageFlushCallbackContainer::Complete( - closeCallbackContainer, {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); - OnMessageFlushCallbackContainer::Release(closeCallbackContainer); + closeCallbackContainer.get(), {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); ReleaseContinuation(m_allocator, m_clientBootstrap, releaseContinuation); } @@ -2068,23 +2157,34 @@ namespace Aws void ClientContinuationImpl::OnMessage(const struct aws_event_stream_rpc_message_args *messageArgs) noexcept { - std::function activationResultCallback; - MessageResult result; bool isResponse = false; + bool shouldClose = false; + std::function activationResultCallback = nullptr; + { std::lock_guard lock(m_sharedStateLock); isResponse = static_cast(m_sharedState.m_currentState == ContinuationStateType::PendingActivate); + result = DeserializeRawMessage(messageArgs, isResponse); + if (isResponse) { activationResultCallback = std::move(m_sharedState.m_activationResponseCallback); m_sharedState.m_activationResponseCallback = nullptr; - m_sharedState.m_currentState = ContinuationStateType::Activated; + m_sharedState.m_activationCallbackContainer = nullptr; + + if (result.m_statusCode == EVENT_STREAM_RPC_SUCCESS && + result.m_message.value().m_route == EventStreamMessageRoutingType::Response) + { + m_sharedState.m_currentState = ContinuationStateType::Activated; + } + else + { + shouldClose = true; + } } } - result = DeserializeRawMessage(messageArgs, isResponse); - if (activationResultCallback) { if (result.m_statusCode == EVENT_STREAM_RPC_SUCCESS) @@ -2109,23 +2209,30 @@ namespace Aws activationResultCallback(TaggedResult(RpcError{result.m_statusCode, 0})); } } - else if (!isResponse) + + if (!isResponse) { - if (result.m_message.has_value()) + auto streamHandler = m_streamHandler; + if (streamHandler) { - AWS_FATAL_ASSERT(result.m_message.value().m_route == EventStreamMessageRoutingType::Stream); - auto shape = std::move(result.m_message.value().m_shape); - m_streamHandler->OnStreamEvent(std::move(shape)); - } - else - { - bool shouldClose = m_streamHandler->OnStreamError(nullptr, {result.m_statusCode, 0}); - if (shouldClose) + if (result.m_message.has_value()) { - Close(); + AWS_FATAL_ASSERT(result.m_message.value().m_route == EventStreamMessageRoutingType::Stream); + auto shape = std::move(result.m_message.value().m_shape); + + streamHandler->OnStreamEvent(std::move(shape)); + } + else + { + shouldClose = m_streamHandler->OnStreamError(nullptr, {result.m_statusCode, 0}); } } } + + if (shouldClose) + { + Close(); + } } void ClientContinuationImpl::s_OnContinuationClosed( diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index 3d7e02e82..350d78515 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -66,11 +66,10 @@ add_test_case(EchoClientOperationUnactivatedShutdown) add_test_case(EchoClientOperationUnactivatedClose) add_test_case(EchoClientOperationUnactivatedCloseDropFuture) add_test_case(EchoClientOperationActivateActivate) -#add_test_case(EchoClientOperationActivateWaitActivate) -#add_test_case(EchoClientOperationActivateCloseActivate) -#add_test_case(EchoClientOperationActivateClosedActivate) -#add_test_case(EchoClientOperationActivateCloseConnection) -#add_test_case(EchoClientOperationActivateCloseContinuation) +add_test_case(EchoClientOperationActivateWaitActivate) +add_test_case(EchoClientOperationActivateCloseActivate) +add_test_case(EchoClientOperationActivateClosedActivate) +add_test_case(EchoClientOperationActivateCloseConnection) #add_test_case(EchoClientOperationActivateDoubleCloseContinuation) #add_test_case(EchoClientOperationActivateWaitDoubleCloseContinuation) #add_test_case(EchoClientOperationActivateWaitCloseContinuationWaitCloseContinuation) diff --git a/eventstream_rpc/tests/EchoTestRpcModel.cpp b/eventstream_rpc/tests/EchoTestRpcModel.cpp index 567786fe3..2740222bd 100644 --- a/eventstream_rpc/tests/EchoTestRpcModel.cpp +++ b/eventstream_rpc/tests/EchoTestRpcModel.cpp @@ -1018,14 +1018,15 @@ namespace Awstest std::future GetAllProductsOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } GetAllProductsOperation::GetAllProductsOperation( ClientConnection &connection, const GetAllProductsOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -1033,23 +1034,14 @@ namespace Awstest const GetAllProductsRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(GetAllProductsResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(GetAllProductsResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -1098,14 +1090,15 @@ namespace Awstest std::future CauseServiceErrorOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } CauseServiceErrorOperation::CauseServiceErrorOperation( ClientConnection &connection, const CauseServiceErrorOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -1113,23 +1106,14 @@ namespace Awstest const CauseServiceErrorRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(CauseServiceErrorResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(CauseServiceErrorResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -1200,7 +1184,7 @@ namespace Awstest std::future CauseStreamServiceToErrorOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } CauseStreamServiceToErrorOperation::CauseStreamServiceToErrorOperation( @@ -1208,7 +1192,8 @@ namespace Awstest std::shared_ptr streamHandler, const CauseStreamServiceToErrorOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, streamHandler, operationContext, allocator) + : ClientOperation(connection, streamHandler, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -1216,23 +1201,14 @@ namespace Awstest const EchoStreamingRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(CauseStreamServiceToErrorResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(CauseStreamServiceToErrorResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -1306,7 +1282,7 @@ namespace Awstest std::future EchoStreamMessagesOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } EchoStreamMessagesOperation::EchoStreamMessagesOperation( @@ -1314,7 +1290,8 @@ namespace Awstest std::shared_ptr streamHandler, const EchoStreamMessagesOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, streamHandler, operationContext, allocator) + : ClientOperation(connection, streamHandler, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -1322,23 +1299,14 @@ namespace Awstest const EchoStreamingRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(EchoStreamMessagesResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(EchoStreamMessagesResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -1393,14 +1361,15 @@ namespace Awstest std::future EchoMessageOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } EchoMessageOperation::EchoMessageOperation( ClientConnection &connection, const EchoMessageOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -1408,23 +1377,14 @@ namespace Awstest const EchoMessageRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(EchoMessageResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(EchoMessageResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -1472,14 +1432,15 @@ namespace Awstest std::future GetAllCustomersOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } GetAllCustomersOperation::GetAllCustomersOperation( ClientConnection &connection, const GetAllCustomersOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -1487,23 +1448,14 @@ namespace Awstest const GetAllCustomersRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(GetAllCustomersResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(GetAllCustomersResult(std::move(unmodeledResult))); }); + return activateFuture; } diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 42be63c5c..4b44030b8 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -933,12 +933,6 @@ static int s_TestEchoClientOperationEchoFailureNeverConnected(struct aws_allocat auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_CLOSED, requestFuture.get().baseStatus); - - auto result = echoMessage->GetResult().get(); - ASSERT_FALSE(result); - - auto error = result.GetRpcError(); - ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONNECTION_CLOSED, error.baseStatus); } return AWS_OP_SUCCESS; @@ -975,12 +969,6 @@ static int s_TestEchoClientOperationEchoFailureDisconnected(struct aws_allocator auto activateStatus = requestFuture.get().baseStatus; ASSERT_TRUE( activateStatus == EVENT_STREAM_RPC_CONNECTION_CLOSED || activateStatus == EVENT_STREAM_RPC_CRT_ERROR); - - auto result = echoMessage->GetResult().get(); - ASSERT_FALSE(result); - - auto resultStatus = result.GetRpcError().baseStatus; - ASSERT_TRUE(resultStatus == EVENT_STREAM_RPC_CONNECTION_CLOSED || resultStatus == EVENT_STREAM_RPC_CRT_ERROR); } return AWS_OP_SUCCESS; @@ -1076,16 +1064,16 @@ static int s_TestEchoClientOperationActivateActivate(struct aws_allocator *alloc GetAllCustomersRequest getAllCustomersRequest; auto requestFuture = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); - // auto requestFuture2 = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); - // requestFuture2.wait(); + auto requestFuture2 = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + requestFuture2.wait(); requestFuture.wait(); auto result = getAllCustomers->GetResult().get(); ASSERT_TRUE(result); auto response = result.GetOperationResponse(); ASSERT_NOT_NULL(response); - // auto flush2ErrorStatus = requestFuture2.get().baseStatus; - // ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED, flush2ErrorStatus); + auto flush2ErrorStatus = requestFuture2.get().baseStatus; + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED, flush2ErrorStatus); return AWS_OP_SUCCESS; }); @@ -1093,13 +1081,168 @@ static int s_TestEchoClientOperationActivateActivate(struct aws_allocator *alloc AWS_TEST_CASE(EchoClientOperationActivateActivate, s_TestEchoClientOperationActivateActivate); +static int s_TestEchoClientOperationActivateWaitActivate(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllCustomers = client.NewGetAllCustomers(); + GetAllCustomersRequest getAllCustomersRequest; + + auto requestFuture = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + requestFuture.wait(); + auto result = getAllCustomers->GetResult().get(); + ASSERT_TRUE(result); + auto response = result.GetOperationResponse(); + ASSERT_NOT_NULL(response); + + auto requestFuture2 = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + requestFuture2.wait(); + + auto flush2ErrorStatus = requestFuture2.get().baseStatus; + ASSERT_TRUE( + flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED || + flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED || + flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationActivateWaitActivate, s_TestEchoClientOperationActivateWaitActivate); + +static int s_TestEchoClientOperationActivateCloseActivate(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllCustomers = client.NewGetAllCustomers(); + GetAllCustomersRequest getAllCustomersRequest; + + auto requestFuture = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + + auto closeFuture = getAllCustomers->Close(); + + requestFuture.wait(); + auto flushErrorStatus = requestFuture.get().baseStatus; + ASSERT_TRUE( + flushErrorStatus == EVENT_STREAM_RPC_SUCCESS || + flushErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED); + + auto requestFuture2 = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + requestFuture2.wait(); + + auto flush2ErrorStatus = requestFuture2.get().baseStatus; + ASSERT_TRUE( + flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED || + flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED || + flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS); + + closeFuture.wait(); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationActivateCloseActivate, s_TestEchoClientOperationActivateCloseActivate); + +static int s_TestEchoClientOperationActivateClosedActivate(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllCustomers = client.NewGetAllCustomers(); + GetAllCustomersRequest getAllCustomersRequest; + + auto requestFuture = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + + auto closeFuture = getAllCustomers->Close(); + closeFuture.wait(); + + requestFuture.wait(); + auto flushErrorStatus = requestFuture.get().baseStatus; + ASSERT_TRUE( + flushErrorStatus == EVENT_STREAM_RPC_SUCCESS || + flushErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED); + + auto requestFuture2 = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + requestFuture2.wait(); + + auto flush2ErrorStatus = requestFuture2.get().baseStatus; + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONTINUATION_CLOSED, flush2ErrorStatus); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationActivateClosedActivate, s_TestEchoClientOperationActivateClosedActivate); + +static int s_DoClientScopedRaceCheckTest( + struct aws_allocator *allocator, + std::function testFunction) +{ + ApiHandle apiHandle(allocator); + for (size_t i = 0; i < 100; ++i) + { + + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { + ConnectionLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedStatus = client.Connect(lifecycleHandler); + ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); + + ASSERT_SUCCESS(testFunction(testContext, client)); + } + } + + return AWS_OP_SUCCESS; +} + +static int s_TestEchoClientOperationActivateCloseConnection(struct aws_allocator *allocator, void *ctx) +{ + return s_DoClientScopedRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllCustomers = client.NewGetAllCustomers(); + GetAllCustomersRequest getAllCustomersRequest; + + auto requestFuture = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + + client.Close(); + + requestFuture.wait(); + auto flushErrorStatus = requestFuture.get().baseStatus; + ASSERT_TRUE( + flushErrorStatus == EVENT_STREAM_RPC_SUCCESS || flushErrorStatus == EVENT_STREAM_RPC_CONNECTION_CLOSED); + + auto requestFuture2 = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + requestFuture2.wait(); + + auto flush2ErrorStatus = requestFuture2.get().baseStatus; + ASSERT_TRUE( + flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED || + flush2ErrorStatus == EVENT_STREAM_RPC_CONNECTION_CLOSED || + flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationActivateCloseConnection, s_TestEchoClientOperationActivateCloseConnection); + // Non-streaming race condition tests -// add_test_case(EchoClientOperationActivateActivate) -// add_test_case(EchoClientOperationActivateWaitActivate) -// add_test_case(EchoClientOperationActivateCloseActivate) -// add_test_case(EchoClientOperationActivateClosedActivate) // add_test_case(EchoClientOperationActivateCloseConnection) -// add_test_case(EchoClientOperationActivateCloseContinuation) // add_test_case(EchoClientOperationActivateDoubleCloseContinuation) // add_test_case(EchoClientOperationActivateWaitDoubleCloseContinuation) // add_test_case(EchoClientOperationActivateWaitCloseContinuationWaitCloseContinuation) diff --git a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h index 1fb4b3b66..578a14798 100644 --- a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h +++ b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h @@ -718,8 +718,7 @@ namespace Awstest TaggedResult m_taggedResult; }; - class AWS_ECHOTESTRPC_API GetAllProductsOperation : public ClientOperation, - public std::enable_shared_from_this + class AWS_ECHOTESTRPC_API GetAllProductsOperation : public ClientOperation { public: GetAllProductsOperation( @@ -743,15 +742,7 @@ namespace Awstest std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_ECHOTESTRPC_API CauseServiceErrorOperationContext : public OperationModelContext @@ -793,9 +784,7 @@ namespace Awstest TaggedResult m_taggedResult; }; - class AWS_ECHOTESTRPC_API CauseServiceErrorOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_ECHOTESTRPC_API CauseServiceErrorOperation : public ClientOperation { public: CauseServiceErrorOperation( @@ -819,15 +808,7 @@ namespace Awstest std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_ECHOTESTRPC_API CauseStreamServiceToErrorStreamHandler : public StreamResponseHandler @@ -920,9 +901,7 @@ namespace Awstest TaggedResult m_taggedResult; }; - class AWS_ECHOTESTRPC_API CauseStreamServiceToErrorOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_ECHOTESTRPC_API CauseStreamServiceToErrorOperation : public ClientOperation { public: CauseStreamServiceToErrorOperation( @@ -959,15 +938,7 @@ namespace Awstest std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_ECHOTESTRPC_API EchoStreamMessagesStreamHandler : public StreamResponseHandler @@ -1048,9 +1019,7 @@ namespace Awstest TaggedResult m_taggedResult; }; - class AWS_ECHOTESTRPC_API EchoStreamMessagesOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_ECHOTESTRPC_API EchoStreamMessagesOperation : public ClientOperation { public: EchoStreamMessagesOperation( @@ -1087,15 +1056,7 @@ namespace Awstest std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_ECHOTESTRPC_API EchoMessageOperationContext : public OperationModelContext @@ -1137,8 +1098,7 @@ namespace Awstest TaggedResult m_taggedResult; }; - class AWS_ECHOTESTRPC_API EchoMessageOperation : public ClientOperation, - public std::enable_shared_from_this + class AWS_ECHOTESTRPC_API EchoMessageOperation : public ClientOperation { public: EchoMessageOperation( @@ -1162,15 +1122,7 @@ namespace Awstest std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_ECHOTESTRPC_API GetAllCustomersOperationContext : public OperationModelContext @@ -1212,8 +1164,7 @@ namespace Awstest TaggedResult m_taggedResult; }; - class AWS_ECHOTESTRPC_API GetAllCustomersOperation : public ClientOperation, - public std::enable_shared_from_this + class AWS_ECHOTESTRPC_API GetAllCustomersOperation : public ClientOperation { public: GetAllCustomersOperation( @@ -1237,15 +1188,7 @@ namespace Awstest std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_ECHOTESTRPC_API EchoTestRpcServiceModel : public ServiceModel diff --git a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h index 8cdba9b4d..b88cc4c16 100644 --- a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h +++ b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h @@ -4517,9 +4517,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToIoTCoreOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API SubscribeToIoTCoreOperation : public ClientOperation { public: SubscribeToIoTCoreOperation( @@ -4544,15 +4542,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API ResumeComponentOperationContext : public OperationModelContext @@ -4594,9 +4584,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API ResumeComponentOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API ResumeComponentOperation : public ClientOperation { public: ResumeComponentOperation( @@ -4620,15 +4608,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API PublishToIoTCoreOperationContext : public OperationModelContext @@ -4670,9 +4650,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API PublishToIoTCoreOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API PublishToIoTCoreOperation : public ClientOperation { public: PublishToIoTCoreOperation( @@ -4696,15 +4674,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API SubscribeToConfigurationUpdateStreamHandler : public StreamResponseHandler @@ -4808,9 +4778,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToConfigurationUpdateOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API SubscribeToConfigurationUpdateOperation : public ClientOperation { public: SubscribeToConfigurationUpdateOperation( @@ -4835,15 +4803,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API DeleteThingShadowOperationContext : public OperationModelContext @@ -4885,9 +4845,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API DeleteThingShadowOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API DeleteThingShadowOperation : public ClientOperation { public: DeleteThingShadowOperation( @@ -4911,15 +4869,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API PutComponentMetricOperationContext : public OperationModelContext @@ -4961,9 +4911,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API PutComponentMetricOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API PutComponentMetricOperation : public ClientOperation { public: PutComponentMetricOperation( @@ -4987,15 +4935,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API DeferComponentUpdateOperationContext : public OperationModelContext @@ -5039,9 +4979,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API DeferComponentUpdateOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API DeferComponentUpdateOperation : public ClientOperation { public: DeferComponentUpdateOperation( @@ -5065,15 +5003,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API SubscribeToValidateConfigurationUpdatesStreamHandler @@ -5171,9 +5101,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToValidateConfigurationUpdatesOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API SubscribeToValidateConfigurationUpdatesOperation : public ClientOperation { public: SubscribeToValidateConfigurationUpdatesOperation( @@ -5198,15 +5126,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API GetConfigurationOperationContext : public OperationModelContext @@ -5248,9 +5168,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API GetConfigurationOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API GetConfigurationOperation : public ClientOperation { public: GetConfigurationOperation( @@ -5274,15 +5192,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API SubscribeToTopicStreamHandler : public StreamResponseHandler @@ -5393,9 +5303,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToTopicOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API SubscribeToTopicOperation : public ClientOperation { public: SubscribeToTopicOperation( @@ -5420,15 +5328,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API GetComponentDetailsOperationContext : public OperationModelContext @@ -5470,9 +5370,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API GetComponentDetailsOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API GetComponentDetailsOperation : public ClientOperation { public: GetComponentDetailsOperation( @@ -5496,15 +5394,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API GetClientDeviceAuthTokenOperationContext : public OperationModelContext @@ -5549,9 +5439,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API GetClientDeviceAuthTokenOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API GetClientDeviceAuthTokenOperation : public ClientOperation { public: GetClientDeviceAuthTokenOperation( @@ -5575,15 +5463,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API PublishToTopicOperationContext : public OperationModelContext @@ -5625,9 +5505,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API PublishToTopicOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API PublishToTopicOperation : public ClientOperation { public: PublishToTopicOperation( @@ -5651,15 +5529,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API SubscribeToCertificateUpdatesStreamHandler : public StreamResponseHandler @@ -5773,9 +5643,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToCertificateUpdatesOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API SubscribeToCertificateUpdatesOperation : public ClientOperation { public: SubscribeToCertificateUpdatesOperation( @@ -5800,15 +5668,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API VerifyClientDeviceIdentityOperationContext : public OperationModelContext @@ -5853,9 +5713,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API VerifyClientDeviceIdentityOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API VerifyClientDeviceIdentityOperation : public ClientOperation { public: VerifyClientDeviceIdentityOperation( @@ -5879,15 +5737,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API AuthorizeClientDeviceActionOperationContext : public OperationModelContext @@ -5932,9 +5782,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API AuthorizeClientDeviceActionOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API AuthorizeClientDeviceActionOperation : public ClientOperation { public: AuthorizeClientDeviceActionOperation( @@ -5958,15 +5806,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API ListComponentsOperationContext : public OperationModelContext @@ -6008,9 +5848,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API ListComponentsOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API ListComponentsOperation : public ClientOperation { public: ListComponentsOperation( @@ -6034,15 +5872,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API CreateDebugPasswordOperationContext : public OperationModelContext @@ -6084,9 +5914,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API CreateDebugPasswordOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API CreateDebugPasswordOperation : public ClientOperation { public: CreateDebugPasswordOperation( @@ -6110,15 +5938,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API GetThingShadowOperationContext : public OperationModelContext @@ -6160,9 +5980,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API GetThingShadowOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API GetThingShadowOperation : public ClientOperation { public: GetThingShadowOperation( @@ -6186,15 +6004,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API SendConfigurationValidityReportOperationContext : public OperationModelContext @@ -6239,9 +6049,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SendConfigurationValidityReportOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API SendConfigurationValidityReportOperation : public ClientOperation { public: SendConfigurationValidityReportOperation( @@ -6265,15 +6073,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API UpdateThingShadowOperationContext : public OperationModelContext @@ -6315,9 +6115,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API UpdateThingShadowOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API UpdateThingShadowOperation : public ClientOperation { public: UpdateThingShadowOperation( @@ -6341,15 +6139,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API UpdateConfigurationOperationContext : public OperationModelContext @@ -6391,9 +6181,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API UpdateConfigurationOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API UpdateConfigurationOperation : public ClientOperation { public: UpdateConfigurationOperation( @@ -6417,15 +6205,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API ValidateAuthorizationTokenOperationContext : public OperationModelContext @@ -6470,9 +6250,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API ValidateAuthorizationTokenOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API ValidateAuthorizationTokenOperation : public ClientOperation { public: ValidateAuthorizationTokenOperation( @@ -6496,15 +6274,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API RestartComponentOperationContext : public OperationModelContext @@ -6546,9 +6316,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API RestartComponentOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API RestartComponentOperation : public ClientOperation { public: RestartComponentOperation( @@ -6572,15 +6340,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API GetLocalDeploymentStatusOperationContext : public OperationModelContext @@ -6625,9 +6385,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API GetLocalDeploymentStatusOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API GetLocalDeploymentStatusOperation : public ClientOperation { public: GetLocalDeploymentStatusOperation( @@ -6651,15 +6409,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API GetSecretValueOperationContext : public OperationModelContext @@ -6701,9 +6451,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API GetSecretValueOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API GetSecretValueOperation : public ClientOperation { public: GetSecretValueOperation( @@ -6727,15 +6475,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API UpdateStateOperationContext : public OperationModelContext @@ -6777,8 +6517,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API UpdateStateOperation : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API UpdateStateOperation : public ClientOperation { public: UpdateStateOperation( @@ -6802,15 +6541,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API CancelLocalDeploymentOperationContext : public OperationModelContext @@ -6854,9 +6585,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API CancelLocalDeploymentOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API CancelLocalDeploymentOperation : public ClientOperation { public: CancelLocalDeploymentOperation( @@ -6880,15 +6609,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API ListNamedShadowsForThingOperationContext : public OperationModelContext @@ -6933,9 +6654,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API ListNamedShadowsForThingOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API ListNamedShadowsForThingOperation : public ClientOperation { public: ListNamedShadowsForThingOperation( @@ -6959,15 +6678,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API SubscribeToComponentUpdatesStreamHandler : public StreamResponseHandler @@ -7071,9 +6782,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToComponentUpdatesOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API SubscribeToComponentUpdatesOperation : public ClientOperation { public: SubscribeToComponentUpdatesOperation( @@ -7098,15 +6807,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API ListLocalDeploymentsOperationContext : public OperationModelContext @@ -7150,9 +6851,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API ListLocalDeploymentsOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API ListLocalDeploymentsOperation : public ClientOperation { public: ListLocalDeploymentsOperation( @@ -7176,15 +6875,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API StopComponentOperationContext : public OperationModelContext @@ -7226,9 +6917,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API StopComponentOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API StopComponentOperation : public ClientOperation { public: StopComponentOperation( @@ -7252,15 +6941,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API PauseComponentOperationContext : public OperationModelContext @@ -7302,9 +6983,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API PauseComponentOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API PauseComponentOperation : public ClientOperation { public: PauseComponentOperation( @@ -7328,15 +7007,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API CreateLocalDeploymentOperationContext : public OperationModelContext @@ -7380,9 +7051,7 @@ namespace Aws TaggedResult m_taggedResult; }; - class AWS_GREENGRASSCOREIPC_API CreateLocalDeploymentOperation - : public ClientOperation, - public std::enable_shared_from_this + class AWS_GREENGRASSCOREIPC_API CreateLocalDeploymentOperation : public ClientOperation { public: CreateLocalDeploymentOperation( @@ -7406,15 +7075,7 @@ namespace Aws std::future GetResult() noexcept; private: - std::promise m_resultPromise; - - /* Enforces a happens-before relationship between setting the self-reference and clearing it. */ - std::mutex m_selfReferenceLock; - - /* Keeps the operation alive while activation is in-progress. Internally, we capture `this` in the function - * object that handles the result. If we did not do this, we risk a crash if the user drops their reference - * before the future gets completed. */ - std::shared_ptr m_selfReference; + std::shared_ptr> m_resultPromise; }; class AWS_GREENGRASSCOREIPC_API GreengrassCoreIpcServiceModel : public ServiceModel diff --git a/greengrass_ipc/source/GreengrassCoreIpcModel.cpp b/greengrass_ipc/source/GreengrassCoreIpcModel.cpp index c39dfddfc..c20f3a32a 100644 --- a/greengrass_ipc/source/GreengrassCoreIpcModel.cpp +++ b/greengrass_ipc/source/GreengrassCoreIpcModel.cpp @@ -7041,7 +7041,7 @@ namespace Aws std::future SubscribeToIoTCoreOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } SubscribeToIoTCoreOperation::SubscribeToIoTCoreOperation( @@ -7049,7 +7049,8 @@ namespace Aws std::shared_ptr streamHandler, const SubscribeToIoTCoreOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, streamHandler, operationContext, allocator) + : ClientOperation(connection, streamHandler, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -7057,23 +7058,14 @@ namespace Aws const SubscribeToIoTCoreRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(SubscribeToIoTCoreResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(SubscribeToIoTCoreResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -7122,14 +7114,15 @@ namespace Aws std::future ResumeComponentOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } ResumeComponentOperation::ResumeComponentOperation( ClientConnection &connection, const ResumeComponentOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -7137,23 +7130,14 @@ namespace Aws const ResumeComponentRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(ResumeComponentResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(ResumeComponentResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -7202,14 +7186,15 @@ namespace Aws std::future PublishToIoTCoreOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } PublishToIoTCoreOperation::PublishToIoTCoreOperation( ClientConnection &connection, const PublishToIoTCoreOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -7217,23 +7202,14 @@ namespace Aws const PublishToIoTCoreRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(PublishToIoTCoreResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(PublishToIoTCoreResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -7312,7 +7288,7 @@ namespace Aws std::future SubscribeToConfigurationUpdateOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } SubscribeToConfigurationUpdateOperation::SubscribeToConfigurationUpdateOperation( @@ -7320,7 +7296,8 @@ namespace Aws std::shared_ptr streamHandler, const SubscribeToConfigurationUpdateOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, streamHandler, operationContext, allocator) + : ClientOperation(connection, streamHandler, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -7328,23 +7305,14 @@ namespace Aws const SubscribeToConfigurationUpdateRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(SubscribeToConfigurationUpdateResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(SubscribeToConfigurationUpdateResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -7393,14 +7361,15 @@ namespace Aws std::future DeleteThingShadowOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } DeleteThingShadowOperation::DeleteThingShadowOperation( ClientConnection &connection, const DeleteThingShadowOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -7408,23 +7377,14 @@ namespace Aws const DeleteThingShadowRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(DeleteThingShadowResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(DeleteThingShadowResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -7473,14 +7433,15 @@ namespace Aws std::future PutComponentMetricOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } PutComponentMetricOperation::PutComponentMetricOperation( ClientConnection &connection, const PutComponentMetricOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -7488,23 +7449,14 @@ namespace Aws const PutComponentMetricRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(PutComponentMetricResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(PutComponentMetricResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -7553,14 +7505,15 @@ namespace Aws std::future DeferComponentUpdateOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } DeferComponentUpdateOperation::DeferComponentUpdateOperation( ClientConnection &connection, const DeferComponentUpdateOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -7568,23 +7521,14 @@ namespace Aws const DeferComponentUpdateRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(DeferComponentUpdateResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(DeferComponentUpdateResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -7660,7 +7604,7 @@ namespace Aws std::future SubscribeToValidateConfigurationUpdatesOperation:: GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } SubscribeToValidateConfigurationUpdatesOperation::SubscribeToValidateConfigurationUpdatesOperation( @@ -7668,7 +7612,9 @@ namespace Aws std::shared_ptr streamHandler, const SubscribeToValidateConfigurationUpdatesOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, streamHandler, operationContext, allocator) + : ClientOperation(connection, streamHandler, operationContext, allocator), + m_resultPromise( + Aws::Crt::MakeShared>(allocator)) { } @@ -7676,24 +7622,16 @@ namespace Aws const SubscribeToValidateConfigurationUpdatesRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value( + [promiseReference](TaggedResult &&unmodeledResult) { + promiseReference->set_value( SubscribeToValidateConfigurationUpdatesResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + }); + return activateFuture; } @@ -7742,14 +7680,15 @@ namespace Aws std::future GetConfigurationOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } GetConfigurationOperation::GetConfigurationOperation( ClientConnection &connection, const GetConfigurationOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -7757,23 +7696,14 @@ namespace Aws const GetConfigurationRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(GetConfigurationResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(GetConfigurationResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -7857,7 +7787,7 @@ namespace Aws std::future SubscribeToTopicOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } SubscribeToTopicOperation::SubscribeToTopicOperation( @@ -7865,7 +7795,8 @@ namespace Aws std::shared_ptr streamHandler, const SubscribeToTopicOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, streamHandler, operationContext, allocator) + : ClientOperation(connection, streamHandler, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -7873,23 +7804,14 @@ namespace Aws const SubscribeToTopicRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(SubscribeToTopicResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(SubscribeToTopicResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -7938,14 +7860,15 @@ namespace Aws std::future GetComponentDetailsOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } GetComponentDetailsOperation::GetComponentDetailsOperation( ClientConnection &connection, const GetComponentDetailsOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -7953,23 +7876,14 @@ namespace Aws const GetComponentDetailsRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(GetComponentDetailsResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(GetComponentDetailsResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -8018,14 +7932,15 @@ namespace Aws std::future GetClientDeviceAuthTokenOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } GetClientDeviceAuthTokenOperation::GetClientDeviceAuthTokenOperation( ClientConnection &connection, const GetClientDeviceAuthTokenOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -8033,23 +7948,14 @@ namespace Aws const GetClientDeviceAuthTokenRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(GetClientDeviceAuthTokenResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(GetClientDeviceAuthTokenResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -8098,14 +8004,15 @@ namespace Aws std::future PublishToTopicOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } PublishToTopicOperation::PublishToTopicOperation( ClientConnection &connection, const PublishToTopicOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -8113,23 +8020,14 @@ namespace Aws const PublishToTopicRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(PublishToTopicResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(PublishToTopicResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -8214,7 +8112,7 @@ namespace Aws std::future SubscribeToCertificateUpdatesOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } SubscribeToCertificateUpdatesOperation::SubscribeToCertificateUpdatesOperation( @@ -8222,7 +8120,8 @@ namespace Aws std::shared_ptr streamHandler, const SubscribeToCertificateUpdatesOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, streamHandler, operationContext, allocator) + : ClientOperation(connection, streamHandler, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -8230,23 +8129,14 @@ namespace Aws const SubscribeToCertificateUpdatesRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(SubscribeToCertificateUpdatesResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(SubscribeToCertificateUpdatesResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -8295,14 +8185,15 @@ namespace Aws std::future VerifyClientDeviceIdentityOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } VerifyClientDeviceIdentityOperation::VerifyClientDeviceIdentityOperation( ClientConnection &connection, const VerifyClientDeviceIdentityOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -8310,23 +8201,14 @@ namespace Aws const VerifyClientDeviceIdentityRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(VerifyClientDeviceIdentityResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(VerifyClientDeviceIdentityResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -8375,14 +8257,15 @@ namespace Aws std::future AuthorizeClientDeviceActionOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } AuthorizeClientDeviceActionOperation::AuthorizeClientDeviceActionOperation( ClientConnection &connection, const AuthorizeClientDeviceActionOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -8390,23 +8273,14 @@ namespace Aws const AuthorizeClientDeviceActionRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(AuthorizeClientDeviceActionResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(AuthorizeClientDeviceActionResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -8455,14 +8329,15 @@ namespace Aws std::future ListComponentsOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } ListComponentsOperation::ListComponentsOperation( ClientConnection &connection, const ListComponentsOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -8470,23 +8345,14 @@ namespace Aws const ListComponentsRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(ListComponentsResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(ListComponentsResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -8535,14 +8401,15 @@ namespace Aws std::future CreateDebugPasswordOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } CreateDebugPasswordOperation::CreateDebugPasswordOperation( ClientConnection &connection, const CreateDebugPasswordOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -8550,23 +8417,14 @@ namespace Aws const CreateDebugPasswordRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(CreateDebugPasswordResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(CreateDebugPasswordResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -8615,14 +8473,15 @@ namespace Aws std::future GetThingShadowOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } GetThingShadowOperation::GetThingShadowOperation( ClientConnection &connection, const GetThingShadowOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -8630,23 +8489,14 @@ namespace Aws const GetThingShadowRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(GetThingShadowResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(GetThingShadowResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -8696,14 +8546,15 @@ namespace Aws std::future SendConfigurationValidityReportOperation:: GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } SendConfigurationValidityReportOperation::SendConfigurationValidityReportOperation( ClientConnection &connection, const SendConfigurationValidityReportOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -8711,23 +8562,14 @@ namespace Aws const SendConfigurationValidityReportRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(SendConfigurationValidityReportResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(SendConfigurationValidityReportResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -8776,14 +8618,15 @@ namespace Aws std::future UpdateThingShadowOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } UpdateThingShadowOperation::UpdateThingShadowOperation( ClientConnection &connection, const UpdateThingShadowOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -8791,23 +8634,14 @@ namespace Aws const UpdateThingShadowRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(UpdateThingShadowResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(UpdateThingShadowResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -8856,14 +8690,15 @@ namespace Aws std::future UpdateConfigurationOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } UpdateConfigurationOperation::UpdateConfigurationOperation( ClientConnection &connection, const UpdateConfigurationOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -8871,23 +8706,14 @@ namespace Aws const UpdateConfigurationRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(UpdateConfigurationResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(UpdateConfigurationResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -8936,14 +8762,15 @@ namespace Aws std::future ValidateAuthorizationTokenOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } ValidateAuthorizationTokenOperation::ValidateAuthorizationTokenOperation( ClientConnection &connection, const ValidateAuthorizationTokenOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -8951,23 +8778,14 @@ namespace Aws const ValidateAuthorizationTokenRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(ValidateAuthorizationTokenResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(ValidateAuthorizationTokenResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -9016,14 +8834,15 @@ namespace Aws std::future RestartComponentOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } RestartComponentOperation::RestartComponentOperation( ClientConnection &connection, const RestartComponentOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -9031,23 +8850,14 @@ namespace Aws const RestartComponentRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(RestartComponentResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(RestartComponentResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -9096,14 +8906,15 @@ namespace Aws std::future GetLocalDeploymentStatusOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } GetLocalDeploymentStatusOperation::GetLocalDeploymentStatusOperation( ClientConnection &connection, const GetLocalDeploymentStatusOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -9111,23 +8922,14 @@ namespace Aws const GetLocalDeploymentStatusRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(GetLocalDeploymentStatusResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(GetLocalDeploymentStatusResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -9176,14 +8978,15 @@ namespace Aws std::future GetSecretValueOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } GetSecretValueOperation::GetSecretValueOperation( ClientConnection &connection, const GetSecretValueOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -9191,23 +8994,14 @@ namespace Aws const GetSecretValueRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(GetSecretValueResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(GetSecretValueResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -9255,14 +9049,15 @@ namespace Aws std::future UpdateStateOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } UpdateStateOperation::UpdateStateOperation( ClientConnection &connection, const UpdateStateOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -9270,23 +9065,14 @@ namespace Aws const UpdateStateRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(UpdateStateResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(UpdateStateResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -9335,14 +9121,15 @@ namespace Aws std::future CancelLocalDeploymentOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } CancelLocalDeploymentOperation::CancelLocalDeploymentOperation( ClientConnection &connection, const CancelLocalDeploymentOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -9350,23 +9137,14 @@ namespace Aws const CancelLocalDeploymentRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(CancelLocalDeploymentResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(CancelLocalDeploymentResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -9415,14 +9193,15 @@ namespace Aws std::future ListNamedShadowsForThingOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } ListNamedShadowsForThingOperation::ListNamedShadowsForThingOperation( ClientConnection &connection, const ListNamedShadowsForThingOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -9430,23 +9209,14 @@ namespace Aws const ListNamedShadowsForThingRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(ListNamedShadowsForThingResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(ListNamedShadowsForThingResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -9525,7 +9295,7 @@ namespace Aws std::future SubscribeToComponentUpdatesOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } SubscribeToComponentUpdatesOperation::SubscribeToComponentUpdatesOperation( @@ -9533,7 +9303,8 @@ namespace Aws std::shared_ptr streamHandler, const SubscribeToComponentUpdatesOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, streamHandler, operationContext, allocator) + : ClientOperation(connection, streamHandler, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -9541,23 +9312,14 @@ namespace Aws const SubscribeToComponentUpdatesRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(SubscribeToComponentUpdatesResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(SubscribeToComponentUpdatesResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -9606,14 +9368,15 @@ namespace Aws std::future ListLocalDeploymentsOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } ListLocalDeploymentsOperation::ListLocalDeploymentsOperation( ClientConnection &connection, const ListLocalDeploymentsOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -9621,23 +9384,14 @@ namespace Aws const ListLocalDeploymentsRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(ListLocalDeploymentsResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(ListLocalDeploymentsResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -9686,14 +9440,15 @@ namespace Aws std::future StopComponentOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } StopComponentOperation::StopComponentOperation( ClientConnection &connection, const StopComponentOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -9701,23 +9456,14 @@ namespace Aws const StopComponentRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(StopComponentResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(StopComponentResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -9766,14 +9512,15 @@ namespace Aws std::future PauseComponentOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } PauseComponentOperation::PauseComponentOperation( ClientConnection &connection, const PauseComponentOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -9781,23 +9528,14 @@ namespace Aws const PauseComponentRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(PauseComponentResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(PauseComponentResult(std::move(unmodeledResult))); }); + return activateFuture; } @@ -9846,14 +9584,15 @@ namespace Aws std::future CreateLocalDeploymentOperation::GetResult() noexcept { - return m_resultPromise.get_future(); + return m_resultPromise->get_future(); } CreateLocalDeploymentOperation::CreateLocalDeploymentOperation( ClientConnection &connection, const CreateLocalDeploymentOperationContext &operationContext, Aws::Crt::Allocator *allocator) noexcept - : ClientOperation(connection, nullptr, operationContext, allocator) + : ClientOperation(connection, nullptr, operationContext, allocator), + m_resultPromise(Aws::Crt::MakeShared>(allocator)) { } @@ -9861,23 +9600,14 @@ namespace Aws const CreateLocalDeploymentRequest &request, OnMessageFlushCallback onMessageFlushCallback) noexcept { - bool synchronousSuccess = false; - std::lock_guard selfReferenceLock(m_selfReferenceLock); + auto promiseReference = m_resultPromise; + auto activateFuture = ClientOperation::Activate( static_cast(&request), std::move(onMessageFlushCallback), - [this](TaggedResult &&unmodeledResult) - { - std::lock_guard selfReferenceLock(m_selfReferenceLock); - m_resultPromise.set_value(CreateLocalDeploymentResult(std::move(unmodeledResult))); - m_selfReference = nullptr; - }, - synchronousSuccess); - if (synchronousSuccess) - { - m_selfReference = shared_from_this(); - ; - } + [promiseReference](TaggedResult &&unmodeledResult) + { promiseReference->set_value(CreateLocalDeploymentResult(std::move(unmodeledResult))); }); + return activateFuture; } From 2c4b72fe1bf02ffc4bfe72a157bcfcd8fbc8e9de Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Mon, 16 Jun 2025 11:39:46 -0700 Subject: [PATCH 42/56] Streaming success tests --- eventstream_rpc/tests/CMakeLists.txt | 23 +- .../tests/EventStreamClientTest.cpp | 442 +++++++++++++++++- 2 files changed, 449 insertions(+), 16 deletions(-) diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index 350d78515..e1e1e6d26 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -70,15 +70,24 @@ add_test_case(EchoClientOperationActivateWaitActivate) add_test_case(EchoClientOperationActivateCloseActivate) add_test_case(EchoClientOperationActivateClosedActivate) add_test_case(EchoClientOperationActivateCloseConnection) -#add_test_case(EchoClientOperationActivateDoubleCloseContinuation) -#add_test_case(EchoClientOperationActivateWaitDoubleCloseContinuation) -#add_test_case(EchoClientOperationActivateWaitCloseContinuationWaitCloseContinuation) -#add_test_case(EchoClientOperationActivateShutdown) -#add_test_case(EchoClientOperationActivateShutdownDropFuture) -#add_test_case(EchoClientOperationActivateWaitCloseShutdown) -#add_test_case(EchoClientOperationActivateWaitCloseShutdownDropFuture) +add_test_case(EchoClientOperationActivateDoubleCloseContinuation) +add_test_case(EchoClientOperationActivateWaitDoubleCloseContinuation) +add_test_case(EchoClientOperationActivateWaitCloseContinuationWaitCloseContinuation) +add_test_case(EchoClientOperationActivateShutdown) +add_test_case(EchoClientOperationActivateShutdownDropFuture) +add_test_case(EchoClientOperationActivateWaitCloseShutdown) +add_test_case(EchoClientOperationActivateWaitCloseShutdownDropFuture) # streaming echo messages tests +add_test_case(EchoClientStreamingOperationEchoSuccessString) +add_test_case(EchoClientStreamingOperationEchoSuccessBoolean) +add_test_case(EchoClientStreamingOperationEchoSuccessTime) +add_test_case(EchoClientStreamingOperationEchoSuccessDocument) +add_test_case(EchoClientStreamingOperationEchoSuccessEnum) +add_test_case(EchoClientStreamingOperationEchoSuccessBlob) +add_test_case(EchoClientStreamingOperationEchoSuccessStringList) +add_test_case(EchoClientStreamingOperationEchoSuccessPairList) +add_test_case(EchoClientStreamingOperationEchoSuccessProductMap) # streaming failure/error tests diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 4b44030b8..830b005ff 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -1241,15 +1241,439 @@ static int s_TestEchoClientOperationActivateCloseConnection(struct aws_allocator AWS_TEST_CASE(EchoClientOperationActivateCloseConnection, s_TestEchoClientOperationActivateCloseConnection); -// Non-streaming race condition tests -// add_test_case(EchoClientOperationActivateCloseConnection) -// add_test_case(EchoClientOperationActivateDoubleCloseContinuation) -// add_test_case(EchoClientOperationActivateWaitDoubleCloseContinuation) -// add_test_case(EchoClientOperationActivateWaitCloseContinuationWaitCloseContinuation) -// add_test_case(EchoClientOperationActivateShutdown) -// add_test_case(EchoClientOperationActivateShutdownDropFuture) -// add_test_case(EchoClientOperationActivateWaitCloseShutdown) -// add_test_case(EchoClientOperationActivateWaitCloseShutdownDropFuture) +static int s_TestEchoClientOperationActivateDoubleCloseContinuation(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllCustomers = client.NewGetAllCustomers(); + GetAllCustomersRequest getAllCustomersRequest; + + auto requestFuture = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + + auto closeFuture = getAllCustomers->Close(); + auto closeFuture2 = getAllCustomers->Close(); + + requestFuture.wait(); + auto flushErrorStatus = requestFuture.get().baseStatus; + ASSERT_TRUE( + flushErrorStatus == EVENT_STREAM_RPC_SUCCESS || + flushErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED); + + closeFuture.wait(); + closeFuture2.wait(); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE( + EchoClientOperationActivateDoubleCloseContinuation, + s_TestEchoClientOperationActivateDoubleCloseContinuation); + +static int s_TestEchoClientOperationActivateWaitDoubleCloseContinuation(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllCustomers = client.NewGetAllCustomers(); + GetAllCustomersRequest getAllCustomersRequest; + + auto requestFuture = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + requestFuture.wait(); + + auto closeFuture = getAllCustomers->Close(); + auto closeFuture2 = getAllCustomers->Close(); + + auto flushErrorStatus = requestFuture.get().baseStatus; + ASSERT_TRUE( + flushErrorStatus == EVENT_STREAM_RPC_SUCCESS || + flushErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED); + + closeFuture.wait(); + closeFuture2.wait(); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE( + EchoClientOperationActivateWaitDoubleCloseContinuation, + s_TestEchoClientOperationActivateWaitDoubleCloseContinuation); + +static int s_TestEchoClientOperationActivateWaitCloseContinuationWaitCloseContinuation( + struct aws_allocator *allocator, + void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllCustomers = client.NewGetAllCustomers(); + GetAllCustomersRequest getAllCustomersRequest; + + auto requestFuture = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + auto flushErrorStatus = requestFuture.get().baseStatus; + ASSERT_TRUE( + flushErrorStatus == EVENT_STREAM_RPC_SUCCESS || + flushErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED); + + auto closeFuture = getAllCustomers->Close(); + closeFuture.wait(); + + auto closeFuture2 = getAllCustomers->Close(); + closeFuture2.wait(); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE( + EchoClientOperationActivateWaitCloseContinuationWaitCloseContinuation, + s_TestEchoClientOperationActivateWaitCloseContinuationWaitCloseContinuation); + +static int s_TestEchoClientOperationActivateShutdown(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllCustomers = client.NewGetAllCustomers(); + GetAllCustomersRequest getAllCustomersRequest; + + auto requestFuture = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + getAllCustomers = nullptr; + auto flushErrorStatus = requestFuture.get().baseStatus; + ASSERT_TRUE( + flushErrorStatus == EVENT_STREAM_RPC_SUCCESS || + flushErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationActivateShutdown, s_TestEchoClientOperationActivateShutdown); + +static int s_TestEchoClientOperationActivateShutdownDropFuture(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllCustomers = client.NewGetAllCustomers(); + + GetAllCustomersRequest getAllCustomersRequest; + getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationActivateShutdownDropFuture, s_TestEchoClientOperationActivateShutdownDropFuture); + +static int s_TestEchoClientOperationActivateWaitCloseShutdown(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllCustomers = client.NewGetAllCustomers(); + GetAllCustomersRequest getAllCustomersRequest; + + auto requestFuture = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + auto flushErrorStatus = requestFuture.get().baseStatus; + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_SUCCESS, flushErrorStatus); + + auto closeFuture = getAllCustomers->Close(); + getAllCustomers = nullptr; + + closeFuture.wait(); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientOperationActivateWaitCloseShutdown, s_TestEchoClientOperationActivateWaitCloseShutdown); + +static int s_TestEchoClientOperationActivateWaitCloseShutdownDropFuture(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto getAllCustomers = client.NewGetAllCustomers(); + GetAllCustomersRequest getAllCustomersRequest; + + auto requestFuture = getAllCustomers->Activate(getAllCustomersRequest, s_onMessageFlush); + auto flushErrorStatus = requestFuture.get().baseStatus; + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_SUCCESS, flushErrorStatus); + + getAllCustomers->Close(); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE( + EchoClientOperationActivateWaitCloseShutdownDropFuture, + s_TestEchoClientOperationActivateWaitCloseShutdownDropFuture); + +class EchoStreamMessagesTestHandler : public EchoStreamMessagesStreamHandler +{ + public: + EchoStreamMessagesTestHandler( + Aws::Crt::Allocator *allocator, + EventStreamClientTestContext *context, + bool closeOnError) + : m_allocator(allocator), m_context(context), m_closeOnError(closeOnError) + { + } + + void OnStreamEvent(EchoStreamingMessage *response) override + { + std::lock_guard lock(m_lock); + + m_messages.push_back(Aws::Crt::MakeShared(m_allocator, *response)); + m_signal.notify_all(); + } + + bool OnStreamError(RpcError rpcError) override + { + std::lock_guard lock(m_lock); + + m_rpcErrors.push_back(rpcError); + m_signal.notify_all(); + + return m_closeOnError; + } + + bool OnStreamError(OperationError *operationError) override + { + (void)operationError; + + return m_closeOnError; + } + + void WaitForMessages(size_t count) + { + std::unique_lock lock(m_lock); + m_signal.wait(lock, [this, count]() { return m_messages.size() == count; }); + } + + int ValidateMessages(MessageData &expectedData) + { + std::lock_guard lock(m_lock); + for (size_t i = 0; i < m_messages.size(); i++) + { + const auto &message = m_messages[i]; + ASSERT_SUCCESS(s_checkMessageDataEquality(expectedData, message->GetStreamMessage().value())); + } + + return AWS_OP_SUCCESS; + } + + private: + Aws::Crt::Allocator *m_allocator; + EventStreamClientTestContext *m_context; + bool m_closeOnError; + + std::mutex m_lock; + std::condition_variable m_signal; + + Aws::Crt::Vector> m_messages; + Vector m_rpcErrors; +}; + +constexpr size_t STREAM_MESSAGE_COUNT = 10; + +static int s_DoTestEchoClientStreamingOperationEchoSuccess( + struct aws_allocator *allocator, + std::function messageDataBuilder) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + MessageData expecectedMessageData; + messageDataBuilder(expecectedMessageData); + + { + auto handler = Aws::Crt::MakeShared(allocator, allocator, &testContext, false); + ConnectionLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedStatus = client.Connect(lifecycleHandler); + ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); + + auto echoStreamMessages = client.NewEchoStreamMessages(handler); + EchoStreamingRequest echoStreamingMessageRequest; + auto activateFuture = echoStreamMessages->Activate(echoStreamingMessageRequest, s_onMessageFlush); + activateFuture.wait(); + + auto result = echoStreamMessages->GetResult().get(); + ASSERT_TRUE(result); + + Aws::Crt::Vector> streamMessageFutures; + for (size_t i = 0; i < STREAM_MESSAGE_COUNT; ++i) + { + EchoStreamingMessage streamMessage; + MessageData messageData; + messageDataBuilder(messageData); + streamMessage.SetStreamMessage(messageData); + + auto streamFuture = echoStreamMessages->SendStreamMessage(streamMessage, s_onMessageFlush); + streamMessageFutures.emplace_back(std::move(streamFuture)); + } + + handler->WaitForMessages(STREAM_MESSAGE_COUNT); + ASSERT_INT_EQUALS(STREAM_MESSAGE_COUNT, streamMessageFutures.size()); + + for (size_t i = 0; i < streamMessageFutures.size(); i++) + { + auto streamResult = streamMessageFutures[i].get(); + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_SUCCESS, streamResult.baseStatus); + } + + ASSERT_SUCCESS(handler->ValidateMessages(expecectedMessageData)); + } + + return AWS_OP_SUCCESS; +} + +static int s_TestEchoClientStreamingOperationEchoSuccessString(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientStreamingOperationEchoSuccess( + allocator, + [](MessageData &messageData) + { + Aws::Crt::String value = "Hello World"; + messageData.SetStringMessage(value); + }); +} + +AWS_TEST_CASE(EchoClientStreamingOperationEchoSuccessString, s_TestEchoClientStreamingOperationEchoSuccessString); + +static int s_TestEchoClientStreamingOperationEchoSuccessBoolean(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientStreamingOperationEchoSuccess( + allocator, [](MessageData &messageData) { messageData.SetBooleanMessage(true); }); +} + +AWS_TEST_CASE(EchoClientStreamingOperationEchoSuccessBoolean, s_TestEchoClientStreamingOperationEchoSuccessBoolean); + +static int s_TestEchoClientStreamingOperationEchoSuccessTime(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientStreamingOperationEchoSuccess( + allocator, [](MessageData &messageData) { messageData.SetTimeMessage(Aws::Crt::DateTime::Now()); }); +} + +AWS_TEST_CASE(EchoClientStreamingOperationEchoSuccessTime, s_TestEchoClientStreamingOperationEchoSuccessTime); + +static int s_TestEchoClientStreamingOperationEchoSuccessDocument(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientStreamingOperationEchoSuccess( + allocator, + [](MessageData &messageData) + { + Aws::Crt::JsonObject subobject; + subobject.WithString("Hello", "There"); + Aws::Crt::JsonObject document; + document.WithInt64("Derp", 21); + document.WithObject("DailyAffirmations", subobject); + + messageData.SetDocumentMessage(document); + }); +} + +AWS_TEST_CASE(EchoClientStreamingOperationEchoSuccessDocument, s_TestEchoClientStreamingOperationEchoSuccessDocument); + +static int s_TestEchoClientStreamingOperationEchoSuccessEnum(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientStreamingOperationEchoSuccess( + allocator, [](MessageData &messageData) { messageData.SetEnumMessage(FruitEnum::FRUIT_ENUM_PINEAPPLE); }); +} + +AWS_TEST_CASE(EchoClientStreamingOperationEchoSuccessEnum, s_TestEchoClientStreamingOperationEchoSuccessEnum); + +static int s_TestEchoClientStreamingOperationEchoSuccessBlob(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientStreamingOperationEchoSuccess( + allocator, + [](MessageData &messageData) + { + Aws::Crt::Vector blob = {1, 2, 3, 4, 5}; + messageData.SetBlobMessage(blob); + }); +} + +AWS_TEST_CASE(EchoClientStreamingOperationEchoSuccessBlob, s_TestEchoClientStreamingOperationEchoSuccessBlob); + +static int s_TestEchoClientStreamingOperationEchoSuccessStringList(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientStreamingOperationEchoSuccess( + allocator, + [](MessageData &messageData) + { + Aws::Crt::Vector stringList = {"1", "2", "Toasty", "Mctoaster"}; + messageData.SetStringListMessage(stringList); + }); +} + +AWS_TEST_CASE( + EchoClientStreamingOperationEchoSuccessStringList, + s_TestEchoClientStreamingOperationEchoSuccessStringList); + +static int s_TestEchoClientStreamingOperationEchoSuccessPairList(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientStreamingOperationEchoSuccess( + allocator, + [](MessageData &messageData) + { + Pair pair1; + pair1.SetKey("Uff"); + pair1.SetValue("Dah"); + + Pair pair2; + pair2.SetKey("Hello"); + pair2.SetValue("World"); + + Aws::Crt::Vector pairList = {pair1, pair2}; + messageData.SetKeyValuePairList(pairList); + }); +} + +AWS_TEST_CASE(EchoClientStreamingOperationEchoSuccessPairList, s_TestEchoClientStreamingOperationEchoSuccessPairList); + +static int s_TestEchoClientStreamingOperationEchoSuccessProductMap(struct aws_allocator *allocator, void *ctx) +{ + return s_DoTestEchoClientStreamingOperationEchoSuccess( + allocator, + [](MessageData &messageData) + { + Aws::Crt::Map productMap = {}; + Product product1; + product1.SetName("Derp"); + product1.SetPrice(4.0); + + Product product2; + product2.SetName("Can Of Derp"); + product2.SetPrice(7.5); + + productMap[product1.GetName().value()] = product1; + productMap[product2.GetName().value()] = product2; + + messageData.SetStringToValue(productMap); + }); +} + +AWS_TEST_CASE( + EchoClientStreamingOperationEchoSuccessProductMap, + s_TestEchoClientStreamingOperationEchoSuccessProductMap); #ifdef NEVER From 8187524f7e66bc90edd68216374dec22f7f0d7f1 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 18 Jun 2025 14:57:59 -0700 Subject: [PATCH 43/56] Final stress testing --- .../aws/eventstreamrpc/EventStreamClient.h | 2 +- eventstream_rpc/source/EventStreamClient.cpp | 62 +- eventstream_rpc/tests/CMakeLists.txt | 5 + eventstream_rpc/tests/EchoTestRpcClient.cpp | 3 +- eventstream_rpc/tests/EchoTestRpcModel.cpp | 26 +- .../tests/EventStreamClientTest.cpp | 533 +++++++++++++++++- .../tests/include/awstest/EchoTestRpcModel.h | 26 +- .../aws/greengrass/GreengrassCoreIpcModel.h | 139 +++-- .../source/GreengrassCoreIpcClient.cpp | 3 +- .../source/GreengrassCoreIpcModel.cpp | 149 +++-- 10 files changed, 784 insertions(+), 164 deletions(-) diff --git a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h index 4bdbe0f2c..4ee17c6f0 100644 --- a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h +++ b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h @@ -550,7 +550,7 @@ namespace Aws ClientOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const OperationModelContext &operationModelContext, + const std::shared_ptr &operationModelContext, Crt::Allocator *allocator) noexcept; ~ClientOperation() noexcept override; diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 5273b60f9..46687d116 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -1412,7 +1412,7 @@ namespace Aws Crt::String GetModelName() const noexcept; void Initialize( - const OperationModelContext *operationModelContext, + const std::shared_ptr &operationModelContext, std::shared_ptr streamHandler) noexcept { m_operationModelContext = operationModelContext; @@ -1453,13 +1453,16 @@ namespace Aws Aws::Crt::Allocator *m_allocator; struct aws_client_bootstrap *m_clientBootstrap; + struct aws_event_loop *m_connectionEventLoop; std::shared_ptr m_selfReference; std::mutex m_sharedStateLock; ContinuationSharedState m_sharedState; - const OperationModelContext *m_operationModelContext; + std::shared_ptr m_operationModelContext; + + std::mutex m_streamHandlerLock; std::shared_ptr m_streamHandler; /* @@ -1478,11 +1481,11 @@ namespace Aws ClientOperation::ClientOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const OperationModelContext &operationModelContext, + const std::shared_ptr &operationModelContext, Crt::Allocator *allocator) noexcept : m_allocator(allocator), m_impl(connection.NewStream()) { - m_impl->Initialize(&operationModelContext, std::move(streamHandler)); + m_impl->Initialize(operationModelContext, std::move(streamHandler)); } ClientOperation::~ClientOperation() noexcept @@ -1555,7 +1558,8 @@ namespace Aws Aws::Crt::Allocator *allocator, struct aws_client_bootstrap *bootstrap, struct aws_event_stream_rpc_client_connection *connection) noexcept - : m_allocator(allocator), m_clientBootstrap(aws_client_bootstrap_acquire(bootstrap)), m_sharedState(), + : m_allocator(allocator), m_clientBootstrap(aws_client_bootstrap_acquire(bootstrap)), + m_connectionEventLoop(aws_event_stream_rpc_client_connection_get_event_loop(connection)), m_sharedState(), m_operationModelContext(nullptr), m_continuationValid(true) { if (connection != nullptr) @@ -1643,6 +1647,24 @@ namespace Aws std::shared_ptr activationCallbackContainer = nullptr; std::function activationResponseCallback = nullptr; + { + if (m_connectionEventLoop != nullptr) + { + bool useHandlerLock = !aws_event_loop_thread_is_callers_thread(m_connectionEventLoop); + if (useHandlerLock) + { + m_streamHandlerLock.lock(); + } + + m_streamHandler = nullptr; + + if (useHandlerLock) + { + m_streamHandlerLock.unlock(); + } + } + } + { std::lock_guard lock(m_sharedStateLock); if (m_sharedState.m_currentState == ContinuationStateType::None) @@ -2212,19 +2234,43 @@ namespace Aws if (!isResponse) { + std::lock_guard handlerLock(m_streamHandlerLock); + auto streamHandler = m_streamHandler; if (streamHandler) { if (result.m_message.has_value()) { - AWS_FATAL_ASSERT(result.m_message.value().m_route == EventStreamMessageRoutingType::Stream); auto shape = std::move(result.m_message.value().m_shape); + auto route = result.m_message.value().m_route; + switch (route) + { + case EventStreamMessageRoutingType::Stream: + { + + streamHandler->OnStreamEvent(std::move(shape)); + break; + } + + case EventStreamMessageRoutingType::Error: + { + Crt::Allocator *allocator = m_allocator; + auto errorResponse = Crt::ScopedResource( + static_cast(shape.release()), + [allocator](OperationError *shape) { Crt::Delete(shape, allocator); }); - streamHandler->OnStreamEvent(std::move(shape)); + shouldClose = streamHandler->OnStreamError( + std::move(errorResponse), {EVENT_STREAM_RPC_SUCCESS, 0}); + break; + } + + default: + AWS_FATAL_ASSERT(false); + } } else { - shouldClose = m_streamHandler->OnStreamError(nullptr, {result.m_statusCode, 0}); + shouldClose = streamHandler->OnStreamError(nullptr, {result.m_statusCode, 0}); } } } diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index e1e1e6d26..360f780e7 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -90,8 +90,13 @@ add_test_case(EchoClientStreamingOperationEchoSuccessPairList) add_test_case(EchoClientStreamingOperationEchoSuccessProductMap) # streaming failure/error tests +add_test_case(EchoClientStreamingOperationCauseServiceError) # streaming race condition tests +add_test_case(EchoClientStreamingOperationSendCloseOperation) +add_test_case(EchoClientStreamingOperationSendDropOperation) +add_test_case(EchoClientStreamingOperationSendCloseConnection) +add_test_case(EchoClientOperationStress) generate_cpp_test_driver(${TEST_BINARY_NAME}) aws_add_sanitizers(${TEST_BINARY_NAME}) diff --git a/eventstream_rpc/tests/EchoTestRpcClient.cpp b/eventstream_rpc/tests/EchoTestRpcClient.cpp index 871869f68..3a568b84f 100644 --- a/eventstream_rpc/tests/EchoTestRpcClient.cpp +++ b/eventstream_rpc/tests/EchoTestRpcClient.cpp @@ -14,7 +14,8 @@ namespace Awstest EchoTestRpcClient::EchoTestRpcClient( Aws::Crt::Io::ClientBootstrap &clientBootstrap, Aws::Crt::Allocator *allocator) noexcept - : m_connection( + : m_echoTestRpcServiceModel(allocator), + m_connection( Aws::Crt::MakeShared(allocator, allocator, clientBootstrap.GetUnderlyingHandle())), m_allocator(allocator), m_asyncLaunchMode(std::launch::deferred) { diff --git a/eventstream_rpc/tests/EchoTestRpcModel.cpp b/eventstream_rpc/tests/EchoTestRpcModel.cpp index 2740222bd..07e81aa13 100644 --- a/eventstream_rpc/tests/EchoTestRpcModel.cpp +++ b/eventstream_rpc/tests/EchoTestRpcModel.cpp @@ -1023,7 +1023,7 @@ namespace Awstest GetAllProductsOperation::GetAllProductsOperation( ClientConnection &connection, - const GetAllProductsOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -1095,7 +1095,7 @@ namespace Awstest CauseServiceErrorOperation::CauseServiceErrorOperation( ClientConnection &connection, - const CauseServiceErrorOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -1190,7 +1190,7 @@ namespace Awstest CauseStreamServiceToErrorOperation::CauseStreamServiceToErrorOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const CauseStreamServiceToErrorOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, streamHandler, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -1288,7 +1288,7 @@ namespace Awstest EchoStreamMessagesOperation::EchoStreamMessagesOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const EchoStreamMessagesOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, streamHandler, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -1366,7 +1366,7 @@ namespace Awstest EchoMessageOperation::EchoMessageOperation( ClientConnection &connection, - const EchoMessageOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -1437,7 +1437,7 @@ namespace Awstest GetAllCustomersOperation::GetAllCustomersOperation( ClientConnection &connection, - const GetAllCustomersOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -1459,10 +1459,16 @@ namespace Awstest return activateFuture; } - EchoTestRpcServiceModel::EchoTestRpcServiceModel() noexcept - : m_getAllProductsOperationContext(*this), m_causeServiceErrorOperationContext(*this), - m_causeStreamServiceToErrorOperationContext(*this), m_echoStreamMessagesOperationContext(*this), - m_echoMessageOperationContext(*this), m_getAllCustomersOperationContext(*this) + EchoTestRpcServiceModel::EchoTestRpcServiceModel(Aws::Crt::Allocator *allocator) noexcept + : m_getAllProductsOperationContext(Aws::Crt::MakeShared(allocator, *this)), + m_causeServiceErrorOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_causeStreamServiceToErrorOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_echoStreamMessagesOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_echoMessageOperationContext(Aws::Crt::MakeShared(allocator, *this)), + m_getAllCustomersOperationContext(Aws::Crt::MakeShared(allocator, *this)) { } diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 830b005ff..087ad9dad 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -1423,11 +1423,8 @@ AWS_TEST_CASE( class EchoStreamMessagesTestHandler : public EchoStreamMessagesStreamHandler { public: - EchoStreamMessagesTestHandler( - Aws::Crt::Allocator *allocator, - EventStreamClientTestContext *context, - bool closeOnError) - : m_allocator(allocator), m_context(context), m_closeOnError(closeOnError) + EchoStreamMessagesTestHandler(Aws::Crt::Allocator *allocator, bool closeOnError) + : m_allocator(allocator), m_closeOnError(closeOnError) { } @@ -1476,7 +1473,6 @@ class EchoStreamMessagesTestHandler : public EchoStreamMessagesStreamHandler private: Aws::Crt::Allocator *m_allocator; - EventStreamClientTestContext *m_context; bool m_closeOnError; std::mutex m_lock; @@ -1504,7 +1500,7 @@ static int s_DoTestEchoClientStreamingOperationEchoSuccess( messageDataBuilder(expecectedMessageData); { - auto handler = Aws::Crt::MakeShared(allocator, allocator, &testContext, false); + auto handler = Aws::Crt::MakeShared(allocator, allocator, false); ConnectionLifecycleHandler lifecycleHandler; Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); auto connectedStatus = client.Connect(lifecycleHandler); @@ -1675,6 +1671,529 @@ AWS_TEST_CASE( EchoClientStreamingOperationEchoSuccessProductMap, s_TestEchoClientStreamingOperationEchoSuccessProductMap); +class CauseServiceErrorTestHandler : public CauseStreamServiceToErrorStreamHandler +{ + public: + CauseServiceErrorTestHandler(Aws::Crt::Allocator *allocator, bool closeOnError) + : m_allocator(allocator), m_closeOnError(closeOnError) + { + } + + void OnStreamEvent(EchoStreamingMessage *response) override { (void)response; } + + bool OnStreamError(RpcError rpcError) override + { + (void)rpcError; + + return m_closeOnError; + } + + bool OnStreamError(ServiceError *serviceError) override + { + std::lock_guard lock(m_lock); + + m_serviceErrors.push_back(Aws::Crt::MakeShared(m_allocator, *serviceError)); + m_signal.notify_all(); + + return m_closeOnError; + } + + bool OnStreamError(OperationError *operationError) override + { + (void)operationError; + + return m_closeOnError; + } + + void WaitForErrors(size_t count) + { + std::unique_lock lock(m_lock); + m_signal.wait(lock, [this, count]() { return m_serviceErrors.size() == count; }); + } + + int ValidateErrors(ServiceError &expectedError) + { + std::lock_guard lock(m_lock); + for (size_t i = 0; i < m_serviceErrors.size(); i++) + { + const auto &error = m_serviceErrors[i]; + + ASSERT_TRUE(error->GetMessage().has_value() == expectedError.GetMessage().has_value()); + ASSERT_TRUE(error->GetValue().has_value() == expectedError.GetValue().has_value()); + + if (expectedError.GetMessage().has_value()) + { + ASSERT_TRUE(expectedError.GetMessage().value() == error->GetMessage().value()); + } + + if (expectedError.GetValue().has_value()) + { + ASSERT_TRUE(expectedError.GetValue().value() == error->GetValue().value()); + } + } + + return AWS_OP_SUCCESS; + } + + private: + Aws::Crt::Allocator *m_allocator; + bool m_closeOnError; + + std::mutex m_lock; + std::condition_variable m_signal; + + Aws::Crt::Vector> m_serviceErrors; +}; + +static int s_TestEchoClientStreamingOperationCauseServiceError(struct aws_allocator *allocator, void *ctx) +{ + ApiHandle apiHandle(allocator); + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + { + auto handler = Aws::Crt::MakeShared(allocator, allocator, false); + ConnectionLifecycleHandler lifecycleHandler; + Awstest::EchoTestRpcClient client(*testContext.clientBootstrap, allocator); + auto connectedStatus = client.Connect(lifecycleHandler); + ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); + + auto causeStreamServiceError = client.NewCauseStreamServiceToError(handler); + EchoStreamingRequest request; + auto activateFuture = causeStreamServiceError->Activate(request, s_onMessageFlush); + activateFuture.wait(); + + auto result = causeStreamServiceError->GetResult().get(); + ASSERT_TRUE(result); + + EchoStreamingMessage streamMessage; + MessageData messageData; + Aws::Crt::String value = "Hello World"; + messageData.SetStringMessage(value); + streamMessage.SetStreamMessage(messageData); + + auto streamFuture = causeStreamServiceError->SendStreamMessage(streamMessage, s_onMessageFlush); + + handler->WaitForErrors(1); + + auto streamResult = streamFuture.get(); + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_SUCCESS, streamResult.baseStatus); + + ServiceError expectedError; + expectedError.SetMessage("Intentionally caused ServiceError on stream"); + + ASSERT_SUCCESS(handler->ValidateErrors(expectedError)); + } + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(EchoClientStreamingOperationCauseServiceError, s_TestEchoClientStreamingOperationCauseServiceError); + +static int s_TestEchoClientStreamingOperationSendCloseOperation(struct aws_allocator *allocator, void *ctx) +{ + return s_DoSimpleRequestRaceCheckTest( + allocator, + [allocator](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto handler = Aws::Crt::MakeShared(allocator, allocator, false); + auto echoStreamMessages = client.NewEchoStreamMessages(handler); + EchoStreamingRequest echoStreamingMessageRequest; + auto activateFuture = echoStreamMessages->Activate(echoStreamingMessageRequest, s_onMessageFlush); + activateFuture.wait(); + + auto result = echoStreamMessages->GetResult().get(); + ASSERT_TRUE(result); + + EchoStreamingMessage streamMessage; + MessageData messageData; + Aws::Crt::String value = "Hello World"; + messageData.SetStringMessage(value); + + streamMessage.SetStreamMessage(messageData); + + auto streamFuture = echoStreamMessages->SendStreamMessage(streamMessage, s_onMessageFlush); + + auto closeFuture = echoStreamMessages->Close(); + closeFuture.wait(); + + auto streamResultStatus = streamFuture.get().baseStatus; + ASSERT_TRUE( + streamResultStatus == EVENT_STREAM_RPC_SUCCESS || + streamResultStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientStreamingOperationSendCloseOperation, s_TestEchoClientStreamingOperationSendCloseOperation); + +static int s_TestEchoClientStreamingOperationSendDropOperation(struct aws_allocator *allocator, void *ctx) +{ + + return s_DoSimpleRequestRaceCheckTest( + allocator, + [allocator](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto handler = Aws::Crt::MakeShared(allocator, allocator, false); + auto echoStreamMessages = client.NewEchoStreamMessages(handler); + EchoStreamingRequest echoStreamingMessageRequest; + auto activateFuture = echoStreamMessages->Activate(echoStreamingMessageRequest, s_onMessageFlush); + activateFuture.wait(); + + auto result = echoStreamMessages->GetResult().get(); + ASSERT_TRUE(result); + + EchoStreamingMessage streamMessage; + MessageData messageData; + Aws::Crt::String value = "Hello World"; + messageData.SetStringMessage(value); + + streamMessage.SetStreamMessage(messageData); + + auto streamFuture = echoStreamMessages->SendStreamMessage(streamMessage, s_onMessageFlush); + + echoStreamMessages = nullptr; + + auto streamResultStatus = streamFuture.get().baseStatus; + ASSERT_TRUE( + streamResultStatus == EVENT_STREAM_RPC_SUCCESS || + streamResultStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientStreamingOperationSendDropOperation, s_TestEchoClientStreamingOperationSendDropOperation); + +static int s_TestEchoClientStreamingOperationSendCloseConnection(struct aws_allocator *allocator, void *ctx) +{ + return s_DoClientScopedRaceCheckTest( + allocator, + [allocator](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto handler = Aws::Crt::MakeShared(allocator, allocator, false); + auto echoStreamMessages = client.NewEchoStreamMessages(handler); + EchoStreamingRequest echoStreamingMessageRequest; + auto activateFuture = echoStreamMessages->Activate(echoStreamingMessageRequest, s_onMessageFlush); + activateFuture.wait(); + + auto result = echoStreamMessages->GetResult().get(); + ASSERT_TRUE(result); + + EchoStreamingMessage streamMessage; + MessageData messageData; + Aws::Crt::String value = "Hello World"; + messageData.SetStringMessage(value); + + streamMessage.SetStreamMessage(messageData); + + auto streamFuture = echoStreamMessages->SendStreamMessage(streamMessage, s_onMessageFlush); + + client.Close(); + + auto streamResultStatus = streamFuture.get().baseStatus; + ASSERT_TRUE( + streamResultStatus == EVENT_STREAM_RPC_SUCCESS || + streamResultStatus == EVENT_STREAM_RPC_CONNECTION_CLOSED); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientStreamingOperationSendCloseConnection, s_TestEchoClientStreamingOperationSendCloseConnection); + +class EchoStressContext +{ + public: + ~EchoStressContext() + { + m_client = nullptr; + m_stream = nullptr; + } + + std::shared_ptr m_client; + std::shared_ptr m_lifecycleHandler; + std::shared_ptr m_stream; + std::shared_ptr m_streamHandler; + Aws::Crt::Vector> m_oldLifecycleHandlers; + + Aws::Crt::Allocator *m_allocator; +}; + +using StressAction = std::function; + +struct WeightedAction +{ + StressAction m_action; + size_t m_weight; +}; + +class EchoStressActionDistribution +{ + public: + EchoStressActionDistribution(); + + void AddAction(StressAction &&action, size_t weight); + + void ApplyRandomAction(const EventStreamClientTestContext &testContext, EchoStressContext &stressContext); + + private: + Aws::Crt::Vector m_actions; + + size_t m_totalWeight; +}; + +EchoStressActionDistribution::EchoStressActionDistribution() : m_actions(), m_totalWeight(0) {} + +void EchoStressActionDistribution::AddAction(StressAction &&action, size_t weight) +{ + if (weight == 0) + { + return; + } + + m_actions.emplace_back(std::move(WeightedAction{std::move(action), weight})); + m_totalWeight += weight; +} + +void EchoStressActionDistribution::ApplyRandomAction( + const EventStreamClientTestContext &testContext, + EchoStressContext &stressContext) +{ + if (m_totalWeight == 0 || m_actions.empty()) + { + return; + } + + size_t accumulator = std::rand() % m_totalWeight; + for (size_t i = 0; i < m_actions.size(); ++i) + { + const auto &action = m_actions[i]; + + if (accumulator < action.m_weight) + { + action.m_action(testContext, stressContext); + break; + } + + accumulator -= action.m_weight; + } +} + +static void s_CreateClientIfNeeded(const EventStreamClientTestContext &testContext, EchoStressContext &stressContext) +{ + if (stressContext.m_client != nullptr) + { + return; + } + + stressContext.m_lifecycleHandler = Aws::Crt::MakeShared(stressContext.m_allocator); + stressContext.m_client = Aws::Crt::MakeShared( + stressContext.m_allocator, *testContext.clientBootstrap, stressContext.m_allocator); +} + +static void s_BeginClientAction(const EventStreamClientTestContext &testContext, EchoStressContext &stressContext) +{ + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - BeginClient"); + s_CreateClientIfNeeded(testContext, stressContext); + + auto connectFuture = stressContext.m_client->Connect(*stressContext.m_lifecycleHandler); + + if (std::rand() % 2) + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - BeginClient - waiting on connect future"); + connectFuture.wait(); + } +} + +static void s_EndClientAction(const EventStreamClientTestContext &testContext, EchoStressContext &stressContext) +{ + (void)testContext; + + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - EndClient"); + if (stressContext.m_client == nullptr) + { + return; + } + + if (std::rand() % 2) + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - EndClient - Closing"); + stressContext.m_client->Close(); + if (std::rand() % 2) + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - EndClient - Waiting On Close Completion"); + stressContext.m_lifecycleHandler->WaitOnDisconnected(); + } + } + else + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - EndClient - Dropping"); + stressContext.m_oldLifecycleHandlers.push_back(stressContext.m_lifecycleHandler); + stressContext.m_lifecycleHandler = nullptr; + stressContext.m_client = nullptr; + } +} + +static void s_RequestResponseAction(const EventStreamClientTestContext &testContext, EchoStressContext &stressContext) +{ + (void)testContext; + + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - RequestResponse"); + s_CreateClientIfNeeded(testContext, stressContext); + + auto echoMessage = stressContext.m_client->NewEchoMessage(); + + EchoMessageRequest echoMessageRequest; + MessageData messageData; + messageData.SetStringMessage("HelloWorld"); + echoMessageRequest.SetMessage(messageData); + + auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); + + if (std::rand() % 2) + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - RequestResponse - waiting on flush future"); + auto flushResult = requestFuture.get(); + + if (flushResult.baseStatus == EVENT_STREAM_RPC_SUCCESS) + { + if (std::rand() % 2) + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - RequestResponse - waiting on result"); + auto result = echoMessage->GetResult().get(); + } + } + } +} + +static void s_BeginStreamAction(const EventStreamClientTestContext &testContext, EchoStressContext &stressContext) +{ + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - BeginStream"); + s_CreateClientIfNeeded(testContext, stressContext); + + stressContext.m_stream = nullptr; + stressContext.m_streamHandler = nullptr; + + stressContext.m_streamHandler = Aws::Crt::MakeShared( + stressContext.m_allocator, stressContext.m_allocator, false); + auto echoStreamMessages = stressContext.m_client->NewEchoStreamMessages(stressContext.m_streamHandler); + + EchoStreamingRequest echoStreamingMessageRequest; + auto activateFuture = echoStreamMessages->Activate(echoStreamingMessageRequest, s_onMessageFlush); + + if (std::rand() % 2) + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - BeginStream - waiting on Activate flush future"); + auto flushResult = activateFuture.get(); + if (flushResult.baseStatus == EVENT_STREAM_RPC_SUCCESS) + { + if (std::rand() % 2) + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - BeginStream - waiting on Activate result"); + auto result = echoStreamMessages->GetResult().get(); + } + } + } +} + +static void s_SendStreamAction(const EventStreamClientTestContext &testContext, EchoStressContext &stressContext) +{ + (void)testContext; + + if (stressContext.m_stream == nullptr) + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - SendStream - nothing to do"); + return; + } + + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - SendStream"); + EchoStreamingMessage streamMessage; + MessageData messageData; + Aws::Crt::String value = "Hello World"; + messageData.SetStringMessage(value); + + streamMessage.SetStreamMessage(messageData); + + auto streamFuture = stressContext.m_stream->SendStreamMessage(streamMessage, s_onMessageFlush); + if (std::rand() % 2) + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - SendStream - waiting on flush future"); + streamFuture.get(); + } +} + +static void s_EndStreamAction(const EventStreamClientTestContext &testContext, EchoStressContext &stressContext) +{ + (void)testContext; + + if (stressContext.m_stream == nullptr) + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - EndStream - nothing to do"); + return; + } + + if (std::rand() % 2) + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - EndStream - Closing"); + auto closeFuture = stressContext.m_stream->Close(); + if (std::rand() % 2) + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - EndStream - Waiting on Close future"); + closeFuture.wait(); + } + } + else + { + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EchoStressTest - EndStream - Dropping"); + stressContext.m_stream = nullptr; + stressContext.m_streamHandler = nullptr; + } +} + +constexpr size_t STRESS_TEST_STEP_COUNT = 50000; + +static int s_TestEchoClientOperationStress(struct aws_allocator *allocator, void *ctx) +{ + (void)ctx; + + ApiHandle apiHandle(allocator); + + { + EchoStressContext stressContext; + stressContext.m_allocator = allocator; + + EventStreamClientTestContext testContext(allocator); + if (!testContext.isValidEnvironment()) + { + printf("Environment Variables are not set for the test, skipping..."); + return AWS_OP_SKIP; + } + + EchoStressActionDistribution actionDistribution; + actionDistribution.AddAction(s_BeginClientAction, 3); + actionDistribution.AddAction(s_EndClientAction, 1); + actionDistribution.AddAction(s_RequestResponseAction, 4); + actionDistribution.AddAction(s_BeginStreamAction, 2); + actionDistribution.AddAction(s_SendStreamAction, 4); + actionDistribution.AddAction(s_EndStreamAction, 1); + + for (size_t i = 0; i < STRESS_TEST_STEP_COUNT; ++i) + { + actionDistribution.ApplyRandomAction(testContext, stressContext); + } + } + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(EchoClientOperationStress, s_TestEchoClientOperationStress); + #ifdef NEVER AWS_TEST_CASE_FIXTURE(EchoOperation, s_testSetup, s_TestEchoOperation, s_testTeardown, &s_testContext); diff --git a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h index 578a14798..4c46677e7 100644 --- a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h +++ b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h @@ -723,7 +723,7 @@ namespace Awstest public: GetAllProductsOperation( ClientConnection &connection, - const GetAllProductsOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -789,7 +789,7 @@ namespace Awstest public: CauseServiceErrorOperation( ClientConnection &connection, - const CauseServiceErrorOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -907,7 +907,7 @@ namespace Awstest CauseStreamServiceToErrorOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const CauseStreamServiceToErrorOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -1025,7 +1025,7 @@ namespace Awstest EchoStreamMessagesOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const EchoStreamMessagesOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -1103,7 +1103,7 @@ namespace Awstest public: EchoMessageOperation( ClientConnection &connection, - const EchoMessageOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -1169,7 +1169,7 @@ namespace Awstest public: GetAllCustomersOperation( ClientConnection &connection, - const GetAllCustomersOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -1194,7 +1194,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API EchoTestRpcServiceModel : public ServiceModel { public: - EchoTestRpcServiceModel() noexcept; + EchoTestRpcServiceModel(Aws::Crt::Allocator *allocator) noexcept; Aws::Crt::ScopedResource AllocateOperationErrorFromPayload( const Aws::Crt::String &errorModelName, Aws::Crt::StringView stringView, @@ -1203,12 +1203,12 @@ namespace Awstest private: friend class EchoTestRpcClient; - GetAllProductsOperationContext m_getAllProductsOperationContext; - CauseServiceErrorOperationContext m_causeServiceErrorOperationContext; - CauseStreamServiceToErrorOperationContext m_causeStreamServiceToErrorOperationContext; - EchoStreamMessagesOperationContext m_echoStreamMessagesOperationContext; - EchoMessageOperationContext m_echoMessageOperationContext; - GetAllCustomersOperationContext m_getAllCustomersOperationContext; + std::shared_ptr m_getAllProductsOperationContext; + std::shared_ptr m_causeServiceErrorOperationContext; + std::shared_ptr m_causeStreamServiceToErrorOperationContext; + std::shared_ptr m_echoStreamMessagesOperationContext; + std::shared_ptr m_echoMessageOperationContext; + std::shared_ptr m_getAllCustomersOperationContext; Aws::Crt::Map m_modelNameToErrorResponse; }; } // namespace Awstest diff --git a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h index b88cc4c16..068ec8e69 100644 --- a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h +++ b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h @@ -4523,7 +4523,7 @@ namespace Aws SubscribeToIoTCoreOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const SubscribeToIoTCoreOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -4589,7 +4589,7 @@ namespace Aws public: ResumeComponentOperation( ClientConnection &connection, - const ResumeComponentOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -4655,7 +4655,7 @@ namespace Aws public: PublishToIoTCoreOperation( ClientConnection &connection, - const PublishToIoTCoreOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -4784,7 +4784,7 @@ namespace Aws SubscribeToConfigurationUpdateOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const SubscribeToConfigurationUpdateOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -4850,7 +4850,7 @@ namespace Aws public: DeleteThingShadowOperation( ClientConnection &connection, - const DeleteThingShadowOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -4916,7 +4916,7 @@ namespace Aws public: PutComponentMetricOperation( ClientConnection &connection, - const PutComponentMetricOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -4984,7 +4984,7 @@ namespace Aws public: DeferComponentUpdateOperation( ClientConnection &connection, - const DeferComponentUpdateOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -5107,7 +5107,7 @@ namespace Aws SubscribeToValidateConfigurationUpdatesOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const SubscribeToValidateConfigurationUpdatesOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -5173,7 +5173,7 @@ namespace Aws public: GetConfigurationOperation( ClientConnection &connection, - const GetConfigurationOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -5309,7 +5309,7 @@ namespace Aws SubscribeToTopicOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const SubscribeToTopicOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -5375,7 +5375,7 @@ namespace Aws public: GetComponentDetailsOperation( ClientConnection &connection, - const GetComponentDetailsOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -5444,7 +5444,7 @@ namespace Aws public: GetClientDeviceAuthTokenOperation( ClientConnection &connection, - const GetClientDeviceAuthTokenOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -5510,7 +5510,7 @@ namespace Aws public: PublishToTopicOperation( ClientConnection &connection, - const PublishToTopicOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -5649,7 +5649,7 @@ namespace Aws SubscribeToCertificateUpdatesOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const SubscribeToCertificateUpdatesOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -5718,7 +5718,7 @@ namespace Aws public: VerifyClientDeviceIdentityOperation( ClientConnection &connection, - const VerifyClientDeviceIdentityOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -5787,7 +5787,7 @@ namespace Aws public: AuthorizeClientDeviceActionOperation( ClientConnection &connection, - const AuthorizeClientDeviceActionOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -5853,7 +5853,7 @@ namespace Aws public: ListComponentsOperation( ClientConnection &connection, - const ListComponentsOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -5919,7 +5919,7 @@ namespace Aws public: CreateDebugPasswordOperation( ClientConnection &connection, - const CreateDebugPasswordOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -5985,7 +5985,7 @@ namespace Aws public: GetThingShadowOperation( ClientConnection &connection, - const GetThingShadowOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6054,7 +6054,7 @@ namespace Aws public: SendConfigurationValidityReportOperation( ClientConnection &connection, - const SendConfigurationValidityReportOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6120,7 +6120,7 @@ namespace Aws public: UpdateThingShadowOperation( ClientConnection &connection, - const UpdateThingShadowOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6186,7 +6186,7 @@ namespace Aws public: UpdateConfigurationOperation( ClientConnection &connection, - const UpdateConfigurationOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6255,7 +6255,7 @@ namespace Aws public: ValidateAuthorizationTokenOperation( ClientConnection &connection, - const ValidateAuthorizationTokenOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6321,7 +6321,7 @@ namespace Aws public: RestartComponentOperation( ClientConnection &connection, - const RestartComponentOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6390,7 +6390,7 @@ namespace Aws public: GetLocalDeploymentStatusOperation( ClientConnection &connection, - const GetLocalDeploymentStatusOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6456,7 +6456,7 @@ namespace Aws public: GetSecretValueOperation( ClientConnection &connection, - const GetSecretValueOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6522,7 +6522,7 @@ namespace Aws public: UpdateStateOperation( ClientConnection &connection, - const UpdateStateOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6590,7 +6590,7 @@ namespace Aws public: CancelLocalDeploymentOperation( ClientConnection &connection, - const CancelLocalDeploymentOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6659,7 +6659,7 @@ namespace Aws public: ListNamedShadowsForThingOperation( ClientConnection &connection, - const ListNamedShadowsForThingOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6788,7 +6788,7 @@ namespace Aws SubscribeToComponentUpdatesOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const SubscribeToComponentUpdatesOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6856,7 +6856,7 @@ namespace Aws public: ListLocalDeploymentsOperation( ClientConnection &connection, - const ListLocalDeploymentsOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6922,7 +6922,7 @@ namespace Aws public: StopComponentOperation( ClientConnection &connection, - const StopComponentOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -6988,7 +6988,7 @@ namespace Aws public: PauseComponentOperation( ClientConnection &connection, - const PauseComponentOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -7056,7 +7056,7 @@ namespace Aws public: CreateLocalDeploymentOperation( ClientConnection &connection, - const CreateLocalDeploymentOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) noexcept; /** @@ -7081,7 +7081,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API GreengrassCoreIpcServiceModel : public ServiceModel { public: - GreengrassCoreIpcServiceModel() noexcept; + GreengrassCoreIpcServiceModel(Aws::Crt::Allocator *allocator) noexcept; Aws::Crt::ScopedResource AllocateOperationErrorFromPayload( const Aws::Crt::String &errorModelName, Aws::Crt::StringView stringView, @@ -7090,41 +7090,40 @@ namespace Aws private: friend class GreengrassCoreIpcClient; - SubscribeToIoTCoreOperationContext m_subscribeToIoTCoreOperationContext; - ResumeComponentOperationContext m_resumeComponentOperationContext; - PublishToIoTCoreOperationContext m_publishToIoTCoreOperationContext; - SubscribeToConfigurationUpdateOperationContext m_subscribeToConfigurationUpdateOperationContext; - DeleteThingShadowOperationContext m_deleteThingShadowOperationContext; - PutComponentMetricOperationContext m_putComponentMetricOperationContext; - DeferComponentUpdateOperationContext m_deferComponentUpdateOperationContext; - SubscribeToValidateConfigurationUpdatesOperationContext - m_subscribeToValidateConfigurationUpdatesOperationContext; - GetConfigurationOperationContext m_getConfigurationOperationContext; - SubscribeToTopicOperationContext m_subscribeToTopicOperationContext; - GetComponentDetailsOperationContext m_getComponentDetailsOperationContext; - GetClientDeviceAuthTokenOperationContext m_getClientDeviceAuthTokenOperationContext; - PublishToTopicOperationContext m_publishToTopicOperationContext; - SubscribeToCertificateUpdatesOperationContext m_subscribeToCertificateUpdatesOperationContext; - VerifyClientDeviceIdentityOperationContext m_verifyClientDeviceIdentityOperationContext; - AuthorizeClientDeviceActionOperationContext m_authorizeClientDeviceActionOperationContext; - ListComponentsOperationContext m_listComponentsOperationContext; - CreateDebugPasswordOperationContext m_createDebugPasswordOperationContext; - GetThingShadowOperationContext m_getThingShadowOperationContext; - SendConfigurationValidityReportOperationContext m_sendConfigurationValidityReportOperationContext; - UpdateThingShadowOperationContext m_updateThingShadowOperationContext; - UpdateConfigurationOperationContext m_updateConfigurationOperationContext; - ValidateAuthorizationTokenOperationContext m_validateAuthorizationTokenOperationContext; - RestartComponentOperationContext m_restartComponentOperationContext; - GetLocalDeploymentStatusOperationContext m_getLocalDeploymentStatusOperationContext; - GetSecretValueOperationContext m_getSecretValueOperationContext; - UpdateStateOperationContext m_updateStateOperationContext; - CancelLocalDeploymentOperationContext m_cancelLocalDeploymentOperationContext; - ListNamedShadowsForThingOperationContext m_listNamedShadowsForThingOperationContext; - SubscribeToComponentUpdatesOperationContext m_subscribeToComponentUpdatesOperationContext; - ListLocalDeploymentsOperationContext m_listLocalDeploymentsOperationContext; - StopComponentOperationContext m_stopComponentOperationContext; - PauseComponentOperationContext m_pauseComponentOperationContext; - CreateLocalDeploymentOperationContext m_createLocalDeploymentOperationContext; + std::shared_ptr m_subscribeToIoTCoreOperationContext; + std::shared_ptr m_resumeComponentOperationContext; + std::shared_ptr m_publishToIoTCoreOperationContext; + std::shared_ptr m_subscribeToConfigurationUpdateOperationContext; + std::shared_ptr m_deleteThingShadowOperationContext; + std::shared_ptr m_putComponentMetricOperationContext; + std::shared_ptr m_deferComponentUpdateOperationContext; + std::shared_ptr m_subscribeToValidateConfigurationUpdatesOperationContext; + std::shared_ptr m_getConfigurationOperationContext; + std::shared_ptr m_subscribeToTopicOperationContext; + std::shared_ptr m_getComponentDetailsOperationContext; + std::shared_ptr m_getClientDeviceAuthTokenOperationContext; + std::shared_ptr m_publishToTopicOperationContext; + std::shared_ptr m_subscribeToCertificateUpdatesOperationContext; + std::shared_ptr m_verifyClientDeviceIdentityOperationContext; + std::shared_ptr m_authorizeClientDeviceActionOperationContext; + std::shared_ptr m_listComponentsOperationContext; + std::shared_ptr m_createDebugPasswordOperationContext; + std::shared_ptr m_getThingShadowOperationContext; + std::shared_ptr m_sendConfigurationValidityReportOperationContext; + std::shared_ptr m_updateThingShadowOperationContext; + std::shared_ptr m_updateConfigurationOperationContext; + std::shared_ptr m_validateAuthorizationTokenOperationContext; + std::shared_ptr m_restartComponentOperationContext; + std::shared_ptr m_getLocalDeploymentStatusOperationContext; + std::shared_ptr m_getSecretValueOperationContext; + std::shared_ptr m_updateStateOperationContext; + std::shared_ptr m_cancelLocalDeploymentOperationContext; + std::shared_ptr m_listNamedShadowsForThingOperationContext; + std::shared_ptr m_subscribeToComponentUpdatesOperationContext; + std::shared_ptr m_listLocalDeploymentsOperationContext; + std::shared_ptr m_stopComponentOperationContext; + std::shared_ptr m_pauseComponentOperationContext; + std::shared_ptr m_createLocalDeploymentOperationContext; Aws::Crt::Map m_modelNameToErrorResponse; }; } // namespace Greengrass diff --git a/greengrass_ipc/source/GreengrassCoreIpcClient.cpp b/greengrass_ipc/source/GreengrassCoreIpcClient.cpp index 1a00a3416..bee357030 100644 --- a/greengrass_ipc/source/GreengrassCoreIpcClient.cpp +++ b/greengrass_ipc/source/GreengrassCoreIpcClient.cpp @@ -16,7 +16,8 @@ namespace Aws GreengrassCoreIpcClient::GreengrassCoreIpcClient( Aws::Crt::Io::ClientBootstrap &clientBootstrap, Aws::Crt::Allocator *allocator) noexcept - : m_connection( + : m_greengrassCoreIpcServiceModel(allocator), + m_connection( Aws::Crt::MakeShared(allocator, allocator, clientBootstrap.GetUnderlyingHandle())), m_allocator(allocator), m_asyncLaunchMode(std::launch::deferred) { diff --git a/greengrass_ipc/source/GreengrassCoreIpcModel.cpp b/greengrass_ipc/source/GreengrassCoreIpcModel.cpp index c20f3a32a..486c656ec 100644 --- a/greengrass_ipc/source/GreengrassCoreIpcModel.cpp +++ b/greengrass_ipc/source/GreengrassCoreIpcModel.cpp @@ -7047,7 +7047,7 @@ namespace Aws SubscribeToIoTCoreOperation::SubscribeToIoTCoreOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const SubscribeToIoTCoreOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, streamHandler, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -7119,7 +7119,7 @@ namespace Aws ResumeComponentOperation::ResumeComponentOperation( ClientConnection &connection, - const ResumeComponentOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -7191,7 +7191,7 @@ namespace Aws PublishToIoTCoreOperation::PublishToIoTCoreOperation( ClientConnection &connection, - const PublishToIoTCoreOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -7294,7 +7294,7 @@ namespace Aws SubscribeToConfigurationUpdateOperation::SubscribeToConfigurationUpdateOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const SubscribeToConfigurationUpdateOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, streamHandler, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -7366,7 +7366,7 @@ namespace Aws DeleteThingShadowOperation::DeleteThingShadowOperation( ClientConnection &connection, - const DeleteThingShadowOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -7438,7 +7438,7 @@ namespace Aws PutComponentMetricOperation::PutComponentMetricOperation( ClientConnection &connection, - const PutComponentMetricOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -7510,7 +7510,7 @@ namespace Aws DeferComponentUpdateOperation::DeferComponentUpdateOperation( ClientConnection &connection, - const DeferComponentUpdateOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -7610,7 +7610,7 @@ namespace Aws SubscribeToValidateConfigurationUpdatesOperation::SubscribeToValidateConfigurationUpdatesOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const SubscribeToValidateConfigurationUpdatesOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, streamHandler, operationContext, allocator), m_resultPromise( @@ -7685,7 +7685,7 @@ namespace Aws GetConfigurationOperation::GetConfigurationOperation( ClientConnection &connection, - const GetConfigurationOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -7793,7 +7793,7 @@ namespace Aws SubscribeToTopicOperation::SubscribeToTopicOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const SubscribeToTopicOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, streamHandler, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -7865,7 +7865,7 @@ namespace Aws GetComponentDetailsOperation::GetComponentDetailsOperation( ClientConnection &connection, - const GetComponentDetailsOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -7937,7 +7937,7 @@ namespace Aws GetClientDeviceAuthTokenOperation::GetClientDeviceAuthTokenOperation( ClientConnection &connection, - const GetClientDeviceAuthTokenOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8009,7 +8009,7 @@ namespace Aws PublishToTopicOperation::PublishToTopicOperation( ClientConnection &connection, - const PublishToTopicOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8118,7 +8118,7 @@ namespace Aws SubscribeToCertificateUpdatesOperation::SubscribeToCertificateUpdatesOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const SubscribeToCertificateUpdatesOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, streamHandler, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8190,7 +8190,7 @@ namespace Aws VerifyClientDeviceIdentityOperation::VerifyClientDeviceIdentityOperation( ClientConnection &connection, - const VerifyClientDeviceIdentityOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8262,7 +8262,7 @@ namespace Aws AuthorizeClientDeviceActionOperation::AuthorizeClientDeviceActionOperation( ClientConnection &connection, - const AuthorizeClientDeviceActionOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8334,7 +8334,7 @@ namespace Aws ListComponentsOperation::ListComponentsOperation( ClientConnection &connection, - const ListComponentsOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8406,7 +8406,7 @@ namespace Aws CreateDebugPasswordOperation::CreateDebugPasswordOperation( ClientConnection &connection, - const CreateDebugPasswordOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8478,7 +8478,7 @@ namespace Aws GetThingShadowOperation::GetThingShadowOperation( ClientConnection &connection, - const GetThingShadowOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8551,7 +8551,7 @@ namespace Aws SendConfigurationValidityReportOperation::SendConfigurationValidityReportOperation( ClientConnection &connection, - const SendConfigurationValidityReportOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8623,7 +8623,7 @@ namespace Aws UpdateThingShadowOperation::UpdateThingShadowOperation( ClientConnection &connection, - const UpdateThingShadowOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8695,7 +8695,7 @@ namespace Aws UpdateConfigurationOperation::UpdateConfigurationOperation( ClientConnection &connection, - const UpdateConfigurationOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8767,7 +8767,7 @@ namespace Aws ValidateAuthorizationTokenOperation::ValidateAuthorizationTokenOperation( ClientConnection &connection, - const ValidateAuthorizationTokenOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8839,7 +8839,7 @@ namespace Aws RestartComponentOperation::RestartComponentOperation( ClientConnection &connection, - const RestartComponentOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8911,7 +8911,7 @@ namespace Aws GetLocalDeploymentStatusOperation::GetLocalDeploymentStatusOperation( ClientConnection &connection, - const GetLocalDeploymentStatusOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -8983,7 +8983,7 @@ namespace Aws GetSecretValueOperation::GetSecretValueOperation( ClientConnection &connection, - const GetSecretValueOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -9054,7 +9054,7 @@ namespace Aws UpdateStateOperation::UpdateStateOperation( ClientConnection &connection, - const UpdateStateOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -9126,7 +9126,7 @@ namespace Aws CancelLocalDeploymentOperation::CancelLocalDeploymentOperation( ClientConnection &connection, - const CancelLocalDeploymentOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -9198,7 +9198,7 @@ namespace Aws ListNamedShadowsForThingOperation::ListNamedShadowsForThingOperation( ClientConnection &connection, - const ListNamedShadowsForThingOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -9301,7 +9301,7 @@ namespace Aws SubscribeToComponentUpdatesOperation::SubscribeToComponentUpdatesOperation( ClientConnection &connection, std::shared_ptr streamHandler, - const SubscribeToComponentUpdatesOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, streamHandler, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -9373,7 +9373,7 @@ namespace Aws ListLocalDeploymentsOperation::ListLocalDeploymentsOperation( ClientConnection &connection, - const ListLocalDeploymentsOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -9445,7 +9445,7 @@ namespace Aws StopComponentOperation::StopComponentOperation( ClientConnection &connection, - const StopComponentOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -9517,7 +9517,7 @@ namespace Aws PauseComponentOperation::PauseComponentOperation( ClientConnection &connection, - const PauseComponentOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -9589,7 +9589,7 @@ namespace Aws CreateLocalDeploymentOperation::CreateLocalDeploymentOperation( ClientConnection &connection, - const CreateLocalDeploymentOperationContext &operationContext, + const std::shared_ptr &operationContext, Aws::Crt::Allocator *allocator) noexcept : ClientOperation(connection, nullptr, operationContext, allocator), m_resultPromise(Aws::Crt::MakeShared>(allocator)) @@ -9611,25 +9611,68 @@ namespace Aws return activateFuture; } - GreengrassCoreIpcServiceModel::GreengrassCoreIpcServiceModel() noexcept - : m_subscribeToIoTCoreOperationContext(*this), m_resumeComponentOperationContext(*this), - m_publishToIoTCoreOperationContext(*this), m_subscribeToConfigurationUpdateOperationContext(*this), - m_deleteThingShadowOperationContext(*this), m_putComponentMetricOperationContext(*this), - m_deferComponentUpdateOperationContext(*this), - m_subscribeToValidateConfigurationUpdatesOperationContext(*this), - m_getConfigurationOperationContext(*this), m_subscribeToTopicOperationContext(*this), - m_getComponentDetailsOperationContext(*this), m_getClientDeviceAuthTokenOperationContext(*this), - m_publishToTopicOperationContext(*this), m_subscribeToCertificateUpdatesOperationContext(*this), - m_verifyClientDeviceIdentityOperationContext(*this), m_authorizeClientDeviceActionOperationContext(*this), - m_listComponentsOperationContext(*this), m_createDebugPasswordOperationContext(*this), - m_getThingShadowOperationContext(*this), m_sendConfigurationValidityReportOperationContext(*this), - m_updateThingShadowOperationContext(*this), m_updateConfigurationOperationContext(*this), - m_validateAuthorizationTokenOperationContext(*this), m_restartComponentOperationContext(*this), - m_getLocalDeploymentStatusOperationContext(*this), m_getSecretValueOperationContext(*this), - m_updateStateOperationContext(*this), m_cancelLocalDeploymentOperationContext(*this), - m_listNamedShadowsForThingOperationContext(*this), m_subscribeToComponentUpdatesOperationContext(*this), - m_listLocalDeploymentsOperationContext(*this), m_stopComponentOperationContext(*this), - m_pauseComponentOperationContext(*this), m_createLocalDeploymentOperationContext(*this) + GreengrassCoreIpcServiceModel::GreengrassCoreIpcServiceModel(Aws::Crt::Allocator *allocator) noexcept + : m_subscribeToIoTCoreOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_resumeComponentOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_publishToIoTCoreOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_subscribeToConfigurationUpdateOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_deleteThingShadowOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_putComponentMetricOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_deferComponentUpdateOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_subscribeToValidateConfigurationUpdatesOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_getConfigurationOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_subscribeToTopicOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_getComponentDetailsOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_getClientDeviceAuthTokenOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_publishToTopicOperationContext(Aws::Crt::MakeShared(allocator, *this)), + m_subscribeToCertificateUpdatesOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_verifyClientDeviceIdentityOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_authorizeClientDeviceActionOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_listComponentsOperationContext(Aws::Crt::MakeShared(allocator, *this)), + m_createDebugPasswordOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_getThingShadowOperationContext(Aws::Crt::MakeShared(allocator, *this)), + m_sendConfigurationValidityReportOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_updateThingShadowOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_updateConfigurationOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_validateAuthorizationTokenOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_restartComponentOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_getLocalDeploymentStatusOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_getSecretValueOperationContext(Aws::Crt::MakeShared(allocator, *this)), + m_updateStateOperationContext(Aws::Crt::MakeShared(allocator, *this)), + m_cancelLocalDeploymentOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_listNamedShadowsForThingOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_subscribeToComponentUpdatesOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_listLocalDeploymentsOperationContext( + Aws::Crt::MakeShared(allocator, *this)), + m_stopComponentOperationContext(Aws::Crt::MakeShared(allocator, *this)), + m_pauseComponentOperationContext(Aws::Crt::MakeShared(allocator, *this)), + m_createLocalDeploymentOperationContext( + Aws::Crt::MakeShared(allocator, *this)) { } From 94c78c983e64932b338d509d70126d7cd704b212 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Thu, 19 Jun 2025 09:32:36 -0700 Subject: [PATCH 44/56] Remove operation context subclasses from public API --- eventstream_rpc/tests/EchoTestRpcClient.cpp | 1 + eventstream_rpc/tests/EchoTestRpcModel.cpp | 96 +++ .../tests/include/awstest/EchoTestRpcModel.h | 96 --- .../aws/greengrass/GreengrassCoreIpcModel.h | 546 ------------------ .../source/GreengrassCoreIpcClient.cpp | 1 + .../source/GreengrassCoreIpcModel.cpp | 545 +++++++++++++++++ 6 files changed, 643 insertions(+), 642 deletions(-) diff --git a/eventstream_rpc/tests/EchoTestRpcClient.cpp b/eventstream_rpc/tests/EchoTestRpcClient.cpp index 3a568b84f..e0671dc26 100644 --- a/eventstream_rpc/tests/EchoTestRpcClient.cpp +++ b/eventstream_rpc/tests/EchoTestRpcClient.cpp @@ -11,6 +11,7 @@ namespace Awstest { + EchoTestRpcClient::EchoTestRpcClient( Aws::Crt::Io::ClientBootstrap &clientBootstrap, Aws::Crt::Allocator *allocator) noexcept diff --git a/eventstream_rpc/tests/EchoTestRpcModel.cpp b/eventstream_rpc/tests/EchoTestRpcModel.cpp index 07e81aa13..c46008bec 100644 --- a/eventstream_rpc/tests/EchoTestRpcModel.cpp +++ b/eventstream_rpc/tests/EchoTestRpcModel.cpp @@ -975,6 +975,22 @@ namespace Awstest AbstractShapeBase::s_customDeleter(static_cast(shape)); } + class GetAllProductsOperationContext : public OperationModelContext + { + public: + GetAllProductsOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + GetAllProductsOperationContext::GetAllProductsOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) { @@ -1045,6 +1061,22 @@ namespace Awstest return activateFuture; } + class CauseServiceErrorOperationContext : public OperationModelContext + { + public: + CauseServiceErrorOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + CauseServiceErrorOperationContext::CauseServiceErrorOperationContext( const EchoTestRpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -1141,6 +1173,22 @@ namespace Awstest return streamShouldTerminate; } + class CauseStreamServiceToErrorOperationContext : public OperationModelContext + { + public: + CauseStreamServiceToErrorOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + CauseStreamServiceToErrorOperationContext::CauseStreamServiceToErrorOperationContext( const EchoTestRpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -1239,6 +1287,22 @@ namespace Awstest return streamShouldTerminate; } + class EchoStreamMessagesOperationContext : public OperationModelContext + { + public: + EchoStreamMessagesOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + EchoStreamMessagesOperationContext::EchoStreamMessagesOperationContext( const EchoTestRpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -1318,6 +1382,22 @@ namespace Awstest static_cast(&message), std::move(onMessageFlushCallback)); } + class EchoMessageOperationContext : public OperationModelContext + { + public: + EchoMessageOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + EchoMessageOperationContext::EchoMessageOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) { @@ -1388,6 +1468,22 @@ namespace Awstest return activateFuture; } + class GetAllCustomersOperationContext : public OperationModelContext + { + public: + GetAllCustomersOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + GetAllCustomersOperationContext::GetAllCustomersOperationContext( const EchoTestRpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) diff --git a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h index 4c46677e7..af7a30c95 100644 --- a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h +++ b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h @@ -679,22 +679,6 @@ namespace Awstest private: }; - class AWS_ECHOTESTRPC_API GetAllProductsOperationContext : public OperationModelContext - { - public: - GetAllProductsOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_ECHOTESTRPC_API GetAllProductsResult { public: @@ -745,22 +729,6 @@ namespace Awstest std::shared_ptr> m_resultPromise; }; - class AWS_ECHOTESTRPC_API CauseServiceErrorOperationContext : public OperationModelContext - { - public: - CauseServiceErrorOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_ECHOTESTRPC_API CauseServiceErrorResult { public: @@ -860,22 +828,6 @@ namespace Awstest bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; - class AWS_ECHOTESTRPC_API CauseStreamServiceToErrorOperationContext : public OperationModelContext - { - public: - CauseStreamServiceToErrorOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_ECHOTESTRPC_API CauseStreamServiceToErrorResult { public: @@ -980,22 +932,6 @@ namespace Awstest bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; - class AWS_ECHOTESTRPC_API EchoStreamMessagesOperationContext : public OperationModelContext - { - public: - EchoStreamMessagesOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_ECHOTESTRPC_API EchoStreamMessagesResult { public: @@ -1059,22 +995,6 @@ namespace Awstest std::shared_ptr> m_resultPromise; }; - class AWS_ECHOTESTRPC_API EchoMessageOperationContext : public OperationModelContext - { - public: - EchoMessageOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_ECHOTESTRPC_API EchoMessageResult { public: @@ -1125,22 +1045,6 @@ namespace Awstest std::shared_ptr> m_resultPromise; }; - class AWS_ECHOTESTRPC_API GetAllCustomersOperationContext : public OperationModelContext - { - public: - GetAllCustomersOperationContext(const EchoTestRpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_ECHOTESTRPC_API GetAllCustomersResult { public: diff --git a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h index 068ec8e69..e4dbd9e3b 100644 --- a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h +++ b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h @@ -4478,22 +4478,6 @@ namespace Aws bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToIoTCoreOperationContext : public OperationModelContext - { - public: - SubscribeToIoTCoreOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API SubscribeToIoTCoreResult { public: @@ -4545,22 +4529,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API ResumeComponentOperationContext : public OperationModelContext - { - public: - ResumeComponentOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API ResumeComponentResult { public: @@ -4611,22 +4579,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API PublishToIoTCoreOperationContext : public OperationModelContext - { - public: - PublishToIoTCoreOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API PublishToIoTCoreResult { public: @@ -4736,22 +4688,6 @@ namespace Aws bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToConfigurationUpdateOperationContext : public OperationModelContext - { - public: - SubscribeToConfigurationUpdateOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API SubscribeToConfigurationUpdateResult { public: @@ -4806,22 +4742,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API DeleteThingShadowOperationContext : public OperationModelContext - { - public: - DeleteThingShadowOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API DeleteThingShadowResult { public: @@ -4872,22 +4792,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API PutComponentMetricOperationContext : public OperationModelContext - { - public: - PutComponentMetricOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API PutComponentMetricResult { public: @@ -4938,22 +4842,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API DeferComponentUpdateOperationContext : public OperationModelContext - { - public: - DeferComponentUpdateOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API DeferComponentUpdateResult { public: @@ -5056,24 +4944,6 @@ namespace Aws bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToValidateConfigurationUpdatesOperationContext - : public OperationModelContext - { - public: - SubscribeToValidateConfigurationUpdatesOperationContext( - const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API SubscribeToValidateConfigurationUpdatesResult { public: @@ -5129,22 +4999,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API GetConfigurationOperationContext : public OperationModelContext - { - public: - GetConfigurationOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API GetConfigurationResult { public: @@ -5264,22 +5118,6 @@ namespace Aws bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToTopicOperationContext : public OperationModelContext - { - public: - SubscribeToTopicOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API SubscribeToTopicResult { public: @@ -5331,22 +5169,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API GetComponentDetailsOperationContext : public OperationModelContext - { - public: - GetComponentDetailsOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API GetComponentDetailsResult { public: @@ -5397,22 +5219,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API GetClientDeviceAuthTokenOperationContext : public OperationModelContext - { - public: - GetClientDeviceAuthTokenOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API GetClientDeviceAuthTokenResult { public: @@ -5466,22 +5272,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API PublishToTopicOperationContext : public OperationModelContext - { - public: - PublishToTopicOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API PublishToTopicResult { public: @@ -5601,22 +5391,6 @@ namespace Aws bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToCertificateUpdatesOperationContext : public OperationModelContext - { - public: - SubscribeToCertificateUpdatesOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API SubscribeToCertificateUpdatesResult { public: @@ -5671,22 +5445,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API VerifyClientDeviceIdentityOperationContext : public OperationModelContext - { - public: - VerifyClientDeviceIdentityOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API VerifyClientDeviceIdentityResult { public: @@ -5740,22 +5498,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API AuthorizeClientDeviceActionOperationContext : public OperationModelContext - { - public: - AuthorizeClientDeviceActionOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API AuthorizeClientDeviceActionResult { public: @@ -5809,22 +5551,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API ListComponentsOperationContext : public OperationModelContext - { - public: - ListComponentsOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API ListComponentsResult { public: @@ -5875,22 +5601,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API CreateDebugPasswordOperationContext : public OperationModelContext - { - public: - CreateDebugPasswordOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API CreateDebugPasswordResult { public: @@ -5941,22 +5651,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API GetThingShadowOperationContext : public OperationModelContext - { - public: - GetThingShadowOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API GetThingShadowResult { public: @@ -6007,22 +5701,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API SendConfigurationValidityReportOperationContext : public OperationModelContext - { - public: - SendConfigurationValidityReportOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API SendConfigurationValidityReportResult { public: @@ -6076,22 +5754,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API UpdateThingShadowOperationContext : public OperationModelContext - { - public: - UpdateThingShadowOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API UpdateThingShadowResult { public: @@ -6142,22 +5804,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API UpdateConfigurationOperationContext : public OperationModelContext - { - public: - UpdateConfigurationOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API UpdateConfigurationResult { public: @@ -6208,22 +5854,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API ValidateAuthorizationTokenOperationContext : public OperationModelContext - { - public: - ValidateAuthorizationTokenOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API ValidateAuthorizationTokenResult { public: @@ -6277,22 +5907,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API RestartComponentOperationContext : public OperationModelContext - { - public: - RestartComponentOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API RestartComponentResult { public: @@ -6343,22 +5957,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API GetLocalDeploymentStatusOperationContext : public OperationModelContext - { - public: - GetLocalDeploymentStatusOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API GetLocalDeploymentStatusResult { public: @@ -6412,22 +6010,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API GetSecretValueOperationContext : public OperationModelContext - { - public: - GetSecretValueOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API GetSecretValueResult { public: @@ -6478,22 +6060,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API UpdateStateOperationContext : public OperationModelContext - { - public: - UpdateStateOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API UpdateStateResult { public: @@ -6544,22 +6110,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API CancelLocalDeploymentOperationContext : public OperationModelContext - { - public: - CancelLocalDeploymentOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API CancelLocalDeploymentResult { public: @@ -6612,22 +6162,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API ListNamedShadowsForThingOperationContext : public OperationModelContext - { - public: - ListNamedShadowsForThingOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API ListNamedShadowsForThingResult { public: @@ -6740,22 +6274,6 @@ namespace Aws bool OnStreamError(Aws::Crt::ScopedResource error, RpcError rpcError) override; }; - class AWS_GREENGRASSCOREIPC_API SubscribeToComponentUpdatesOperationContext : public OperationModelContext - { - public: - SubscribeToComponentUpdatesOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API SubscribeToComponentUpdatesResult { public: @@ -6810,22 +6328,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API ListLocalDeploymentsOperationContext : public OperationModelContext - { - public: - ListLocalDeploymentsOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API ListLocalDeploymentsResult { public: @@ -6878,22 +6380,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API StopComponentOperationContext : public OperationModelContext - { - public: - StopComponentOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API StopComponentResult { public: @@ -6944,22 +6430,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API PauseComponentOperationContext : public OperationModelContext - { - public: - PauseComponentOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API PauseComponentResult { public: @@ -7010,22 +6480,6 @@ namespace Aws std::shared_ptr> m_resultPromise; }; - class AWS_GREENGRASSCOREIPC_API CreateLocalDeploymentOperationContext : public OperationModelContext - { - public: - CreateLocalDeploymentOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; - Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( - Aws::Crt::StringView stringView, - Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; - Aws::Crt::String GetRequestModelName() const noexcept override; - Aws::Crt::String GetInitialResponseModelName() const noexcept override; - Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; - Aws::Crt::String GetOperationName() const noexcept override; - }; - class AWS_GREENGRASSCOREIPC_API CreateLocalDeploymentResult { public: diff --git a/greengrass_ipc/source/GreengrassCoreIpcClient.cpp b/greengrass_ipc/source/GreengrassCoreIpcClient.cpp index bee357030..765156874 100644 --- a/greengrass_ipc/source/GreengrassCoreIpcClient.cpp +++ b/greengrass_ipc/source/GreengrassCoreIpcClient.cpp @@ -13,6 +13,7 @@ namespace Aws { namespace Greengrass { + GreengrassCoreIpcClient::GreengrassCoreIpcClient( Aws::Crt::Io::ClientBootstrap &clientBootstrap, Aws::Crt::Allocator *allocator) noexcept diff --git a/greengrass_ipc/source/GreengrassCoreIpcModel.cpp b/greengrass_ipc/source/GreengrassCoreIpcModel.cpp index 486c656ec..d91723063 100644 --- a/greengrass_ipc/source/GreengrassCoreIpcModel.cpp +++ b/greengrass_ipc/source/GreengrassCoreIpcModel.cpp @@ -6998,6 +6998,22 @@ namespace Aws return streamShouldTerminate; } + class SubscribeToIoTCoreOperationContext : public OperationModelContext + { + public: + SubscribeToIoTCoreOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + SubscribeToIoTCoreOperationContext::SubscribeToIoTCoreOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -7069,6 +7085,22 @@ namespace Aws return activateFuture; } + class ResumeComponentOperationContext : public OperationModelContext + { + public: + ResumeComponentOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + ResumeComponentOperationContext::ResumeComponentOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -7141,6 +7173,22 @@ namespace Aws return activateFuture; } + class PublishToIoTCoreOperationContext : public OperationModelContext + { + public: + PublishToIoTCoreOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + PublishToIoTCoreOperationContext::PublishToIoTCoreOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -7245,6 +7293,22 @@ namespace Aws return streamShouldTerminate; } + class SubscribeToConfigurationUpdateOperationContext : public OperationModelContext + { + public: + SubscribeToConfigurationUpdateOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + SubscribeToConfigurationUpdateOperationContext::SubscribeToConfigurationUpdateOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -7316,6 +7380,22 @@ namespace Aws return activateFuture; } + class DeleteThingShadowOperationContext : public OperationModelContext + { + public: + DeleteThingShadowOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + DeleteThingShadowOperationContext::DeleteThingShadowOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -7388,6 +7468,22 @@ namespace Aws return activateFuture; } + class PutComponentMetricOperationContext : public OperationModelContext + { + public: + PutComponentMetricOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + PutComponentMetricOperationContext::PutComponentMetricOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -7460,6 +7556,22 @@ namespace Aws return activateFuture; } + class DeferComponentUpdateOperationContext : public OperationModelContext + { + public: + DeferComponentUpdateOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + DeferComponentUpdateOperationContext::DeferComponentUpdateOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -7558,6 +7670,23 @@ namespace Aws return streamShouldTerminate; } + class SubscribeToValidateConfigurationUpdatesOperationContext : public OperationModelContext + { + public: + SubscribeToValidateConfigurationUpdatesOperationContext( + const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + SubscribeToValidateConfigurationUpdatesOperationContext:: SubscribeToValidateConfigurationUpdatesOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept @@ -7635,6 +7764,22 @@ namespace Aws return activateFuture; } + class GetConfigurationOperationContext : public OperationModelContext + { + public: + GetConfigurationOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + GetConfigurationOperationContext::GetConfigurationOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -7744,6 +7889,22 @@ namespace Aws return streamShouldTerminate; } + class SubscribeToTopicOperationContext : public OperationModelContext + { + public: + SubscribeToTopicOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + SubscribeToTopicOperationContext::SubscribeToTopicOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -7815,6 +7976,22 @@ namespace Aws return activateFuture; } + class GetComponentDetailsOperationContext : public OperationModelContext + { + public: + GetComponentDetailsOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + GetComponentDetailsOperationContext::GetComponentDetailsOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -7887,6 +8064,22 @@ namespace Aws return activateFuture; } + class GetClientDeviceAuthTokenOperationContext : public OperationModelContext + { + public: + GetClientDeviceAuthTokenOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + GetClientDeviceAuthTokenOperationContext::GetClientDeviceAuthTokenOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -7959,6 +8152,22 @@ namespace Aws return activateFuture; } + class PublishToTopicOperationContext : public OperationModelContext + { + public: + PublishToTopicOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + PublishToTopicOperationContext::PublishToTopicOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -8069,6 +8278,22 @@ namespace Aws return streamShouldTerminate; } + class SubscribeToCertificateUpdatesOperationContext : public OperationModelContext + { + public: + SubscribeToCertificateUpdatesOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + SubscribeToCertificateUpdatesOperationContext::SubscribeToCertificateUpdatesOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -8140,6 +8365,22 @@ namespace Aws return activateFuture; } + class VerifyClientDeviceIdentityOperationContext : public OperationModelContext + { + public: + VerifyClientDeviceIdentityOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + VerifyClientDeviceIdentityOperationContext::VerifyClientDeviceIdentityOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -8212,6 +8453,22 @@ namespace Aws return activateFuture; } + class AuthorizeClientDeviceActionOperationContext : public OperationModelContext + { + public: + AuthorizeClientDeviceActionOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + AuthorizeClientDeviceActionOperationContext::AuthorizeClientDeviceActionOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -8284,6 +8541,22 @@ namespace Aws return activateFuture; } + class ListComponentsOperationContext : public OperationModelContext + { + public: + ListComponentsOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + ListComponentsOperationContext::ListComponentsOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -8356,6 +8629,22 @@ namespace Aws return activateFuture; } + class CreateDebugPasswordOperationContext : public OperationModelContext + { + public: + CreateDebugPasswordOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + CreateDebugPasswordOperationContext::CreateDebugPasswordOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -8428,6 +8717,22 @@ namespace Aws return activateFuture; } + class GetThingShadowOperationContext : public OperationModelContext + { + public: + GetThingShadowOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + GetThingShadowOperationContext::GetThingShadowOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -8500,6 +8805,22 @@ namespace Aws return activateFuture; } + class SendConfigurationValidityReportOperationContext : public OperationModelContext + { + public: + SendConfigurationValidityReportOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + SendConfigurationValidityReportOperationContext::SendConfigurationValidityReportOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -8573,6 +8894,22 @@ namespace Aws return activateFuture; } + class UpdateThingShadowOperationContext : public OperationModelContext + { + public: + UpdateThingShadowOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + UpdateThingShadowOperationContext::UpdateThingShadowOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -8645,6 +8982,22 @@ namespace Aws return activateFuture; } + class UpdateConfigurationOperationContext : public OperationModelContext + { + public: + UpdateConfigurationOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + UpdateConfigurationOperationContext::UpdateConfigurationOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -8717,6 +9070,22 @@ namespace Aws return activateFuture; } + class ValidateAuthorizationTokenOperationContext : public OperationModelContext + { + public: + ValidateAuthorizationTokenOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + ValidateAuthorizationTokenOperationContext::ValidateAuthorizationTokenOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -8789,6 +9158,22 @@ namespace Aws return activateFuture; } + class RestartComponentOperationContext : public OperationModelContext + { + public: + RestartComponentOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + RestartComponentOperationContext::RestartComponentOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -8861,6 +9246,22 @@ namespace Aws return activateFuture; } + class GetLocalDeploymentStatusOperationContext : public OperationModelContext + { + public: + GetLocalDeploymentStatusOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + GetLocalDeploymentStatusOperationContext::GetLocalDeploymentStatusOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -8933,6 +9334,22 @@ namespace Aws return activateFuture; } + class GetSecretValueOperationContext : public OperationModelContext + { + public: + GetSecretValueOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + GetSecretValueOperationContext::GetSecretValueOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -9005,6 +9422,22 @@ namespace Aws return activateFuture; } + class UpdateStateOperationContext : public OperationModelContext + { + public: + UpdateStateOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + UpdateStateOperationContext::UpdateStateOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -9076,6 +9509,22 @@ namespace Aws return activateFuture; } + class CancelLocalDeploymentOperationContext : public OperationModelContext + { + public: + CancelLocalDeploymentOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + CancelLocalDeploymentOperationContext::CancelLocalDeploymentOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -9148,6 +9597,22 @@ namespace Aws return activateFuture; } + class ListNamedShadowsForThingOperationContext : public OperationModelContext + { + public: + ListNamedShadowsForThingOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + ListNamedShadowsForThingOperationContext::ListNamedShadowsForThingOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -9252,6 +9717,22 @@ namespace Aws return streamShouldTerminate; } + class SubscribeToComponentUpdatesOperationContext : public OperationModelContext + { + public: + SubscribeToComponentUpdatesOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + SubscribeToComponentUpdatesOperationContext::SubscribeToComponentUpdatesOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -9323,6 +9804,22 @@ namespace Aws return activateFuture; } + class ListLocalDeploymentsOperationContext : public OperationModelContext + { + public: + ListLocalDeploymentsOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + ListLocalDeploymentsOperationContext::ListLocalDeploymentsOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -9395,6 +9892,22 @@ namespace Aws return activateFuture; } + class StopComponentOperationContext : public OperationModelContext + { + public: + StopComponentOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + StopComponentOperationContext::StopComponentOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -9467,6 +9980,22 @@ namespace Aws return activateFuture; } + class PauseComponentOperationContext : public OperationModelContext + { + public: + PauseComponentOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + PauseComponentOperationContext::PauseComponentOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) @@ -9539,6 +10068,22 @@ namespace Aws return activateFuture; } + class CreateLocalDeploymentOperationContext : public OperationModelContext + { + public: + CreateLocalDeploymentOperationContext(const GreengrassCoreIpcServiceModel &serviceModel) noexcept; + Aws::Crt::ScopedResource AllocateInitialResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::ScopedResource AllocateStreamingResponseFromPayload( + Aws::Crt::StringView stringView, + Aws::Crt::Allocator *allocator = Aws::Crt::g_allocator) const noexcept override; + Aws::Crt::String GetRequestModelName() const noexcept override; + Aws::Crt::String GetInitialResponseModelName() const noexcept override; + Aws::Crt::Optional GetStreamingResponseModelName() const noexcept override; + Aws::Crt::String GetOperationName() const noexcept override; + }; + CreateLocalDeploymentOperationContext::CreateLocalDeploymentOperationContext( const GreengrassCoreIpcServiceModel &serviceModel) noexcept : OperationModelContext(serviceModel) From 95524498d4c9e0b1a0cf2cbef5a27f309b491eea Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Fri, 20 Jun 2025 14:12:58 -0700 Subject: [PATCH 45/56] Commentary --- .../aws/eventstreamrpc/EventStreamClient.h | 3 - eventstream_rpc/source/EventStreamClient.cpp | 339 ++++++++++----- eventstream_rpc/tests/CMakeLists.txt | 1 + .../tests/EventStreamClientTest.cpp | 401 ++---------------- 4 files changed, 267 insertions(+), 477 deletions(-) diff --git a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h index 4ee17c6f0..c1e4ab5b1 100644 --- a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h +++ b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h @@ -33,7 +33,6 @@ namespace Aws class MessageAmendment; class ClientOperation; class ClientConnection; - class ClientContinuation; class ClientContinuationHandler; using HeaderValueType = aws_event_stream_header_value_type; @@ -147,8 +146,6 @@ namespace Aws EVENT_STREAM_RPC_UNMAPPED_DATA, EVENT_STREAM_RPC_UNSUPPORTED_CONTENT_TYPE, EVENT_STREAM_RPC_CRT_ERROR, - EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED, - EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS, EVENT_STREAM_RPC_CONTINUATION_NOT_YET_OPENED, }; diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 46687d116..1637dc446 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -23,6 +23,29 @@ namespace Aws { namespace Eventstreamrpc { + /* + * User-data class for completing message flush callbacks. The C++ API supports both callbacks and + * promise completion and so in turn this must support both. + * + * Additionally, because we synthesize callbacks (in order to have non-blocking destruction), this class + * must also support multiple users trying to complete it (with the first one winning) in a thread-safe + * manner. + * + * The general pattern, when needed, results in two possibilities: + * + * (1) Create a (shared_ptr) instance and submit it to the C API via activate()/connect()/send_message() + * (2) Keep a shared_ptr back in the connection/continuation as needed + * (3) C client sends message and invokes completion. A later completion by the binding does nothing. + * + * or + * + * (1) Create a (shared_ptr) instance and submit it to the C API via activate()/connect()/send_message() + * (2) Keep a shared_ptr back in the connection/continuation as needed + * (3) Connection/continuation shutdown happens before the C client does the message flush, so the callbacks + * get triggered by the shutdown. When the C client goes to complete, the completion does nothing (but + * is memory-safe). + + */ class OnMessageFlushCallbackContainer { public: @@ -99,6 +122,10 @@ namespace Aws } m_sharedState; }; + /* + * We can't submit a shared_ptr to the C layer, only a raw pointer. So this class just wraps a shared_ptr + * to a callback container. + */ class OnMessageFlushCallbackContainerWrapper { public: @@ -142,6 +169,7 @@ namespace Aws std::shared_ptr m_container; }; + /* The flush completion callback function that the low-level C client will invoke */ static void s_protocolMessageCallback(int errorCode, void *userData) noexcept { auto *wrapper = static_cast(userData); @@ -333,10 +361,6 @@ namespace Aws ret += Crt::ErrorDebugString(crtError); return ret; } - case EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED: - return "EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED"; - case EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS: - return "EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS"; case EVENT_STREAM_RPC_CONTINUATION_NOT_YET_OPENED: return "EVENT_STREAM_RPC_CONTINUATION_NOT_YET_OPENED"; } @@ -484,23 +508,38 @@ namespace Aws /* * Eventstream Connection Refactor * - * Part 1 of an effort to refactor the eventstream bindings to conform to the latest CRT binding guidelines. - * * For connections, we now enforce the following invariants for correctness: * * 1. No callback is made while a lock is held. We perform callbacks by having a transactional callback context * that is moved out of shared state (under the lock), but the callback context does not perform its work until * the lock is released. - * 2. No C API call is made while the lock is held. TODO: explain the pattern - * Lock-OptimisticExclusiveStateChange-Unlock-APICall-OnFailureUndoStateChange + * + * 2. No C API call is made while the lock is held. This prevents deadlock in degenerate cases where callbacks + * get invoked synchronously (for example, trying to send a message on a closed connection). * * 3. No destructor blocking or synchronization. In order to provide the best behavioral backwards * compatibility, we "synthesize" the callbacks that would occur at destruction when we kick off the async * cleanup process. Later, when the asynchronous events occur that would normally trigger a callback occur, we * ignore them. + * * 4. A self-reference (via shared_ptr member) guarantees the binding impl stays alive longer than the C * objects. The public binding object also keeps a shared_ptr to the impl, so final destruction only occurs * once both the public binding object's destructor has run and no C connection object is still alive. + * + * + * Invariant (2) lead to a common pattern throughout the bindings: + * + * (1) Lock the shared state + * (2) Optimistically update the shared state as if action-to-take was successful + * (3) Unlock the shared state + * (4) Invoke the C API + * (5) If the C API was unsuccessful (rare case), lock the shared state, rollback the optimistic update, unlock + * + * For this to be correct, the shared state update in (2) must exclude other pathways from trying to do the same + * action. For example, if a continuation is created but not activated, calling activate optimistically + * updates the state to PENDING_ACTIVATE, which prevents concurrent callers from doing anything. If the C + * call to activate() fails, then we roll back from PENDING_ACTIVATE, allowing future callers to again try + * and activate the continuation. */ /* What kind of callback should this context trigger? */ @@ -519,7 +558,7 @@ namespace Aws * (3) Helping ensure callbacks always occur once and only once * (4) Passing delayed state (like an error code) forward until the callback can safely be triggered * - * We rely heavily on careful move semantics to ensure (2) and (3) + * We rely on move semantics to ensure (2) and (3) */ class ConnectionCallbackContext { @@ -600,16 +639,18 @@ namespace Aws } /* - * Returns a callback context that should be invoked, and moves this context into a state that should be - * invoked when the connection is closed + * Returns a callback context that should be invoked now (indicating successful connection), and moves + * this context into a state that should be invoked when the connection is closed. */ ConnectionCallbackContext TransitionToConnected() { + // connection success context caller should invoke ConnectionCallbackContext context = {}; context.m_action = ConnectionCallbackActionType::CompleteConnectPromise; context.m_connectPromise = std::move(m_connectPromise); context.m_connectionSuccessCallback = m_connectionSuccessCallback; + // we're now a disconnect context m_action = ConnectionCallbackActionType::DisconnectionCallback; m_error = {EVENT_STREAM_RPC_SUCCESS, AWS_ERROR_SUCCESS}; m_connectPromise = {}; @@ -664,6 +705,7 @@ namespace Aws bool IsOpen() const noexcept; + // Exclusively called by ClientConnection's destructor. void Shutdown() noexcept; private: @@ -676,10 +718,19 @@ namespace Aws enum class ClientState { + // There is no C connection and no pending attempt to create one Disconnected, + + // There is a pending attempt to create a C connection, but it has not completed yet PendingConnect, + + // We have a C connection, but the Connect->Connack handshake has not completed yet PendingConnack, + + // We have a C connection ready to be used Connected, + + // Our formerly-connected C connection is in the process of shutting down Disconnecting, }; @@ -688,6 +739,8 @@ namespace Aws ConnectionLifecycleHandler *m_lifecycleHandler; // cannot be made a shared_ptr sadly ConnectMessageAmender m_connectMessageAmender; ConnectionConfig m_connectionConfig; + + // Non-null as long as something connection-related is going on in the C layer. std::shared_ptr m_selfReference; aws_client_bootstrap *m_bootstrap; aws_event_loop *m_eventLoop; @@ -761,6 +814,13 @@ namespace Aws aws_task_init(&m_task, s_zeroSharedReference, this, "AwsEventstreamConnectionImplClearSharedTask"); } + /* + * This gets called in the following cases: + * + * (1) Synchronous failure to initiate a connection + * (2) Connection setup failure (async callback) + * (3) Connnection (that was successfully established) shutdown completion (async callback) + */ void ClientConnectionImpl::MoveToDisconnected(RpcError error) noexcept { auto *clearSharedTask = @@ -774,7 +834,9 @@ namespace Aws m_sharedState.m_currentState = ClientState::Disconnected; m_sharedState.m_desiredState = ClientState::Disconnected; m_sharedState.m_callbackContext.SetError(error); - m_selfReference = nullptr; // impossible to drop, since the clear shared task just took a ref + m_selfReference = nullptr; // doesn't actually drop, since the clear shared task just took a ref + + // If we've called shutdown, then no further callbacks should be done if (!m_sharedState.m_hasShutDown) { localContext = std::move(m_sharedState.m_callbackContext); @@ -787,6 +849,9 @@ namespace Aws aws_event_loop_schedule_task_now(m_eventLoop, &clearSharedTask->m_task); } + /* + * Common logic to kick off the process of shutting down the connection + */ void ClientConnectionImpl::CloseInternal(bool isShutdown) noexcept { struct aws_event_stream_rpc_client_connection *closeConnection = nullptr; @@ -812,14 +877,22 @@ namespace Aws if (isShutdown) { + /* + * When shutting down (ClientConnection::~ClientConnection only) we synthesize any disconnect/ + * connection-failure callbacks that might happen in the future, and ignore them when they do. + * This gives us behavioral compatibility with the old implementation (that blocked in + * destructors) while still removing the blocking logic. + */ localContext = std::move(m_sharedState.m_callbackContext); connectFlushContainer = m_sharedState.m_connectFlushContainer; m_sharedState.m_connectFlushContainer = nullptr; } } + // only does something on shutdown localContext.InvokeCallbacks(); + // only does something on shutdown OnMessageFlushCallbackContainer::Complete( connectFlushContainer.get(), {EVENT_STREAM_RPC_CONNECTION_CLOSED, AWS_ERROR_EVENT_STREAM_RPC_CONNECTION_CLOSED}); @@ -832,6 +905,10 @@ namespace Aws } } + /* + * Only called by the destructor of the public-facing ClientConnection object. When this returns, no + * further callbacks will be made. + */ void ClientConnectionImpl::Shutdown() noexcept { CloseInternal(true); @@ -864,6 +941,8 @@ namespace Aws return localFuture; } + // Optimistic state update under the lock. Nothing can alter a PendingConnect (other than a + // connection callback). m_lifecycleHandler = connectionLifecycleHandler; std::function disconnectCallback = [connectionLifecycleHandler](RpcError error) { connectionLifecycleHandler->OnDisconnectCallback(error); }; @@ -895,6 +974,7 @@ namespace Aws connectOptions.on_connection_setup = ClientConnectionImpl::s_onConnectionSetup; connectOptions.on_connection_protocol_message = ClientConnectionImpl::s_onProtocolMessage; connectOptions.on_connection_shutdown = ClientConnectionImpl::s_onConnectionShutdown; + connectOptions.user_data = reinterpret_cast(this); if (m_connectionConfig.GetTlsConnectionOptions().has_value()) @@ -904,6 +984,7 @@ namespace Aws if (aws_event_stream_rpc_client_connection_connect(m_allocator, &connectOptions)) { + // Rollback our optimistic state update MoveToDisconnected({EVENT_STREAM_RPC_CONNECTION_SETUP_FAILED, aws_last_error()}); } @@ -977,12 +1058,15 @@ namespace Aws if (impl->m_sharedState.m_desiredState != ClientState::Connected) { + // Someone called Close/Shutdown during the connection process. We couldn't do anything at the + // time, but now we can. So start the close process. AWS_FATAL_ASSERT(impl->m_sharedState.m_desiredState == ClientState::Disconnected); impl->m_sharedState.m_currentState = ClientState::Disconnecting; closeConnection = connection; } else { + // optimistic state update to waiting on a connack from the server impl->m_sharedState.m_currentState = ClientState::PendingConnack; connectConnection = connection; @@ -1019,6 +1103,8 @@ namespace Aws if (connectErrorCode != AWS_ERROR_SUCCESS) { + // rollback our optimistic connack update since we failed to send the connect. + // We dont need to release connectConnection because we're "transferring" it to closeConnection std::lock_guard lock(impl->m_sharedStateLock); impl->m_sharedState.m_callbackContext.SetError({EVENT_STREAM_RPC_CRT_ERROR, connectErrorCode}); @@ -1074,6 +1160,7 @@ namespace Aws std::lock_guard lock(impl->m_sharedStateLock); if (impl->m_sharedState.m_currentState != ClientState::PendingConnack || !successfulAck) { + // triggered if closed/shutdown or failed the handshake if (!impl->m_sharedState.m_hasShutDown) { impl->m_sharedState.m_callbackContext.SetError(RpcError{ @@ -1091,6 +1178,7 @@ namespace Aws } else { + // everything's good; transition into the connected state impl->m_sharedState.m_currentState = ClientState::Connected; localCallbackContext = impl->m_sharedState.m_callbackContext.TransitionToConnected(); } @@ -1316,10 +1404,16 @@ namespace Aws return nullptr; } + // Depending on the current state of the continuation, each inbound message falls into one of three types enum class EventStreamMessageRoutingType { + // The inbound message should be turned into a modeled response for an Activate request Response, + + // The inbound message should be turned into a modeled streaming event Stream, + + // The inbound message should be turned into a modeled error for an Activate request Error }; @@ -1352,12 +1446,22 @@ namespace Aws Crt::Optional m_message; }; + // One-way, sequential state sequence for continuations enum class ContinuationStateType { + // Continuation has been created, but Activate has not been called yet None, + + // The continuation is in the process of being activated PendingActivate, + + // The continuation has been successfully activated Activated, + + // The continuation is closing PendingClose, + + // The continuation is closed Closed, }; @@ -1389,6 +1493,7 @@ namespace Aws struct aws_event_stream_rpc_client_connection *connection) noexcept; virtual ~ClientContinuationImpl(); + // Only called by ClientContinuation::~ClientContinuation void ShutDown() noexcept; std::future Activate( @@ -1462,6 +1567,16 @@ namespace Aws std::shared_ptr m_operationModelContext; + /* + * A small exception to our "never hold a lock while making callbacks" rule. + * + * The handler lock is "one-way"; it is held while invoking callbacks on the stream handler. We also + * conditionally hold it while zeroing the handler on shutdown. Because we do not need the lock for + * user-facing functions outside ShutDown, deadlock is not a risk. + * + * THis allows us to guarantee that streaming events/errors are not emitted after ShutDown is called, + * even while asynchronous C shutdown is in-progress. + */ std::mutex m_streamHandlerLock; std::shared_ptr m_streamHandler; @@ -1478,82 +1593,6 @@ namespace Aws bool m_continuationValid; }; - ClientOperation::ClientOperation( - ClientConnection &connection, - std::shared_ptr streamHandler, - const std::shared_ptr &operationModelContext, - Crt::Allocator *allocator) noexcept - : m_allocator(allocator), m_impl(connection.NewStream()) - { - m_impl->Initialize(operationModelContext, std::move(streamHandler)); - } - - ClientOperation::~ClientOperation() noexcept - { - m_impl->ShutDown(); - m_impl = nullptr; - } - - std::future ClientOperation::Close(OnMessageFlushCallback onMessageFlushCallback) noexcept - { - return m_impl->Close(std::move(onMessageFlushCallback)); - } - - void ClientOperation::WithLaunchMode(std::launch mode) noexcept - { - (void)mode; - } - - Crt::String ClientOperation::GetModelName() const noexcept - { - return m_impl->GetModelName(); - } - - std::future ClientOperation::Activate( - const AbstractShapeBase *shape, - OnMessageFlushCallback &&onMessageFlushCallback, - std::function &&onResultCallback) noexcept - { - Crt::List headers; - headers.emplace_back(EventStreamHeader( - Crt::String(CONTENT_TYPE_HEADER), Crt::String(CONTENT_TYPE_APPLICATION_JSON), m_allocator)); - headers.emplace_back( - EventStreamHeader(Crt::String(SERVICE_MODEL_TYPE_HEADER), GetModelName(), m_allocator)); - Crt::JsonObject payloadObject; - shape->SerializeToJsonObject(payloadObject); - Crt::String payloadString = payloadObject.View().WriteCompact(); - - return m_impl->Activate( - GetModelName(), - headers, - Crt::ByteBufFromCString(payloadString.c_str()), - AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE, - 0, - std::move(onResultCallback), - std::move(onMessageFlushCallback)); - } - - std::future ClientOperation::SendStreamMessage( - const AbstractShapeBase *shape, - OnMessageFlushCallback &&onMessageFlushCallback) noexcept - { - Crt::List headers; - headers.emplace_back(EventStreamHeader( - Crt::String(CONTENT_TYPE_HEADER), Crt::String(CONTENT_TYPE_APPLICATION_JSON), m_allocator)); - headers.emplace_back( - EventStreamHeader(Crt::String(SERVICE_MODEL_TYPE_HEADER), GetModelName(), m_allocator)); - Crt::JsonObject payloadObject; - shape->SerializeToJsonObject(payloadObject); - Crt::String payloadString = payloadObject.View().WriteCompact(); - - return m_impl->SendStreamMessage( - headers, - Crt::ByteBufFromCString(payloadString.c_str()), - AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE, - 0, - std::move(onMessageFlushCallback)); - } - ClientContinuationImpl::ClientContinuationImpl( Aws::Crt::Allocator *allocator, struct aws_client_bootstrap *bootstrap, @@ -1633,6 +1672,7 @@ namespace Aws AWS_FATAL_ASSERT(bootstrap != NULL); + // We use the bootstrap rather than the connection's event loop because we might not have a connection struct aws_event_loop *event_loop = aws_event_loop_group_get_next_loop(bootstrap->event_loop_group); AWS_FATAL_ASSERT(event_loop != NULL); @@ -1647,9 +1687,13 @@ namespace Aws std::shared_ptr activationCallbackContainer = nullptr; std::function activationResponseCallback = nullptr; + // This block prevents streaming event callbacks from triggering after scope exit { if (m_connectionEventLoop != nullptr) { + // If we're on the connection's event loop thread then we risk deadlock by trying to use + // the handler lock. But in that case, it's safe not to use it, because we only use the lock from + // the event loop (or the single call to ShutDown) bool useHandlerLock = !aws_event_loop_thread_is_callers_thread(m_connectionEventLoop); if (useHandlerLock) { @@ -1666,6 +1710,7 @@ namespace Aws } { + // update state and gather up all the callbacks we need to synthesize std::lock_guard lock(m_sharedStateLock); if (m_sharedState.m_currentState == ContinuationStateType::None) { @@ -1685,15 +1730,15 @@ namespace Aws m_sharedState.m_activationResponseCallback = nullptr; } + // synthesize callbacks + if (activationResponseCallback) { activationResponseCallback( TaggedResult(RpcError{EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS})); } - /* - * Short-circuit and simulate both activate and close callbacks as necessary. - */ + // Short-circuit and simulate both activate and close callbacks as necessary. OnMessageFlushCallbackContainer::Complete( activationCallbackContainer.get(), {EVENT_STREAM_RPC_CONTINUATION_CLOSED, AWS_ERROR_SUCCESS}); @@ -1702,10 +1747,12 @@ namespace Aws if (releaseContinuation != nullptr) { + // An unactivated continuation should be released directly ReleaseContinuation(m_allocator, m_clientBootstrap, releaseContinuation); } else { + // A continuation that has at least started the activation process should be closed first Close(); } } @@ -1716,10 +1763,8 @@ namespace Aws { return EVENT_STREAM_RPC_CONTINUATION_CLOSED; } - else - { - return EVENT_STREAM_RPC_CONNECTION_CLOSED; - } + + return EVENT_STREAM_RPC_CONNECTION_CLOSED; } std::future ClientContinuationImpl::Activate( @@ -1747,6 +1792,7 @@ namespace Aws { if (m_sharedState.m_currentState == ContinuationStateType::None) { + // optimistically update shared state to pending activate activateContinuation = m_sharedState.m_continuation; aws_event_stream_rpc_client_continuation_acquire(activateContinuation); m_sharedState.m_currentState = ContinuationStateType::PendingActivate; @@ -1756,11 +1802,13 @@ namespace Aws } else { + // we're not in a state we can activate switch (m_sharedState.m_currentState) { case ContinuationStateType::PendingActivate: case ContinuationStateType::Activated: - activationError = {EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED, 0}; + // simulate what would be returned if we invoked the C API + activationError = {EVENT_STREAM_RPC_CRT_ERROR, AWS_ERROR_INVALID_STATE}; break; case ContinuationStateType::PendingClose: @@ -1776,7 +1824,6 @@ namespace Aws } else { - // null continuation is only if the connection didn't exist at creation time activationError = {GetEmptyContinuationStatusCode(), 0}; } } @@ -1805,6 +1852,7 @@ namespace Aws if (result != AWS_OP_SUCCESS) { + // ah shucks, we failed, rollback our optimistic shared state update std::lock_guard lock(m_sharedStateLock); m_sharedState.m_currentState = ContinuationStateType::None; m_sharedState.m_desiredState = ContinuationStateType::None; @@ -1853,11 +1901,13 @@ namespace Aws { if (m_sharedState.m_currentState == ContinuationStateType::Activated) { + // it's safe to send a stream message sendContinuation = m_sharedState.m_continuation; aws_event_stream_rpc_client_continuation_acquire(sendContinuation); } else { + // we're not in a state to send a stream message switch (m_sharedState.m_currentState) { case ContinuationStateType::PendingActivate: @@ -1878,8 +1928,7 @@ namespace Aws } else { - // null continuation is only if the connection didn't exist at creation time - sendError = {EVENT_STREAM_RPC_CONNECTION_CLOSED, 0}; + sendError = {GetEmptyContinuationStatusCode(), 0}; } } @@ -1932,6 +1981,8 @@ namespace Aws m_allocator, m_allocator, std::move(onMessageFlushCallback), std::move(closePromise)); RpcError closeError = {}; struct aws_event_stream_rpc_client_continuation_token *closeContinuation = nullptr; + + // needed to correctly roll back on failure to send the end-stream message ContinuationStateType previousState = ContinuationStateType::PendingClose; { @@ -1952,20 +2003,13 @@ namespace Aws } else { - if (m_sharedState.m_currentState == ContinuationStateType::PendingClose) - { - closeError = {EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS, 0}; - } - else - { - closeError = {EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}; - } + // not in a valid state to close + closeError = {EVENT_STREAM_RPC_CONTINUATION_CLOSED, 0}; } } else { - // null continuation is only if the connection didn't exist at creation time - closeError = {EVENT_STREAM_RPC_CONNECTION_CLOSED, 0}; + closeError = {GetEmptyContinuationStatusCode(), 0}; } } @@ -1992,6 +2036,7 @@ namespace Aws m_sharedState.m_closeCallbackContainer = nullptr; if (m_sharedState.m_currentState != ContinuationStateType::Closed) { + // Rollback to previous state m_sharedState.m_currentState = previousState; } } @@ -2218,6 +2263,7 @@ namespace Aws } else { + // Horribly awkward cast due to the infuriating original API design Crt::Allocator *allocator = m_allocator; auto errorResponse = Crt::ScopedResource( static_cast(result.m_message.value().m_shape.release()), @@ -2318,5 +2364,80 @@ namespace Aws m_allocator, m_allocator, m_bootstrap, m_sharedState.m_underlyingConnection); } + ClientOperation::ClientOperation( + ClientConnection &connection, + std::shared_ptr streamHandler, + const std::shared_ptr &operationModelContext, + Crt::Allocator *allocator) noexcept + : m_allocator(allocator), m_impl(connection.NewStream()) + { + m_impl->Initialize(operationModelContext, std::move(streamHandler)); + } + + ClientOperation::~ClientOperation() noexcept + { + m_impl->ShutDown(); + m_impl = nullptr; + } + + std::future ClientOperation::Close(OnMessageFlushCallback onMessageFlushCallback) noexcept + { + return m_impl->Close(std::move(onMessageFlushCallback)); + } + + void ClientOperation::WithLaunchMode(std::launch mode) noexcept + { + (void)mode; + } + + Crt::String ClientOperation::GetModelName() const noexcept + { + return m_impl->GetModelName(); + } + + std::future ClientOperation::Activate( + const AbstractShapeBase *shape, + OnMessageFlushCallback &&onMessageFlushCallback, + std::function &&onResultCallback) noexcept + { + Crt::List headers; + headers.emplace_back(EventStreamHeader( + Crt::String(CONTENT_TYPE_HEADER), Crt::String(CONTENT_TYPE_APPLICATION_JSON), m_allocator)); + headers.emplace_back( + EventStreamHeader(Crt::String(SERVICE_MODEL_TYPE_HEADER), GetModelName(), m_allocator)); + Crt::JsonObject payloadObject; + shape->SerializeToJsonObject(payloadObject); + Crt::String payloadString = payloadObject.View().WriteCompact(); + + return m_impl->Activate( + GetModelName(), + headers, + Crt::ByteBufFromCString(payloadString.c_str()), + AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE, + 0, + std::move(onResultCallback), + std::move(onMessageFlushCallback)); + } + + std::future ClientOperation::SendStreamMessage( + const AbstractShapeBase *shape, + OnMessageFlushCallback &&onMessageFlushCallback) noexcept + { + Crt::List headers; + headers.emplace_back(EventStreamHeader( + Crt::String(CONTENT_TYPE_HEADER), Crt::String(CONTENT_TYPE_APPLICATION_JSON), m_allocator)); + headers.emplace_back( + EventStreamHeader(Crt::String(SERVICE_MODEL_TYPE_HEADER), GetModelName(), m_allocator)); + Crt::JsonObject payloadObject; + shape->SerializeToJsonObject(payloadObject); + Crt::String payloadString = payloadObject.View().WriteCompact(); + + return m_impl->SendStreamMessage( + headers, + Crt::ByteBufFromCString(payloadString.c_str()), + AWS_EVENT_STREAM_RPC_MESSAGE_TYPE_APPLICATION_MESSAGE, + 0, + std::move(onMessageFlushCallback)); + } } /* namespace Eventstreamrpc */ } // namespace Aws diff --git a/eventstream_rpc/tests/CMakeLists.txt b/eventstream_rpc/tests/CMakeLists.txt index 360f780e7..52e647bb4 100644 --- a/eventstream_rpc/tests/CMakeLists.txt +++ b/eventstream_rpc/tests/CMakeLists.txt @@ -96,6 +96,7 @@ add_test_case(EchoClientStreamingOperationCauseServiceError) add_test_case(EchoClientStreamingOperationSendCloseOperation) add_test_case(EchoClientStreamingOperationSendDropOperation) add_test_case(EchoClientStreamingOperationSendCloseConnection) +add_test_case(EchoClientStreamingOperationUnactivatedSend) add_test_case(EchoClientOperationStress) generate_cpp_test_driver(${TEST_BINARY_NAME}) diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 087ad9dad..3ef346bab 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -1072,8 +1072,9 @@ static int s_TestEchoClientOperationActivateActivate(struct aws_allocator *alloc auto response = result.GetOperationResponse(); ASSERT_NOT_NULL(response); - auto flush2ErrorStatus = requestFuture2.get().baseStatus; - ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED, flush2ErrorStatus); + auto flush2Result = requestFuture2.get(); + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CRT_ERROR, flush2Result.baseStatus); + ASSERT_INT_EQUALS(AWS_ERROR_INVALID_STATE, flush2Result.crtError); return AWS_OP_SUCCESS; }); @@ -1102,9 +1103,8 @@ static int s_TestEchoClientOperationActivateWaitActivate(struct aws_allocator *a auto flush2ErrorStatus = requestFuture2.get().baseStatus; ASSERT_TRUE( - flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED || - flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED || - flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS); + flush2ErrorStatus == EVENT_STREAM_RPC_CRT_ERROR || + flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED); return AWS_OP_SUCCESS; }); @@ -1136,9 +1136,8 @@ static int s_TestEchoClientOperationActivateCloseActivate(struct aws_allocator * auto flush2ErrorStatus = requestFuture2.get().baseStatus; ASSERT_TRUE( - flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED || - flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED || - flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSE_IN_PROGRESS); + flush2ErrorStatus == EVENT_STREAM_RPC_CRT_ERROR || + flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED); closeFuture.wait(); @@ -1233,7 +1232,7 @@ static int s_TestEchoClientOperationActivateCloseConnection(struct aws_allocator ASSERT_TRUE( flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_CLOSED || flush2ErrorStatus == EVENT_STREAM_RPC_CONNECTION_CLOSED || - flush2ErrorStatus == EVENT_STREAM_RPC_CONTINUATION_ALREADY_OPENED); + flush2ErrorStatus == EVENT_STREAM_RPC_CRT_ERROR); return AWS_OP_SUCCESS; }); @@ -1907,6 +1906,34 @@ static int s_TestEchoClientStreamingOperationSendCloseConnection(struct aws_allo AWS_TEST_CASE(EchoClientStreamingOperationSendCloseConnection, s_TestEchoClientStreamingOperationSendCloseConnection); +static int s_TestEchoClientStreamingOperationUnactivatedSend(struct aws_allocator *allocator, void *ctx) +{ + + return s_DoSimpleRequestRaceCheckTest( + allocator, + [allocator](EventStreamClientTestContext &testContext, EchoTestRpcClient &client) + { + auto handler = Aws::Crt::MakeShared(allocator, allocator, false); + auto echoStreamMessages = client.NewEchoStreamMessages(handler); + + EchoStreamingMessage streamMessage; + MessageData messageData; + Aws::Crt::String value = "Hello World"; + messageData.SetStringMessage(value); + + streamMessage.SetStreamMessage(messageData); + + auto streamFuture = echoStreamMessages->SendStreamMessage(streamMessage, s_onMessageFlush); + + auto streamResultStatus = streamFuture.get().baseStatus; + ASSERT_INT_EQUALS(EVENT_STREAM_RPC_CONTINUATION_NOT_YET_OPENED, streamResultStatus); + + return AWS_OP_SUCCESS; + }); +} + +AWS_TEST_CASE(EchoClientStreamingOperationUnactivatedSend, s_TestEchoClientStreamingOperationUnactivatedSend); + class EchoStressContext { public: @@ -2193,359 +2220,3 @@ static int s_TestEchoClientOperationStress(struct aws_allocator *allocator, void } AWS_TEST_CASE(EchoClientOperationStress, s_TestEchoClientOperationStress); - -#ifdef NEVER - -AWS_TEST_CASE_FIXTURE(EchoOperation, s_testSetup, s_TestEchoOperation, s_testTeardown, &s_testContext); -static int s_TestEchoOperation(struct aws_allocator *allocator, void *ctx) -{ - auto *testContext = static_cast(ctx); - if (!s_isEchoserverSetup(*testContext)) - { - printf("Environment Variables are not set for the test, skip the test"); - return AWS_OP_SKIP; - } - - ConnectionLifecycleHandler lifecycleHandler; - Aws::Crt::String expectedMessage("Async I0 FTW"); - EchoMessageRequest echoMessageRequest; - MessageData messageData; - messageData.SetStringMessage(expectedMessage); - - /* Perform a regular echo operation. */ - { - Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); - auto connectedStatus = client.Connect(lifecycleHandler); - ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); - auto echoMessage = client.NewEchoMessage(); - messageData.SetStringMessage(expectedMessage); - echoMessageRequest.SetMessage(messageData); - auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - requestFuture.wait(); - auto result = echoMessage->GetResult().get(); - ASSERT_TRUE(result); - auto response = result.GetOperationResponse(); - ASSERT_NOT_NULL(response); - ASSERT_TRUE(response->GetMessage().value().GetStringMessage().value() == expectedMessage); - } - - /* Attempt a connection, close it, then try running operations as normal. */ - { - ConnectionLifecycleHandler lifecycleHandler; - Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); - auto connectedStatus = client.Connect(lifecycleHandler); - ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); - client.Close(); - auto echoMessage = client.NewEchoMessage(); - EchoMessageRequest echoMessageRequest; - MessageData messageData; - Aws::Crt::String expectedMessage("l33t"); - messageData.SetStringMessage(expectedMessage); - echoMessageRequest.SetMessage(messageData); - auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - ASSERT_TRUE(requestFuture.get().baseStatus == EVENT_STREAM_RPC_CONNECTION_CLOSED); - auto result = echoMessage->GetOperationResult().get(); - ASSERT_FALSE(result); - auto error = result.GetRpcError(); - ASSERT_TRUE(error.baseStatus == EVENT_STREAM_RPC_CONNECTION_CLOSED); - } - - /* Perform a regular echo operation but one after another without waiting. - * Only the response from the first operation will be received. */ - { - Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); - auto connectedStatus = client.Connect(lifecycleHandler); - ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); - auto echoMessage = client.NewEchoMessage(); - messageData.SetStringMessage(expectedMessage); - echoMessageRequest.SetMessage(messageData); - auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - MessageData differentMessage; - differentMessage.SetBooleanMessage(true); - echoMessageRequest.SetMessage(differentMessage); - requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - requestFuture.wait(); - auto result = echoMessage->GetResult().get(); - ASSERT_TRUE(result); - auto response = result.GetOperationResponse(); - ASSERT_NOT_NULL(response); - ASSERT_TRUE(response->GetMessage().value().GetStringMessage().value() == expectedMessage); - } - - /* Closing the stream should be idempotent. */ - { - Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); - - auto connectedStatus = client.Connect(lifecycleHandler); - ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); - auto echoMessage = client.NewEchoMessage(); - messageData.SetStringMessage(expectedMessage); - echoMessageRequest.SetMessage(messageData); - auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - MessageData differentMessage; - differentMessage.SetBooleanMessage(true); - echoMessageRequest.SetMessage(differentMessage); - requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - requestFuture.wait(); - echoMessage->Close().wait(); - echoMessage->Close().wait(); - echoMessage->Close().wait(); - echoMessage->Close().wait(); - } - - /* Close without waiting on activation or close futures. */ - { - Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); - - auto connectedStatus = client.Connect(lifecycleHandler); - ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); - auto echoMessage = client.NewEchoMessage(); - messageData.SetStringMessage(expectedMessage); - echoMessageRequest.SetMessage(messageData); - auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - MessageData differentMessage; - differentMessage.SetBooleanMessage(true); - echoMessageRequest.SetMessage(differentMessage); - echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - echoMessage->Close(); - echoMessage->Close(); - echoMessage->Close(); - echoMessage->Close(); - } - - /* Close without waiting for TERMINATE_STREAM to flush then immediately trying to activate. */ - { - Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); - - auto connectedStatus = client.Connect(lifecycleHandler); - ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); - auto echoMessage = client.NewEchoMessage(); - messageData.SetStringMessage(expectedMessage); - echoMessageRequest.SetMessage(messageData); - auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - MessageData differentMessage; - differentMessage.SetBooleanMessage(true); - echoMessageRequest.SetMessage(differentMessage); - requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - requestFuture.wait(); - auto closeFuture = echoMessage->Close(); - requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - closeFuture.wait(); - requestFuture.wait(); - } - - /* Connect thrice and verify that the future of the first attempt succeeds. - * The rest of the attempts must fail with an error. - * Use the client to perform an operation and verify that the operation still succeeds. */ - { - Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); - auto connectedStatus = client.Connect(lifecycleHandler); - auto failedStatus = client.Connect(lifecycleHandler); - ASSERT_TRUE(failedStatus.get().baseStatus == EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED); - failedStatus = client.Connect(lifecycleHandler); - ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); - ASSERT_TRUE(failedStatus.get().baseStatus == EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED); - auto echoMessage = client.NewEchoMessage(); - echoMessageRequest.SetMessage(messageData); - auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - requestFuture.wait(); - auto result = echoMessage->GetResult().get(); - ASSERT_TRUE(result); - auto response = result.GetOperationResponse(); - ASSERT_NOT_NULL(response); - ASSERT_TRUE(response->GetMessage().value().GetStringMessage().value() == expectedMessage); - } - - /* Connect twice sequentially. - * Use the client to perform an operation and verify that the operation still succeeds. */ - { - Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); - auto connectedStatus = client.Connect(lifecycleHandler); - ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); - connectedStatus = client.Connect(lifecycleHandler); - ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_CONNECTION_ALREADY_ESTABLISHED); - auto echoMessage = client.NewEchoMessage(); - echoMessageRequest.SetMessage(messageData); - auto requestFuture = echoMessage->Activate(echoMessageRequest, s_onMessageFlush); - requestFuture.wait(); - auto result = echoMessage->GetResult().get(); - ASSERT_TRUE(result); - auto response = result.GetOperationResponse(); - ASSERT_NOT_NULL(response); - ASSERT_TRUE(response->GetMessage().value().GetStringMessage().value() == expectedMessage); - } - - return AWS_OP_SUCCESS; -} - -class ThreadPool -{ - public: - ThreadPool(int numThreads = std::thread::hardware_concurrency()) noexcept - : m_numThreads(numThreads), m_stopped(false) - { - for (int i = 0; i < numThreads; i++) - { - m_threadPool.push_back(std::thread(&ThreadPool::TaskWorker, this)); - } - m_taskErrorCode = AWS_OP_SUCCESS; - } - - void AddTask(std::function task) noexcept - { - { - std::unique_lock lock(m_queueMutex); - m_queue.push(task); - } - m_taskReady.notify_one(); - } - - void Shutdown() noexcept - { - /* Wake up all threads so that they can complete. */ - m_taskReady.notify_all(); - - /* Wait for all threads to complete. */ - for (std::thread &thread : m_threadPool) - { - thread.join(); - } - - m_threadPool.clear(); - m_stopped = true; - } - - void BlockUntilTasksFinish() noexcept - { - while (true) - { - if (m_queueMutex.try_lock()) - { - if (m_queue.empty()) - { - m_stopped = true; - m_queueMutex.unlock(); - /* Wait for all threads to complete. */ - m_taskReady.notify_all(); - for (std::thread &thread : m_threadPool) - { - thread.join(); - } - break; - } - else - { - m_queueMutex.unlock(); - std::this_thread::yield(); - } - } - } - } - - int GetErrorCode() noexcept { return m_taskErrorCode; } - - ~ThreadPool() noexcept - { - if (!m_stopped) - Shutdown(); - } - - private: - int m_numThreads; - std::mutex m_poolMutex; - std::vector m_threadPool; - std::mutex m_queueMutex; - std::queue> m_queue; - std::condition_variable m_taskReady; - int m_taskErrorCode; - bool m_stopped; - - void TaskWorker() - { - while (true) - { - { - std::unique_lock lock(m_queueMutex); - - m_taskReady.wait(lock, [this] { return !m_queue.empty() || m_stopped; }); - if (!m_queue.empty()) - { - std::function currentJob = m_queue.front(); - m_queue.pop(); - lock.unlock(); - if (currentJob) - { - int errorCode = currentJob(); - if (errorCode) - m_taskErrorCode = errorCode; - } - } - else if (m_stopped) - { - break; - } - } - } - } -}; - -AWS_TEST_CASE_FIXTURE(StressTestClient, s_testSetup, s_TestStressClient, s_testTeardown, &s_testContext); -static int s_TestStressClient(struct aws_allocator *allocator, void *ctx) -{ - auto *testContext = static_cast(ctx); - if (!s_isEchoserverSetup(*testContext)) - { - printf("Environment Variables are not set for the test, skip the test"); - return AWS_OP_SKIP; - } - - ThreadPool threadPool; - ConnectionLifecycleHandler lifecycleHandler; - Aws::Crt::String expectedMessage("Async I0 FTW"); - EchoMessageRequest echoMessageRequest; - MessageData messageData; - messageData.SetStringMessage(expectedMessage); - - { - Awstest::EchoTestRpcClient client(*testContext->clientBootstrap, allocator); - auto connectedStatus = client.Connect(lifecycleHandler); - ASSERT_TRUE(connectedStatus.get().baseStatus == EVENT_STREAM_RPC_SUCCESS); - auto invokeOperation = [&](void) -> int - { - auto echoMessage = client.NewEchoMessage(); - messageData.SetStringMessage(expectedMessage); - echoMessageRequest.SetMessage(messageData); - auto requestStatus = echoMessage->Activate(echoMessageRequest, s_onMessageFlush).get(); - auto resultFuture = echoMessage->GetResult(); - /* The response may never arrive depending on how many ongoing requests are made - * so in case of timeout, assume success. */ - std::future_status status = resultFuture.wait_for(std::chrono::seconds(5)); - if (status != std::future_status::ready) - { - return AWS_OP_SUCCESS; - } - auto result = echoMessage->GetResult().get(); - ASSERT_TRUE(result); - auto response = result.GetOperationResponse(); - ASSERT_NOT_NULL(response); - ASSERT_TRUE(response->GetMessage().value().GetStringMessage().value() == expectedMessage); - - return AWS_OP_SUCCESS; - }; - - for (int i = 0; i < 1000; i++) - threadPool.AddTask(invokeOperation); - - threadPool.BlockUntilTasksFinish(); - - if (threadPool.GetErrorCode() != AWS_OP_SUCCESS) - return threadPool.GetErrorCode(); - } - - return AWS_OP_SUCCESS; -} -#endif From afafd85b2b662b3de9bf5720e6ffa6d607cb339e Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 24 Jun 2025 08:29:37 -0700 Subject: [PATCH 46/56] Update CRT version --- crt/aws-crt-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crt/aws-crt-cpp b/crt/aws-crt-cpp index 05edb40f5..56dc6adb0 160000 --- a/crt/aws-crt-cpp +++ b/crt/aws-crt-cpp @@ -1 +1 @@ -Subproject commit 05edb40f592813fab2b6f7ba141554fdcf86a7c9 +Subproject commit 56dc6adb0fcde401e18345849c6b459f8bc7dbb6 From b13a1e2ab2dd75c1ec4765a03385d55766c501fd Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 24 Jun 2025 08:46:16 -0700 Subject: [PATCH 47/56] Structure init --- eventstream_rpc/source/EventStreamClient.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 1637dc446..62f229117 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -1603,12 +1603,13 @@ namespace Aws { if (connection != nullptr) { - struct aws_event_stream_rpc_client_stream_continuation_options continuation_options = { - .on_continuation = s_OnContinuationMessage, - .on_continuation_closed = s_OnContinuationClosed, - .on_continuation_terminated = s_OnContinuationTerminated, - .user_data = this, - }; + struct aws_event_stream_rpc_client_stream_continuation_options continuation_options; + AWS_ZERO_STRUCT(continuation_options); + continuation_options.on_continuation = s_OnContinuationMessage; + continuation_options.on_continuation_closed = s_OnContinuationClosed; + continuation_options.on_continuation_terminated = s_OnContinuationTerminated; + continuation_options.user_data = this; + m_sharedState.m_continuation = aws_event_stream_rpc_client_connection_new_stream(connection, &continuation_options); } From 9bd481d5bd150b4c542588a9fde9e8f1f10cdd2d Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 24 Jun 2025 08:51:29 -0700 Subject: [PATCH 48/56] Missing include --- eventstream_rpc/tests/EventStreamClientTest.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 3ef346bab..ed5eab401 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -16,6 +16,8 @@ #include +#include + using namespace Aws::Crt; using namespace Aws::Eventstreamrpc; using namespace Awstest; From ba9a4bf7978f5716c24f53cc7885316a2831599b Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 24 Jun 2025 09:06:01 -0700 Subject: [PATCH 49/56] Unused params & missing casts --- eventstream_rpc/source/EventStreamClient.cpp | 31 +++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 62f229117..9df3b5bd9 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -49,18 +49,16 @@ namespace Aws class OnMessageFlushCallbackContainer { public: - OnMessageFlushCallbackContainer(Crt::Allocator *allocator, OnMessageFlushCallback &&flushCallback) - : m_sharedState({}) + OnMessageFlushCallbackContainer(OnMessageFlushCallback &&flushCallback) : m_sharedState({}) { m_sharedState.m_state = CallbackState::Incomplete; m_sharedState.m_onMessageFlushCallback = std::move(flushCallback); } OnMessageFlushCallbackContainer( - Crt::Allocator *allocator, OnMessageFlushCallback &&flushCallback, std::promise &&flushPromise) - : OnMessageFlushCallbackContainer(allocator, std::move(flushCallback)) + : OnMessageFlushCallbackContainer(std::move(flushCallback)) { m_sharedState.m_onFlushPromise = std::move(flushPromise); } @@ -130,10 +128,9 @@ namespace Aws { public: OnMessageFlushCallbackContainerWrapper(Crt::Allocator *allocator, OnMessageFlushCallback &&flushCallback) - : m_allocator(allocator), m_container(Aws::Crt::MakeShared( - allocator, - allocator, - std::move(flushCallback))) + : m_allocator(allocator), + m_container( + Aws::Crt::MakeShared(allocator, std::move(flushCallback))) { } @@ -142,7 +139,6 @@ namespace Aws OnMessageFlushCallback &&flushCallback, std::promise &&flushPromise) : m_allocator(allocator), m_container(Aws::Crt::MakeShared( - allocator, allocator, std::move(flushCallback), std::move(flushPromise))) @@ -412,7 +408,7 @@ namespace Aws m_valueByteBuf = Crt::ByteBufNewCopy(allocator, header.header_value.variable_len_val, header.header_value_len); m_underlyingHandle.header_value.variable_len_val = m_valueByteBuf.buffer; - m_underlyingHandle.header_value_len = m_valueByteBuf.len; + m_underlyingHandle.header_value_len = static_cast(m_valueByteBuf.len); break; default: @@ -800,6 +796,9 @@ namespace Aws static void s_zeroSharedReference(struct aws_task *task, void *arg, enum aws_task_status status) { + (void)task; + (void)status; + auto clearSharedTask = static_cast(arg); // implicit destructor does all the work @@ -1386,7 +1385,10 @@ namespace Aws return true; } - void StreamResponseHandler::OnStreamEvent(Crt::ScopedResource response) {} + void StreamResponseHandler::OnStreamEvent(Crt::ScopedResource response) + { + (void)response; + } void StreamResponseHandler::OnStreamClosed() {} @@ -1646,6 +1648,9 @@ namespace Aws static void s_releaseContinuation(struct aws_task *task, void *arg, enum aws_task_status status) { + (void)task; + (void)status; + auto releaseTask = static_cast(arg); aws_event_stream_rpc_client_continuation_release(releaseTask->m_continuation); @@ -2332,6 +2337,8 @@ namespace Aws struct aws_event_stream_rpc_client_continuation_token *token, void *user_data) noexcept { + (void)token; + auto impl = reinterpret_cast(user_data); impl->OnClosed(); } @@ -2341,6 +2348,8 @@ namespace Aws const struct aws_event_stream_rpc_message_args *message_args, void *user_data) noexcept { + (void)token; + auto impl = reinterpret_cast(user_data); impl->OnMessage(message_args); } From c68b8c7289089ff126fa477676bd39a6145a4012 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 24 Jun 2025 09:50:16 -0700 Subject: [PATCH 50/56] Let's not do CI setup twice --- .builder/actions/sdk-ci-test-setup.py | 20 -------------------- .builder/actions/setup-eventstream-server.py | 1 - 2 files changed, 21 deletions(-) delete mode 100644 .builder/actions/sdk-ci-test-setup.py diff --git a/.builder/actions/sdk-ci-test-setup.py b/.builder/actions/sdk-ci-test-setup.py deleted file mode 100644 index 1ffbca9ef..000000000 --- a/.builder/actions/sdk-ci-test-setup.py +++ /dev/null @@ -1,20 +0,0 @@ -import Builder - -class SdkCiTestSetup(Builder.Action): - - def run(self, env): - - actions = [] - java_sdk_dir = None - - try: - java_sdk_dir = Builder.SetupEventStreamEchoServer().run(env) - Builder.SetupCrossCICrtEnvironment().run(env) - except Exception as ex: - print(f'Failure while setting up tests: {ex}') - actions.append("exit 1") - finally: - if java_sdk_dir: - env.shell.rm(java_sdk_dir) - - return Builder.Script(actions, name='sdk-ci-test-setup') diff --git a/.builder/actions/setup-eventstream-server.py b/.builder/actions/setup-eventstream-server.py index 349826c3c..4fedb67fd 100644 --- a/.builder/actions/setup-eventstream-server.py +++ b/.builder/actions/setup-eventstream-server.py @@ -118,7 +118,6 @@ def run(self, env): try: self._build_and_run_eventstream_echo_server(env) - Builder.SetupCrossCICrtEnvironment().run(env) except: pass From 84b5f80c50ba0c7e71babcbd13b18f4ba26d670f Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 24 Jun 2025 10:45:10 -0700 Subject: [PATCH 51/56] Sigh --- eventstream_rpc/tests/EventStreamClientTest.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index ed5eab401..097edfff9 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -62,6 +62,10 @@ EventStreamClientTestContext::EventStreamClientTestContext(struct aws_allocator aws_string_destroy(host_env_value); aws_string_destroy(port_env_value); + + AWS_LOGF_INFO( + AWS_LS_COMMON_GENERAL, "EventStreamClientTestContext - Host name %d bytes long", (int)echoServerHost.length()); + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EventStreamClientTestContext - Host name : %s", (int)echoServerHost.c_str()); } bool EventStreamClientTestContext::isValidEnvironment() const From b49cb828c135222222a3e4316a3c9d4f76ccbf2b Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 24 Jun 2025 10:48:55 -0700 Subject: [PATCH 52/56] Oops --- eventstream_rpc/tests/EventStreamClientTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eventstream_rpc/tests/EventStreamClientTest.cpp b/eventstream_rpc/tests/EventStreamClientTest.cpp index 097edfff9..9ef25e9c8 100644 --- a/eventstream_rpc/tests/EventStreamClientTest.cpp +++ b/eventstream_rpc/tests/EventStreamClientTest.cpp @@ -65,7 +65,7 @@ EventStreamClientTestContext::EventStreamClientTestContext(struct aws_allocator AWS_LOGF_INFO( AWS_LS_COMMON_GENERAL, "EventStreamClientTestContext - Host name %d bytes long", (int)echoServerHost.length()); - AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EventStreamClientTestContext - Host name : %s", (int)echoServerHost.c_str()); + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EventStreamClientTestContext - Host name : %s", echoServerHost.c_str()); } bool EventStreamClientTestContext::isValidEnvironment() const From 5dcb8131f849c22fc127e4f11722cd9e3182d270 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 24 Jun 2025 11:17:23 -0700 Subject: [PATCH 53/56] More logging --- eventstream_rpc/source/EventStreamClient.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 9df3b5bd9..37ec737b4 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -965,7 +965,11 @@ namespace Aws socketOptions = m_connectionConfig.GetSocketOptions().value(); } - struct aws_event_stream_rpc_client_connection_options connectOptions = {}; + auto hostName = connectionConfig.GetHostName().value(); + + struct aws_event_stream_rpc_client_connection_options connectOptions; + AWS_ZERO_STRUCT(connectOptions); + connectOptions.host_name = connectionConfig.GetHostName().value().c_str(); connectOptions.port = connectionConfig.GetPort().value(); connectOptions.bootstrap = m_bootstrap; @@ -976,6 +980,9 @@ namespace Aws connectOptions.user_data = reinterpret_cast(this); + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EventStreamClient - Host name %d bytes long", (int)hostName.length()); + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EventStreamClient - Host name : %s", hostName.c_str()); + if (m_connectionConfig.GetTlsConnectionOptions().has_value()) { connectOptions.tls_options = m_connectionConfig.GetTlsConnectionOptions()->GetUnderlyingHandle(); From b36a824b8ef278834d91bbd61eaa3adfd9c6a02d Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 24 Jun 2025 11:54:06 -0700 Subject: [PATCH 54/56] Don't grab a raw c string managed by a temporary --- eventstream_rpc/source/EventStreamClient.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 37ec737b4..60eedc01b 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -966,11 +966,13 @@ namespace Aws } auto hostName = connectionConfig.GetHostName().value(); + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EventStreamClient - Host name %d bytes long", (int)hostName.length()); + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EventStreamClient - Host name : %s", hostName.c_str()); struct aws_event_stream_rpc_client_connection_options connectOptions; AWS_ZERO_STRUCT(connectOptions); - connectOptions.host_name = connectionConfig.GetHostName().value().c_str(); + connectOptions.host_name = hostName.c_str(); connectOptions.port = connectionConfig.GetPort().value(); connectOptions.bootstrap = m_bootstrap; connectOptions.socket_options = &socketOptions.GetImpl(); @@ -980,9 +982,6 @@ namespace Aws connectOptions.user_data = reinterpret_cast(this); - AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EventStreamClient - Host name %d bytes long", (int)hostName.length()); - AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EventStreamClient - Host name : %s", hostName.c_str()); - if (m_connectionConfig.GetTlsConnectionOptions().has_value()) { connectOptions.tls_options = m_connectionConfig.GetTlsConnectionOptions()->GetUnderlyingHandle(); @@ -994,6 +993,10 @@ namespace Aws MoveToDisconnected({EVENT_STREAM_RPC_CONNECTION_SETUP_FAILED, aws_last_error()}); } + AWS_LOGF_INFO( + AWS_LS_COMMON_GENERAL, "EventStreamClient2 - Host name %d bytes long", (int)hostName.length()); + AWS_LOGF_INFO(AWS_LS_COMMON_GENERAL, "EventStreamClient2 - Host name : %s", hostName.c_str()); + return localFuture; } From df48929f7bffb12230e0c5959bcb7e148c30b9d3 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Tue, 24 Jun 2025 14:20:44 -0700 Subject: [PATCH 55/56] Apply Igor's old eventstream cleanup changes --- .../aws/eventstreamrpc/EventStreamClient.h | 35 ++++++++++--------- eventstream_rpc/source/EventStreamClient.cpp | 28 ++++++++------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h index c1e4ab5b1..af169160b 100644 --- a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h +++ b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h @@ -40,7 +40,7 @@ namespace Aws /** * A callback prototype that is called upon flushing a message over the wire. - * @param errorCode A non-zero value if an error occured while attempting to flush the message. + * @param errorCode A non-zero value if an error occurred while attempting to flush the message. */ using OnMessageFlushCallback = std::function; @@ -61,7 +61,7 @@ namespace Aws EventStreamHeader(EventStreamHeader &&rhs) noexcept; EventStreamHeader &operator=(const EventStreamHeader &lhs) noexcept; ~EventStreamHeader() noexcept; - EventStreamHeader( + explicit EventStreamHeader( const struct aws_event_stream_header_value_pair &header, Crt::Allocator *allocator = Crt::g_allocator); EventStreamHeader( @@ -75,8 +75,6 @@ namespace Aws const struct aws_event_stream_header_value_pair *GetUnderlyingHandle() const; - bool operator==(const EventStreamHeader &other) const noexcept; - private: Crt::Allocator *m_allocator; Crt::ByteBuf m_valueByteBuf; @@ -92,22 +90,24 @@ namespace Aws { public: MessageAmendment(const MessageAmendment &lhs); - MessageAmendment(MessageAmendment &&rhs); + MessageAmendment(MessageAmendment &&rhs) noexcept; MessageAmendment &operator=(const MessageAmendment &lhs); - MessageAmendment &operator=(MessageAmendment &&rhs); + MessageAmendment &operator=(MessageAmendment &&rhs) noexcept; ~MessageAmendment() noexcept; explicit MessageAmendment(Crt::Allocator *allocator = Crt::g_allocator) noexcept; MessageAmendment( const Crt::List &headers, Crt::Optional &payload, Crt::Allocator *allocator) noexcept; - MessageAmendment( + explicit MessageAmendment( const Crt::List &headers, Crt::Allocator *allocator = Crt::g_allocator) noexcept; - MessageAmendment( + explicit MessageAmendment( Crt::List &&headers, Crt::Allocator *allocator = Crt::g_allocator) noexcept; - MessageAmendment(const Crt::ByteBuf &payload, Crt::Allocator *allocator = Crt::g_allocator) noexcept; + explicit MessageAmendment( + const Crt::ByteBuf &payload, + Crt::Allocator *allocator = Crt::g_allocator) noexcept; /** * Add a given header to the end of the header list. @@ -168,10 +168,10 @@ namespace Aws OnMessageFlushCallback GetConnectRequestCallback() const noexcept { return m_connectRequestCallback; } ConnectMessageAmender GetConnectMessageAmender() const noexcept { - return [&](void) -> const MessageAmendment & { return m_connectAmendment; }; + return [&]() -> const MessageAmendment & { return m_connectAmendment; }; } - void SetHostName(Crt::String hostName) noexcept { m_hostName = hostName; } + void SetHostName(Crt::String hostName) noexcept { m_hostName = std::move(hostName); } void SetPort(uint32_t port) noexcept { m_port = port; } void SetSocketOptions(const Crt::Io::SocketOptions &socketOptions) noexcept { @@ -191,7 +191,7 @@ namespace Aws } void SetConnectRequestCallback(OnMessageFlushCallback connectRequestCallback) noexcept { - m_connectRequestCallback = connectRequestCallback; + m_connectRequestCallback = std::move(connectRequestCallback); } EventStreamRpcStatusCode Validate() const noexcept; @@ -330,7 +330,7 @@ namespace Aws public: explicit OperationError() noexcept = default; static void s_customDeleter(OperationError *shape) noexcept; - virtual void SerializeToJsonObject(Crt::JsonObject &payloadObject) const override; + void SerializeToJsonObject(Crt::JsonObject &payloadObject) const override; virtual Crt::Optional GetMessage() const noexcept = 0; }; @@ -416,13 +416,16 @@ namespace Aws private: union AWS_EVENTSTREAMRPC_API OperationResult { - OperationResult(Crt::ScopedResource &&response) noexcept + explicit OperationResult(Crt::ScopedResource &&response) noexcept : m_response(std::move(response)) { } - OperationResult(Crt::ScopedResource &&error) noexcept : m_error(std::move(error)) {} + explicit OperationResult(Crt::ScopedResource &&error) noexcept + : m_error(std::move(error)) + { + } OperationResult() noexcept : m_response(nullptr) {} - ~OperationResult() noexcept {}; + ~OperationResult() noexcept {} Crt::ScopedResource m_response; Crt::ScopedResource m_error; }; diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 60eedc01b..8fdefd52b 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -5,13 +5,11 @@ #include #include -#include #include -#include -#include - #include +#include +#include constexpr auto EVENTSTREAM_VERSION_HEADER = ":version"; constexpr auto EVENTSTREAM_VERSION_STRING = "0.1.0"; @@ -235,14 +233,14 @@ namespace Aws return *this; } - MessageAmendment::MessageAmendment(MessageAmendment &&rhs) + MessageAmendment::MessageAmendment(MessageAmendment &&rhs) noexcept : m_headers(std::move(rhs.m_headers)), m_payload(rhs.m_payload), m_allocator(rhs.m_allocator) { rhs.m_allocator = nullptr; rhs.m_payload = Crt::Optional(); } - MessageAmendment &MessageAmendment::operator=(MessageAmendment &&rhs) + MessageAmendment &MessageAmendment::operator=(MessageAmendment &&rhs) noexcept { if (this != &rhs) { @@ -457,15 +455,19 @@ namespace Aws EventStreamHeader &EventStreamHeader::operator=(const EventStreamHeader &lhs) noexcept { - m_allocator = lhs.m_allocator; - if (aws_byte_buf_is_valid(&m_valueByteBuf)) + if (this != &lhs) { - Crt::ByteBufDelete(m_valueByteBuf); + m_allocator = lhs.m_allocator; + if (aws_byte_buf_is_valid(&m_valueByteBuf)) + { + Crt::ByteBufDelete(m_valueByteBuf); + } + m_valueByteBuf = + Crt::ByteBufNewCopy(lhs.m_allocator, lhs.m_valueByteBuf.buffer, lhs.m_valueByteBuf.len); + m_underlyingHandle = lhs.m_underlyingHandle; + m_underlyingHandle.header_value.variable_len_val = m_valueByteBuf.buffer; + m_underlyingHandle.header_value_len = static_cast(m_valueByteBuf.len); } - m_valueByteBuf = Crt::ByteBufNewCopy(lhs.m_allocator, lhs.m_valueByteBuf.buffer, lhs.m_valueByteBuf.len); - m_underlyingHandle = lhs.m_underlyingHandle; - m_underlyingHandle.header_value.variable_len_val = m_valueByteBuf.buffer; - m_underlyingHandle.header_value_len = static_cast(m_valueByteBuf.len); return *this; } From a0282c945ec856e705b31e2b9941a9c98c7a8bc3 Mon Sep 17 00:00:00 2001 From: Bret Ambrose Date: Wed, 25 Jun 2025 10:10:49 -0700 Subject: [PATCH 56/56] clang-tidy codegen updates --- .../aws/eventstreamrpc/EventStreamClient.h | 6 +- eventstream_rpc/source/EventStreamClient.cpp | 6 +- .../tests/include/awstest/EchoTestRpcModel.h | 44 +-- .../aws/greengrass/GreengrassCoreIpcModel.h | 286 +++++++++--------- 4 files changed, 171 insertions(+), 171 deletions(-) diff --git a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h index af169160b..94adea5c7 100644 --- a/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h +++ b/eventstream_rpc/include/aws/eventstreamrpc/EventStreamClient.h @@ -183,7 +183,7 @@ namespace Aws } void SetTlsConnectionOptions(Crt::Io::TlsConnectionOptions tlsConnectionOptions) noexcept { - m_tlsConnectionOptions = tlsConnectionOptions; + m_tlsConnectionOptions = std::move(tlsConnectionOptions); } void SetClientBootstrap(Crt::Io::ClientBootstrap *clientBootstrap) noexcept { @@ -209,7 +209,7 @@ namespace Aws struct AWS_EVENTSTREAMRPC_API RpcError { explicit operator bool() const noexcept { return baseStatus == EVENT_STREAM_RPC_SUCCESS; } - Crt::String StatusToString(); + Crt::String StatusToString() const; EventStreamRpcStatusCode baseStatus; int crtError; @@ -387,7 +387,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept; + explicit operator bool() const noexcept; /** * Get operation result. diff --git a/eventstream_rpc/source/EventStreamClient.cpp b/eventstream_rpc/source/EventStreamClient.cpp index 8fdefd52b..f98d9780b 100644 --- a/eventstream_rpc/source/EventStreamClient.cpp +++ b/eventstream_rpc/source/EventStreamClient.cpp @@ -47,7 +47,7 @@ namespace Aws class OnMessageFlushCallbackContainer { public: - OnMessageFlushCallbackContainer(OnMessageFlushCallback &&flushCallback) : m_sharedState({}) + explicit OnMessageFlushCallbackContainer(OnMessageFlushCallback &&flushCallback) : m_sharedState({}) { m_sharedState.m_state = CallbackState::Incomplete; m_sharedState.m_onMessageFlushCallback = std::move(flushCallback); @@ -234,7 +234,7 @@ namespace Aws } MessageAmendment::MessageAmendment(MessageAmendment &&rhs) noexcept - : m_headers(std::move(rhs.m_headers)), m_payload(rhs.m_payload), m_allocator(rhs.m_allocator) + : m_headers(std::move(rhs.m_headers)), m_payload(std::move(rhs.m_payload)), m_allocator(rhs.m_allocator) { rhs.m_allocator = nullptr; rhs.m_payload = Crt::Optional(); @@ -321,7 +321,7 @@ namespace Aws } } - Crt::String RpcError::StatusToString() + Crt::String RpcError::StatusToString() const { switch (baseStatus) { diff --git a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h index af7a30c95..703c5fa9b 100644 --- a/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h +++ b/eventstream_rpc/tests/include/awstest/EchoTestRpcModel.h @@ -25,7 +25,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API Product : public AbstractShapeBase { public: - Product() noexcept {} + Product() noexcept = default; Product(const Product &) = default; /** * The product's name @@ -67,7 +67,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API Pair : public AbstractShapeBase { public: - Pair() noexcept {} + Pair() noexcept = default; Pair(const Pair &) = default; /** * Pair.key as a string @@ -117,7 +117,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API Customer : public AbstractShapeBase { public: - Customer() noexcept {} + Customer() noexcept = default; Customer(const Customer &) = default; /** * Opaque customer identifier @@ -168,7 +168,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API MessageData : public AbstractShapeBase { public: - MessageData() noexcept {} + MessageData() noexcept = default; MessageData(const MessageData &) = default; /** * Some string data @@ -291,7 +291,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API EchoStreamingMessage : public AbstractShapeBase { public: - EchoStreamingMessage() noexcept {} + EchoStreamingMessage() noexcept = default; EchoStreamingMessage &operator=(const EchoStreamingMessage &) noexcept; EchoStreamingMessage(const EchoStreamingMessage &objectToCopy) { *this = objectToCopy; } /** @@ -367,7 +367,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API ServiceError : public OperationError { public: - ServiceError() noexcept {} + ServiceError() noexcept = default; ServiceError(const ServiceError &) = default; /** * An error message @@ -409,7 +409,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API GetAllProductsResponse : public AbstractShapeBase { public: - GetAllProductsResponse() noexcept {} + GetAllProductsResponse() noexcept = default; GetAllProductsResponse(const GetAllProductsResponse &) = default; /** * A map from strings to products @@ -442,7 +442,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API GetAllProductsRequest : public AbstractShapeBase { public: - GetAllProductsRequest() noexcept {} + GetAllProductsRequest() noexcept = default; GetAllProductsRequest(const GetAllProductsRequest &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetAllProductsRequest &, const Aws::Crt::JsonView &) noexcept; @@ -466,7 +466,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API GetAllCustomersResponse : public AbstractShapeBase { public: - GetAllCustomersResponse() noexcept {} + GetAllCustomersResponse() noexcept = default; GetAllCustomersResponse(const GetAllCustomersResponse &) = default; /** * A list of all known customers @@ -499,7 +499,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API GetAllCustomersRequest : public AbstractShapeBase { public: - GetAllCustomersRequest() noexcept {} + GetAllCustomersRequest() noexcept = default; GetAllCustomersRequest(const GetAllCustomersRequest &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(GetAllCustomersRequest &, const Aws::Crt::JsonView &) noexcept; @@ -523,7 +523,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API EchoStreamingResponse : public AbstractShapeBase { public: - EchoStreamingResponse() noexcept {} + EchoStreamingResponse() noexcept = default; EchoStreamingResponse(const EchoStreamingResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(EchoStreamingResponse &, const Aws::Crt::JsonView &) noexcept; @@ -547,7 +547,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API EchoStreamingRequest : public AbstractShapeBase { public: - EchoStreamingRequest() noexcept {} + EchoStreamingRequest() noexcept = default; EchoStreamingRequest(const EchoStreamingRequest &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(EchoStreamingRequest &, const Aws::Crt::JsonView &) noexcept; @@ -571,7 +571,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API EchoMessageResponse : public AbstractShapeBase { public: - EchoMessageResponse() noexcept {} + EchoMessageResponse() noexcept = default; EchoMessageResponse(const EchoMessageResponse &) = default; /** * Some message data @@ -604,7 +604,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API EchoMessageRequest : public AbstractShapeBase { public: - EchoMessageRequest() noexcept {} + EchoMessageRequest() noexcept = default; EchoMessageRequest(const EchoMessageRequest &) = default; /** * Some message data @@ -637,7 +637,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API CauseServiceErrorResponse : public AbstractShapeBase { public: - CauseServiceErrorResponse() noexcept {} + CauseServiceErrorResponse() noexcept = default; CauseServiceErrorResponse(const CauseServiceErrorResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(CauseServiceErrorResponse &, const Aws::Crt::JsonView &) noexcept; @@ -661,7 +661,7 @@ namespace Awstest class AWS_ECHOTESTRPC_API CauseServiceErrorRequest : public AbstractShapeBase { public: - CauseServiceErrorRequest() noexcept {} + CauseServiceErrorRequest() noexcept = default; CauseServiceErrorRequest(const CauseServiceErrorRequest &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(CauseServiceErrorRequest &, const Aws::Crt::JsonView &) noexcept; @@ -693,7 +693,7 @@ namespace Awstest * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -743,7 +743,7 @@ namespace Awstest * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -844,7 +844,7 @@ namespace Awstest * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -946,7 +946,7 @@ namespace Awstest * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -1009,7 +1009,7 @@ namespace Awstest * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -1059,7 +1059,7 @@ namespace Awstest * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } diff --git a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h index e4dbd9e3b..0644cd38e 100644 --- a/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h +++ b/greengrass_ipc/include/aws/greengrass/GreengrassCoreIpcModel.h @@ -24,7 +24,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API UserProperty : public AbstractShapeBase { public: - UserProperty() noexcept {} + UserProperty() noexcept = default; UserProperty(const UserProperty &) = default; void SetKey(const Aws::Crt::String &key) noexcept { m_key = key; } @@ -68,7 +68,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API MessageContext : public AbstractShapeBase { public: - MessageContext() noexcept {} + MessageContext() noexcept = default; MessageContext(const MessageContext &) = default; /** * The topic where the message was published. @@ -114,7 +114,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API DeploymentStatusDetails : public AbstractShapeBase { public: - DeploymentStatusDetails() noexcept {} + DeploymentStatusDetails() noexcept = default; DeploymentStatusDetails(const DeploymentStatusDetails &) = default; /** * The detailed deployment status of the local deployment. @@ -210,7 +210,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SystemResourceLimits : public AbstractShapeBase { public: - SystemResourceLimits() noexcept {} + SystemResourceLimits() noexcept = default; SystemResourceLimits(const SystemResourceLimits &) = default; /** * (Optional) The maximum amount of RAM (in kilobytes) that this component's processes can use on the core @@ -251,7 +251,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ValidateConfigurationUpdateEvent : public AbstractShapeBase { public: - ValidateConfigurationUpdateEvent() noexcept {} + ValidateConfigurationUpdateEvent() noexcept = default; ValidateConfigurationUpdateEvent(const ValidateConfigurationUpdateEvent &) = default; /** * The object that contains the new configuration. @@ -293,7 +293,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API BinaryMessage : public AbstractShapeBase { public: - BinaryMessage() noexcept {} + BinaryMessage() noexcept = default; BinaryMessage(const BinaryMessage &) = default; /** * The binary message as a blob. @@ -332,7 +332,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API JsonMessage : public AbstractShapeBase { public: - JsonMessage() noexcept {} + JsonMessage() noexcept = default; JsonMessage(const JsonMessage &) = default; /** * The JSON message as an object. @@ -371,7 +371,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API MQTTMessage : public AbstractShapeBase { public: - MQTTMessage() noexcept {} + MQTTMessage() noexcept = default; MQTTMessage(const MQTTMessage &) = default; /** * The topic to which the message was published. @@ -491,7 +491,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ConfigurationUpdateEvent : public AbstractShapeBase { public: - ConfigurationUpdateEvent() noexcept {} + ConfigurationUpdateEvent() noexcept = default; ConfigurationUpdateEvent(const ConfigurationUpdateEvent &) = default; /** * The name of the component. @@ -530,7 +530,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API PostComponentUpdateEvent : public AbstractShapeBase { public: - PostComponentUpdateEvent() noexcept {} + PostComponentUpdateEvent() noexcept = default; PostComponentUpdateEvent(const PostComponentUpdateEvent &) = default; /** * The ID of the AWS IoT Greengrass deployment that updated the component. @@ -560,7 +560,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API PreComponentUpdateEvent : public AbstractShapeBase { public: - PreComponentUpdateEvent() noexcept {} + PreComponentUpdateEvent() noexcept = default; PreComponentUpdateEvent(const PreComponentUpdateEvent &) = default; /** * The ID of the AWS IoT Greengrass deployment that updates the component. @@ -599,7 +599,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API CertificateUpdate : public AbstractShapeBase { public: - CertificateUpdate() noexcept {} + CertificateUpdate() noexcept = default; CertificateUpdate(const CertificateUpdate &) = default; /** * The private key in pem format. @@ -673,7 +673,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API Metric : public AbstractShapeBase { public: - Metric() noexcept {} + Metric() noexcept = default; Metric(const Metric &) = default; void SetName(const Aws::Crt::String &name) noexcept { m_name = name; } @@ -709,7 +709,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API LocalDeployment : public AbstractShapeBase { public: - LocalDeployment() noexcept {} + LocalDeployment() noexcept = default; LocalDeployment(const LocalDeployment &) = default; /** * The ID of the local deployment. @@ -772,7 +772,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ComponentDetails : public AbstractShapeBase { public: - ComponentDetails() noexcept {} + ComponentDetails() noexcept = default; ComponentDetails(const ComponentDetails &) = default; /** * The name of the component. @@ -832,7 +832,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API MQTTCredential : public AbstractShapeBase { public: - MQTTCredential() noexcept {} + MQTTCredential() noexcept = default; MQTTCredential(const MQTTCredential &) = default; /** * The client ID to used to connect. @@ -892,7 +892,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API RunWithInfo : public AbstractShapeBase { public: - RunWithInfo() noexcept {} + RunWithInfo() noexcept = default; RunWithInfo(const RunWithInfo &) = default; /** * (Optional) The POSIX system user and, optionally, group to use to run this component on Linux core @@ -948,7 +948,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ClientDeviceCredential : public AbstractShapeBase { public: - ClientDeviceCredential() noexcept {} + ClientDeviceCredential() noexcept = default; ClientDeviceCredential &operator=(const ClientDeviceCredential &) noexcept; ClientDeviceCredential(const ClientDeviceCredential &objectToCopy) { *this = objectToCopy; } /** @@ -1003,7 +1003,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ValidateConfigurationUpdateEvents : public AbstractShapeBase { public: - ValidateConfigurationUpdateEvents() noexcept {} + ValidateConfigurationUpdateEvents() noexcept = default; ValidateConfigurationUpdateEvents &operator=(const ValidateConfigurationUpdateEvents &) noexcept; ValidateConfigurationUpdateEvents(const ValidateConfigurationUpdateEvents &objectToCopy) { @@ -1056,7 +1056,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SubscriptionResponseMessage : public AbstractShapeBase { public: - SubscriptionResponseMessage() noexcept {} + SubscriptionResponseMessage() noexcept = default; SubscriptionResponseMessage &operator=(const SubscriptionResponseMessage &) noexcept; SubscriptionResponseMessage(const SubscriptionResponseMessage &objectToCopy) { *this = objectToCopy; } /** @@ -1135,7 +1135,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API IoTCoreMessage : public AbstractShapeBase { public: - IoTCoreMessage() noexcept {} + IoTCoreMessage() noexcept = default; IoTCoreMessage &operator=(const IoTCoreMessage &) noexcept; IoTCoreMessage(const IoTCoreMessage &objectToCopy) { *this = objectToCopy; } /** @@ -1190,7 +1190,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ConfigurationUpdateEvents : public AbstractShapeBase { public: - ConfigurationUpdateEvents() noexcept {} + ConfigurationUpdateEvents() noexcept = default; ConfigurationUpdateEvents &operator=(const ConfigurationUpdateEvents &) noexcept; ConfigurationUpdateEvents(const ConfigurationUpdateEvents &objectToCopy) { *this = objectToCopy; } /** @@ -1239,7 +1239,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ComponentUpdatePolicyEvents : public AbstractShapeBase { public: - ComponentUpdatePolicyEvents() noexcept {} + ComponentUpdatePolicyEvents() noexcept = default; ComponentUpdatePolicyEvents &operator=(const ComponentUpdatePolicyEvents &) noexcept; ComponentUpdatePolicyEvents(const ComponentUpdatePolicyEvents &objectToCopy) { *this = objectToCopy; } /** @@ -1312,7 +1312,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API CertificateUpdateEvent : public AbstractShapeBase { public: - CertificateUpdateEvent() noexcept {} + CertificateUpdateEvent() noexcept = default; CertificateUpdateEvent &operator=(const CertificateUpdateEvent &) noexcept; CertificateUpdateEvent(const CertificateUpdateEvent &objectToCopy) { *this = objectToCopy; } /** @@ -1361,7 +1361,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API CertificateOptions : public AbstractShapeBase { public: - CertificateOptions() noexcept {} + CertificateOptions() noexcept = default; CertificateOptions(const CertificateOptions &) = default; /** * The types of certificate updates to subscribe to. @@ -1397,7 +1397,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ConfigurationValidityReport : public AbstractShapeBase { public: - ConfigurationValidityReport() noexcept {} + ConfigurationValidityReport() noexcept = default; ConfigurationValidityReport(const ConfigurationValidityReport &) = default; /** * The validity status. @@ -1445,7 +1445,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API PublishMessage : public AbstractShapeBase { public: - PublishMessage() noexcept {} + PublishMessage() noexcept = default; PublishMessage &operator=(const PublishMessage &) noexcept; PublishMessage(const PublishMessage &objectToCopy) { *this = objectToCopy; } /** @@ -1518,7 +1518,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SecretValue : public AbstractShapeBase { public: - SecretValue() noexcept {} + SecretValue() noexcept = default; SecretValue &operator=(const SecretValue &) noexcept; SecretValue(const SecretValue &objectToCopy) { *this = objectToCopy; } /** @@ -1593,7 +1593,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API CredentialDocument : public AbstractShapeBase { public: - CredentialDocument() noexcept {} + CredentialDocument() noexcept = default; CredentialDocument &operator=(const CredentialDocument &) noexcept; CredentialDocument(const CredentialDocument &objectToCopy) { *this = objectToCopy; } /** @@ -1650,7 +1650,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API InvalidArgumentsError : public OperationError { public: - InvalidArgumentsError() noexcept {} + InvalidArgumentsError() noexcept = default; InvalidArgumentsError(const InvalidArgumentsError &) = default; void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } @@ -1676,7 +1676,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ServiceError : public OperationError { public: - ServiceError() noexcept {} + ServiceError() noexcept = default; ServiceError(const ServiceError &) = default; void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } @@ -1707,7 +1707,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API UnauthorizedError : public OperationError { public: - UnauthorizedError() noexcept {} + UnauthorizedError() noexcept = default; UnauthorizedError(const UnauthorizedError &) = default; void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } @@ -1733,7 +1733,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API VerifyClientDeviceIdentityResponse : public AbstractShapeBase { public: - VerifyClientDeviceIdentityResponse() noexcept {} + VerifyClientDeviceIdentityResponse() noexcept = default; VerifyClientDeviceIdentityResponse(const VerifyClientDeviceIdentityResponse &) = default; /** * Whether the client device's identity is valid. @@ -1766,7 +1766,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API VerifyClientDeviceIdentityRequest : public AbstractShapeBase { public: - VerifyClientDeviceIdentityRequest() noexcept {} + VerifyClientDeviceIdentityRequest() noexcept = default; VerifyClientDeviceIdentityRequest(const VerifyClientDeviceIdentityRequest &) = default; /** * The client device's credentials. @@ -1796,7 +1796,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API InvalidTokenError : public OperationError { public: - InvalidTokenError() noexcept {} + InvalidTokenError() noexcept = default; InvalidTokenError(const InvalidTokenError &) = default; void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } @@ -1822,7 +1822,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ValidateAuthorizationTokenResponse : public AbstractShapeBase { public: - ValidateAuthorizationTokenResponse() noexcept {} + ValidateAuthorizationTokenResponse() noexcept = default; ValidateAuthorizationTokenResponse(const ValidateAuthorizationTokenResponse &) = default; void SetIsValid(const bool &isValid) noexcept { m_isValid = isValid; } @@ -1848,7 +1848,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ValidateAuthorizationTokenRequest : public AbstractShapeBase { public: - ValidateAuthorizationTokenRequest() noexcept {} + ValidateAuthorizationTokenRequest() noexcept = default; ValidateAuthorizationTokenRequest(const ValidateAuthorizationTokenRequest &) = default; void SetToken(const Aws::Crt::String &token) noexcept { m_token = token; } @@ -1874,7 +1874,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ConflictError : public OperationError { public: - ConflictError() noexcept {} + ConflictError() noexcept = default; ConflictError(const ConflictError &) = default; void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } @@ -1900,7 +1900,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API UpdateThingShadowResponse : public AbstractShapeBase { public: - UpdateThingShadowResponse() noexcept {} + UpdateThingShadowResponse() noexcept = default; UpdateThingShadowResponse(const UpdateThingShadowResponse &) = default; /** * The response state document as a JSON encoded blob. @@ -1930,7 +1930,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API UpdateThingShadowRequest : public AbstractShapeBase { public: - UpdateThingShadowRequest() noexcept {} + UpdateThingShadowRequest() noexcept = default; UpdateThingShadowRequest(const UpdateThingShadowRequest &) = default; /** * The name of the thing. @@ -1980,7 +1980,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ResourceNotFoundError : public OperationError { public: - ResourceNotFoundError() noexcept {} + ResourceNotFoundError() noexcept = default; ResourceNotFoundError(const ResourceNotFoundError &) = default; void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } @@ -2016,7 +2016,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API UpdateStateResponse : public AbstractShapeBase { public: - UpdateStateResponse() noexcept {} + UpdateStateResponse() noexcept = default; UpdateStateResponse(const UpdateStateResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(UpdateStateResponse &, const Aws::Crt::JsonView &) noexcept; @@ -2037,7 +2037,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API UpdateStateRequest : public AbstractShapeBase { public: - UpdateStateRequest() noexcept {} + UpdateStateRequest() noexcept = default; UpdateStateRequest(const UpdateStateRequest &) = default; /** * The state to set this component to. @@ -2067,7 +2067,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API FailedUpdateConditionCheckError : public OperationError { public: - FailedUpdateConditionCheckError() noexcept {} + FailedUpdateConditionCheckError() noexcept = default; FailedUpdateConditionCheckError(const FailedUpdateConditionCheckError &) = default; void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } @@ -2093,7 +2093,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API UpdateConfigurationResponse : public AbstractShapeBase { public: - UpdateConfigurationResponse() noexcept {} + UpdateConfigurationResponse() noexcept = default; UpdateConfigurationResponse(const UpdateConfigurationResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(UpdateConfigurationResponse &, const Aws::Crt::JsonView &) noexcept; @@ -2114,7 +2114,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API UpdateConfigurationRequest : public AbstractShapeBase { public: - UpdateConfigurationRequest() noexcept {} + UpdateConfigurationRequest() noexcept = default; UpdateConfigurationRequest(const UpdateConfigurationRequest &) = default; /** * (Optional) The key path to the container node (the object) to update. Specify a list where each entry is @@ -2168,7 +2168,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SubscribeToValidateConfigurationUpdatesResponse : public AbstractShapeBase { public: - SubscribeToValidateConfigurationUpdatesResponse() noexcept {} + SubscribeToValidateConfigurationUpdatesResponse() noexcept = default; SubscribeToValidateConfigurationUpdatesResponse(const SubscribeToValidateConfigurationUpdatesResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; @@ -2193,7 +2193,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SubscribeToValidateConfigurationUpdatesRequest : public AbstractShapeBase { public: - SubscribeToValidateConfigurationUpdatesRequest() noexcept {} + SubscribeToValidateConfigurationUpdatesRequest() noexcept = default; SubscribeToValidateConfigurationUpdatesRequest(const SubscribeToValidateConfigurationUpdatesRequest &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; @@ -2218,7 +2218,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SubscribeToTopicResponse : public AbstractShapeBase { public: - SubscribeToTopicResponse() noexcept {} + SubscribeToTopicResponse() noexcept = default; SubscribeToTopicResponse(const SubscribeToTopicResponse &) = default; /** * @deprecated No longer used @@ -2248,7 +2248,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SubscribeToTopicRequest : public AbstractShapeBase { public: - SubscribeToTopicRequest() noexcept {} + SubscribeToTopicRequest() noexcept = default; SubscribeToTopicRequest(const SubscribeToTopicRequest &) = default; /** * The topic to subscribe to. Supports MQTT-style wildcards. @@ -2287,7 +2287,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SubscribeToIoTCoreResponse : public AbstractShapeBase { public: - SubscribeToIoTCoreResponse() noexcept {} + SubscribeToIoTCoreResponse() noexcept = default; SubscribeToIoTCoreResponse(const SubscribeToIoTCoreResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(SubscribeToIoTCoreResponse &, const Aws::Crt::JsonView &) noexcept; @@ -2308,7 +2308,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SubscribeToIoTCoreRequest : public AbstractShapeBase { public: - SubscribeToIoTCoreRequest() noexcept {} + SubscribeToIoTCoreRequest() noexcept = default; SubscribeToIoTCoreRequest(const SubscribeToIoTCoreRequest &) = default; /** * The topic to which to subscribe. Supports MQTT wildcards. @@ -2347,7 +2347,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SubscribeToConfigurationUpdateResponse : public AbstractShapeBase { public: - SubscribeToConfigurationUpdateResponse() noexcept {} + SubscribeToConfigurationUpdateResponse() noexcept = default; SubscribeToConfigurationUpdateResponse(const SubscribeToConfigurationUpdateResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView( @@ -2371,7 +2371,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SubscribeToConfigurationUpdateRequest : public AbstractShapeBase { public: - SubscribeToConfigurationUpdateRequest() noexcept {} + SubscribeToConfigurationUpdateRequest() noexcept = default; SubscribeToConfigurationUpdateRequest(const SubscribeToConfigurationUpdateRequest &) = default; /** * (Optional) The name of the component. Defaults to the name of the component that makes the request. @@ -2414,7 +2414,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SubscribeToComponentUpdatesResponse : public AbstractShapeBase { public: - SubscribeToComponentUpdatesResponse() noexcept {} + SubscribeToComponentUpdatesResponse() noexcept = default; SubscribeToComponentUpdatesResponse(const SubscribeToComponentUpdatesResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(SubscribeToComponentUpdatesResponse &, const Aws::Crt::JsonView &) noexcept; @@ -2435,7 +2435,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SubscribeToComponentUpdatesRequest : public AbstractShapeBase { public: - SubscribeToComponentUpdatesRequest() noexcept {} + SubscribeToComponentUpdatesRequest() noexcept = default; SubscribeToComponentUpdatesRequest(const SubscribeToComponentUpdatesRequest &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(SubscribeToComponentUpdatesRequest &, const Aws::Crt::JsonView &) noexcept; @@ -2456,7 +2456,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SubscribeToCertificateUpdatesResponse : public AbstractShapeBase { public: - SubscribeToCertificateUpdatesResponse() noexcept {} + SubscribeToCertificateUpdatesResponse() noexcept = default; SubscribeToCertificateUpdatesResponse(const SubscribeToCertificateUpdatesResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView( @@ -2479,7 +2479,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SubscribeToCertificateUpdatesRequest : public AbstractShapeBase { public: - SubscribeToCertificateUpdatesRequest() noexcept {} + SubscribeToCertificateUpdatesRequest() noexcept = default; SubscribeToCertificateUpdatesRequest(const SubscribeToCertificateUpdatesRequest &) = default; void SetCertificateOptions(const CertificateOptions &certificateOptions) noexcept @@ -2511,7 +2511,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ComponentNotFoundError : public OperationError { public: - ComponentNotFoundError() noexcept {} + ComponentNotFoundError() noexcept = default; ComponentNotFoundError(const ComponentNotFoundError &) = default; void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } @@ -2537,7 +2537,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API StopComponentResponse : public AbstractShapeBase { public: - StopComponentResponse() noexcept {} + StopComponentResponse() noexcept = default; StopComponentResponse(const StopComponentResponse &) = default; /** * The status of the stop request. @@ -2576,7 +2576,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API StopComponentRequest : public AbstractShapeBase { public: - StopComponentRequest() noexcept {} + StopComponentRequest() noexcept = default; StopComponentRequest(const StopComponentRequest &) = default; /** * The name of the component. @@ -2606,7 +2606,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SendConfigurationValidityReportResponse : public AbstractShapeBase { public: - SendConfigurationValidityReportResponse() noexcept {} + SendConfigurationValidityReportResponse() noexcept = default; SendConfigurationValidityReportResponse(const SendConfigurationValidityReportResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView( @@ -2630,7 +2630,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API SendConfigurationValidityReportRequest : public AbstractShapeBase { public: - SendConfigurationValidityReportRequest() noexcept {} + SendConfigurationValidityReportRequest() noexcept = default; SendConfigurationValidityReportRequest(const SendConfigurationValidityReportRequest &) = default; /** * The report that tells Greengrass whether or not the configuration update is valid. @@ -2669,7 +2669,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ResumeComponentResponse : public AbstractShapeBase { public: - ResumeComponentResponse() noexcept {} + ResumeComponentResponse() noexcept = default; ResumeComponentResponse(const ResumeComponentResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ResumeComponentResponse &, const Aws::Crt::JsonView &) noexcept; @@ -2690,7 +2690,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ResumeComponentRequest : public AbstractShapeBase { public: - ResumeComponentRequest() noexcept {} + ResumeComponentRequest() noexcept = default; ResumeComponentRequest(const ResumeComponentRequest &) = default; /** * The name of the component to resume. @@ -2720,7 +2720,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API RestartComponentResponse : public AbstractShapeBase { public: - RestartComponentResponse() noexcept {} + RestartComponentResponse() noexcept = default; RestartComponentResponse(const RestartComponentResponse &) = default; /** * The status of the restart request. @@ -2759,7 +2759,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API RestartComponentRequest : public AbstractShapeBase { public: - RestartComponentRequest() noexcept {} + RestartComponentRequest() noexcept = default; RestartComponentRequest(const RestartComponentRequest &) = default; /** * The name of the component. @@ -2789,7 +2789,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API PutComponentMetricResponse : public AbstractShapeBase { public: - PutComponentMetricResponse() noexcept {} + PutComponentMetricResponse() noexcept = default; PutComponentMetricResponse(const PutComponentMetricResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(PutComponentMetricResponse &, const Aws::Crt::JsonView &) noexcept; @@ -2810,7 +2810,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API PutComponentMetricRequest : public AbstractShapeBase { public: - PutComponentMetricRequest() noexcept {} + PutComponentMetricRequest() noexcept = default; PutComponentMetricRequest(const PutComponentMetricRequest &) = default; void SetMetrics(const Aws::Crt::Vector &metrics) noexcept { m_metrics = metrics; } @@ -2836,7 +2836,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API PublishToTopicResponse : public AbstractShapeBase { public: - PublishToTopicResponse() noexcept {} + PublishToTopicResponse() noexcept = default; PublishToTopicResponse(const PublishToTopicResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(PublishToTopicResponse &, const Aws::Crt::JsonView &) noexcept; @@ -2857,7 +2857,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API PublishToTopicRequest : public AbstractShapeBase { public: - PublishToTopicRequest() noexcept {} + PublishToTopicRequest() noexcept = default; PublishToTopicRequest(const PublishToTopicRequest &) = default; /** * The topic to publish the message. @@ -2896,7 +2896,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API PublishToIoTCoreResponse : public AbstractShapeBase { public: - PublishToIoTCoreResponse() noexcept {} + PublishToIoTCoreResponse() noexcept = default; PublishToIoTCoreResponse(const PublishToIoTCoreResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(PublishToIoTCoreResponse &, const Aws::Crt::JsonView &) noexcept; @@ -2917,7 +2917,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API PublishToIoTCoreRequest : public AbstractShapeBase { public: - PublishToIoTCoreRequest() noexcept {} + PublishToIoTCoreRequest() noexcept = default; PublishToIoTCoreRequest(const PublishToIoTCoreRequest &) = default; /** * The topic to which to publish the message. @@ -3046,7 +3046,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API PauseComponentResponse : public AbstractShapeBase { public: - PauseComponentResponse() noexcept {} + PauseComponentResponse() noexcept = default; PauseComponentResponse(const PauseComponentResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(PauseComponentResponse &, const Aws::Crt::JsonView &) noexcept; @@ -3067,7 +3067,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API PauseComponentRequest : public AbstractShapeBase { public: - PauseComponentRequest() noexcept {} + PauseComponentRequest() noexcept = default; PauseComponentRequest(const PauseComponentRequest &) = default; /** * The name of the component to pause, which must be a generic component. @@ -3097,7 +3097,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ListNamedShadowsForThingResponse : public AbstractShapeBase { public: - ListNamedShadowsForThingResponse() noexcept {} + ListNamedShadowsForThingResponse() noexcept = default; ListNamedShadowsForThingResponse(const ListNamedShadowsForThingResponse &) = default; /** * The list of shadow names. @@ -3147,7 +3147,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ListNamedShadowsForThingRequest : public AbstractShapeBase { public: - ListNamedShadowsForThingRequest() noexcept {} + ListNamedShadowsForThingRequest() noexcept = default; ListNamedShadowsForThingRequest(const ListNamedShadowsForThingRequest &) = default; /** * The name of the thing. @@ -3199,7 +3199,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ListLocalDeploymentsResponse : public AbstractShapeBase { public: - ListLocalDeploymentsResponse() noexcept {} + ListLocalDeploymentsResponse() noexcept = default; ListLocalDeploymentsResponse(const ListLocalDeploymentsResponse &) = default; /** * The list of local deployments. @@ -3235,7 +3235,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ListLocalDeploymentsRequest : public AbstractShapeBase { public: - ListLocalDeploymentsRequest() noexcept {} + ListLocalDeploymentsRequest() noexcept = default; ListLocalDeploymentsRequest(const ListLocalDeploymentsRequest &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ListLocalDeploymentsRequest &, const Aws::Crt::JsonView &) noexcept; @@ -3256,7 +3256,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ListComponentsResponse : public AbstractShapeBase { public: - ListComponentsResponse() noexcept {} + ListComponentsResponse() noexcept = default; ListComponentsResponse(const ListComponentsResponse &) = default; /** * The list of components. @@ -3292,7 +3292,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API ListComponentsRequest : public AbstractShapeBase { public: - ListComponentsRequest() noexcept {} + ListComponentsRequest() noexcept = default; ListComponentsRequest(const ListComponentsRequest &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(ListComponentsRequest &, const Aws::Crt::JsonView &) noexcept; @@ -3313,7 +3313,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API GetThingShadowResponse : public AbstractShapeBase { public: - GetThingShadowResponse() noexcept {} + GetThingShadowResponse() noexcept = default; GetThingShadowResponse(const GetThingShadowResponse &) = default; /** * The response state document as a JSON encoded blob. @@ -3343,7 +3343,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API GetThingShadowRequest : public AbstractShapeBase { public: - GetThingShadowRequest() noexcept {} + GetThingShadowRequest() noexcept = default; GetThingShadowRequest(const GetThingShadowRequest &) = default; /** * The name of the thing. @@ -3384,7 +3384,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API GetSecretValueResponse : public AbstractShapeBase { public: - GetSecretValueResponse() noexcept {} + GetSecretValueResponse() noexcept = default; GetSecretValueResponse(const GetSecretValueResponse &) = default; /** * The ID of the secret. @@ -3447,7 +3447,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API GetSecretValueRequest : public AbstractShapeBase { public: - GetSecretValueRequest() noexcept {} + GetSecretValueRequest() noexcept = default; GetSecretValueRequest(const GetSecretValueRequest &) = default; /** * The name of the secret to get. You can specify either the Amazon Resource Name (ARN) or the friendly name @@ -3510,7 +3510,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API GetLocalDeploymentStatusResponse : public AbstractShapeBase { public: - GetLocalDeploymentStatusResponse() noexcept {} + GetLocalDeploymentStatusResponse() noexcept = default; GetLocalDeploymentStatusResponse(const GetLocalDeploymentStatusResponse &) = default; /** * The local deployment. @@ -3540,7 +3540,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API GetLocalDeploymentStatusRequest : public AbstractShapeBase { public: - GetLocalDeploymentStatusRequest() noexcept {} + GetLocalDeploymentStatusRequest() noexcept = default; GetLocalDeploymentStatusRequest(const GetLocalDeploymentStatusRequest &) = default; /** * The ID of the local deployment to get. @@ -3570,7 +3570,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API GetConfigurationResponse : public AbstractShapeBase { public: - GetConfigurationResponse() noexcept {} + GetConfigurationResponse() noexcept = default; GetConfigurationResponse(const GetConfigurationResponse &) = default; /** * The name of the component. @@ -3609,7 +3609,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API GetConfigurationRequest : public AbstractShapeBase { public: - GetConfigurationRequest() noexcept {} + GetConfigurationRequest() noexcept = default; GetConfigurationRequest(const GetConfigurationRequest &) = default; /** * (Optional) The name of the component. Defaults to the name of the component that makes the request. @@ -3650,7 +3650,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API GetComponentDetailsResponse : public AbstractShapeBase { public: - GetComponentDetailsResponse() noexcept {} + GetComponentDetailsResponse() noexcept = default; GetComponentDetailsResponse(const GetComponentDetailsResponse &) = default; /** * The component's details. @@ -3683,7 +3683,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API GetComponentDetailsRequest : public AbstractShapeBase { public: - GetComponentDetailsRequest() noexcept {} + GetComponentDetailsRequest() noexcept = default; GetComponentDetailsRequest(const GetComponentDetailsRequest &) = default; /** * The name of the component to get. @@ -3713,7 +3713,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API InvalidCredentialError : public OperationError { public: - InvalidCredentialError() noexcept {} + InvalidCredentialError() noexcept = default; InvalidCredentialError(const InvalidCredentialError &) = default; void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } @@ -3739,7 +3739,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API GetClientDeviceAuthTokenResponse : public AbstractShapeBase { public: - GetClientDeviceAuthTokenResponse() noexcept {} + GetClientDeviceAuthTokenResponse() noexcept = default; GetClientDeviceAuthTokenResponse(const GetClientDeviceAuthTokenResponse &) = default; /** * The session token for the client device. You can use this session token in subsequent requests to @@ -3777,7 +3777,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API GetClientDeviceAuthTokenRequest : public AbstractShapeBase { public: - GetClientDeviceAuthTokenRequest() noexcept {} + GetClientDeviceAuthTokenRequest() noexcept = default; GetClientDeviceAuthTokenRequest(const GetClientDeviceAuthTokenRequest &) = default; /** * The client device's credentials. @@ -3807,7 +3807,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API DeleteThingShadowResponse : public AbstractShapeBase { public: - DeleteThingShadowResponse() noexcept {} + DeleteThingShadowResponse() noexcept = default; DeleteThingShadowResponse(const DeleteThingShadowResponse &) = default; /** * An empty response state document. @@ -3837,7 +3837,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API DeleteThingShadowRequest : public AbstractShapeBase { public: - DeleteThingShadowRequest() noexcept {} + DeleteThingShadowRequest() noexcept = default; DeleteThingShadowRequest(const DeleteThingShadowRequest &) = default; /** * The name of the thing. @@ -3878,7 +3878,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API DeferComponentUpdateResponse : public AbstractShapeBase { public: - DeferComponentUpdateResponse() noexcept {} + DeferComponentUpdateResponse() noexcept = default; DeferComponentUpdateResponse(const DeferComponentUpdateResponse &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(DeferComponentUpdateResponse &, const Aws::Crt::JsonView &) noexcept; @@ -3899,7 +3899,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API DeferComponentUpdateRequest : public AbstractShapeBase { public: - DeferComponentUpdateRequest() noexcept {} + DeferComponentUpdateRequest() noexcept = default; DeferComponentUpdateRequest(const DeferComponentUpdateRequest &) = default; /** * The ID of the AWS IoT Greengrass deployment to defer. @@ -3951,7 +3951,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API InvalidArtifactsDirectoryPathError : public OperationError { public: - InvalidArtifactsDirectoryPathError() noexcept {} + InvalidArtifactsDirectoryPathError() noexcept = default; InvalidArtifactsDirectoryPathError(const InvalidArtifactsDirectoryPathError &) = default; void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } @@ -3977,7 +3977,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API InvalidRecipeDirectoryPathError : public OperationError { public: - InvalidRecipeDirectoryPathError() noexcept {} + InvalidRecipeDirectoryPathError() noexcept = default; InvalidRecipeDirectoryPathError(const InvalidRecipeDirectoryPathError &) = default; void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } @@ -4003,7 +4003,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API CreateLocalDeploymentResponse : public AbstractShapeBase { public: - CreateLocalDeploymentResponse() noexcept {} + CreateLocalDeploymentResponse() noexcept = default; CreateLocalDeploymentResponse(const CreateLocalDeploymentResponse &) = default; /** * The ID of the local deployment that the request created. @@ -4033,7 +4033,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API CreateLocalDeploymentRequest : public AbstractShapeBase { public: - CreateLocalDeploymentRequest() noexcept {} + CreateLocalDeploymentRequest() noexcept = default; CreateLocalDeploymentRequest(const CreateLocalDeploymentRequest &) = default; /** * The thing group name the deployment is targeting. If the group name is not specified, "LOCAL_DEPLOYMENT" @@ -4171,7 +4171,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API CreateDebugPasswordResponse : public AbstractShapeBase { public: - CreateDebugPasswordResponse() noexcept {} + CreateDebugPasswordResponse() noexcept = default; CreateDebugPasswordResponse(const CreateDebugPasswordResponse &) = default; void SetPassword(const Aws::Crt::String &password) noexcept { m_password = password; } @@ -4235,7 +4235,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API CreateDebugPasswordRequest : public AbstractShapeBase { public: - CreateDebugPasswordRequest() noexcept {} + CreateDebugPasswordRequest() noexcept = default; CreateDebugPasswordRequest(const CreateDebugPasswordRequest &) = default; void SerializeToJsonObject(Aws::Crt::JsonObject &payloadObject) const noexcept override; static void s_loadFromJsonView(CreateDebugPasswordRequest &, const Aws::Crt::JsonView &) noexcept; @@ -4256,7 +4256,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API CancelLocalDeploymentResponse : public AbstractShapeBase { public: - CancelLocalDeploymentResponse() noexcept {} + CancelLocalDeploymentResponse() noexcept = default; CancelLocalDeploymentResponse(const CancelLocalDeploymentResponse &) = default; void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } @@ -4282,7 +4282,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API CancelLocalDeploymentRequest : public AbstractShapeBase { public: - CancelLocalDeploymentRequest() noexcept {} + CancelLocalDeploymentRequest() noexcept = default; CancelLocalDeploymentRequest(const CancelLocalDeploymentRequest &) = default; /** * (Optional) The ID of the local deployment to cancel. @@ -4312,7 +4312,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API InvalidClientDeviceAuthTokenError : public OperationError { public: - InvalidClientDeviceAuthTokenError() noexcept {} + InvalidClientDeviceAuthTokenError() noexcept = default; InvalidClientDeviceAuthTokenError(const InvalidClientDeviceAuthTokenError &) = default; void SetMessage(const Aws::Crt::String &message) noexcept { m_message = message; } @@ -4338,7 +4338,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API AuthorizeClientDeviceActionResponse : public AbstractShapeBase { public: - AuthorizeClientDeviceActionResponse() noexcept {} + AuthorizeClientDeviceActionResponse() noexcept = default; AuthorizeClientDeviceActionResponse(const AuthorizeClientDeviceActionResponse &) = default; /** * Whether the client device is authorized to perform the operation on the resource. @@ -4368,7 +4368,7 @@ namespace Aws class AWS_GREENGRASSCOREIPC_API AuthorizeClientDeviceActionRequest : public AbstractShapeBase { public: - AuthorizeClientDeviceActionRequest() noexcept {} + AuthorizeClientDeviceActionRequest() noexcept = default; AuthorizeClientDeviceActionRequest(const AuthorizeClientDeviceActionRequest &) = default; /** * The session token for the client device from GetClientDeviceAuthToken. @@ -4492,7 +4492,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -4543,7 +4543,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -4593,7 +4593,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -4705,7 +4705,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -4756,7 +4756,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -4806,7 +4806,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -4858,7 +4858,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -4962,7 +4962,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5013,7 +5013,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5132,7 +5132,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5183,7 +5183,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5236,7 +5236,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5286,7 +5286,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5408,7 +5408,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5462,7 +5462,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5515,7 +5515,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5565,7 +5565,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5615,7 +5615,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5665,7 +5665,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5718,7 +5718,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5768,7 +5768,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5818,7 +5818,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5871,7 +5871,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5921,7 +5921,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -5974,7 +5974,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -6024,7 +6024,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -6074,7 +6074,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -6126,7 +6126,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -6179,7 +6179,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -6291,7 +6291,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -6344,7 +6344,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -6394,7 +6394,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -6444,7 +6444,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); } @@ -6496,7 +6496,7 @@ namespace Aws * @return true if the response is associated with an expected response; * false if the response is associated with an error. */ - operator bool() const noexcept { return m_taggedResult == true; } + operator bool() const noexcept { return static_cast(m_taggedResult) == true; } OperationError *GetOperationError() const noexcept { return m_taggedResult.GetOperationError(); } RpcError GetRpcError() const noexcept { return m_taggedResult.GetRpcError(); } ResultType GetResultType() const noexcept { return m_taggedResult.GetResultType(); }